@agent-native/core 0.31.0 → 0.31.2

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 (197) hide show
  1. package/dist/a2a/client.js +1 -1
  2. package/dist/a2a/client.js.map +1 -1
  3. package/dist/a2a/task-store.d.ts.map +1 -1
  4. package/dist/a2a/task-store.js +5 -1
  5. package/dist/a2a/task-store.js.map +1 -1
  6. package/dist/action.js +22 -4
  7. package/dist/action.js.map +1 -1
  8. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  9. package/dist/agent/engine/ai-sdk-engine.js +5 -0
  10. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  11. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  12. package/dist/agent/engine/builder-engine.js +4 -0
  13. package/dist/agent/engine/builder-engine.js.map +1 -1
  14. package/dist/agent/production-agent.d.ts.map +1 -1
  15. package/dist/agent/production-agent.js +24 -1
  16. package/dist/agent/production-agent.js.map +1 -1
  17. package/dist/agent/run-manager.d.ts.map +1 -1
  18. package/dist/agent/run-manager.js +7 -2
  19. package/dist/agent/run-manager.js.map +1 -1
  20. package/dist/agent/run-store.d.ts.map +1 -1
  21. package/dist/agent/run-store.js +5 -1
  22. package/dist/agent/run-store.js.map +1 -1
  23. package/dist/agent/tool-search.js.map +1 -1
  24. package/dist/application-state/store.d.ts.map +1 -1
  25. package/dist/application-state/store.js +18 -7
  26. package/dist/application-state/store.js.map +1 -1
  27. package/dist/browser-sessions/store.d.ts.map +1 -1
  28. package/dist/browser-sessions/store.js +6 -1
  29. package/dist/browser-sessions/store.js.map +1 -1
  30. package/dist/chat-threads/store.d.ts.map +1 -1
  31. package/dist/chat-threads/store.js +6 -2
  32. package/dist/chat-threads/store.js.map +1 -1
  33. package/dist/checkpoints/store.d.ts.map +1 -1
  34. package/dist/checkpoints/store.js +5 -1
  35. package/dist/checkpoints/store.js.map +1 -1
  36. package/dist/client/AgentPanel.js +18 -18
  37. package/dist/client/AgentPanel.js.map +1 -1
  38. package/dist/client/agent-chat.d.ts +0 -3
  39. package/dist/client/agent-chat.d.ts.map +1 -1
  40. package/dist/client/agent-chat.js +0 -3
  41. package/dist/client/agent-chat.js.map +1 -1
  42. package/dist/client/components/CodeRequiredDialog.js +0 -7
  43. package/dist/client/components/CodeRequiredDialog.js.map +1 -1
  44. package/dist/client/composer/use-file-search.d.ts.map +1 -1
  45. package/dist/client/composer/use-file-search.js +14 -3
  46. package/dist/client/composer/use-file-search.js.map +1 -1
  47. package/dist/client/db-admin/EditableCell.js +1 -1
  48. package/dist/client/db-admin/EditableCell.js.map +1 -1
  49. package/dist/client/dev-overlay/DevOverlay.d.ts +0 -2
  50. package/dist/client/dev-overlay/DevOverlay.d.ts.map +1 -1
  51. package/dist/client/dev-overlay/DevOverlay.js +1 -1
  52. package/dist/client/dev-overlay/DevOverlay.js.map +1 -1
  53. package/dist/client/mcp-app-host.d.ts.map +1 -1
  54. package/dist/client/mcp-app-host.js +19 -2
  55. package/dist/client/mcp-app-host.js.map +1 -1
  56. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  57. package/dist/client/resources/ResourcesPanel.js +0 -1
  58. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  59. package/dist/client/settings/SettingsPanel.js +2 -2
  60. package/dist/client/settings/SettingsPanel.js.map +1 -1
  61. package/dist/client/sse-event-processor.d.ts.map +1 -1
  62. package/dist/client/sse-event-processor.js +13 -3
  63. package/dist/client/sse-event-processor.js.map +1 -1
  64. package/dist/client/use-db-sync.d.ts.map +1 -1
  65. package/dist/client/use-db-sync.js +16 -0
  66. package/dist/client/use-db-sync.js.map +1 -1
  67. package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
  68. package/dist/client/use-run-stuck-detection.js +7 -1
  69. package/dist/client/use-run-stuck-detection.js.map +1 -1
  70. package/dist/collab/agent-presence.d.ts +0 -3
  71. package/dist/collab/agent-presence.d.ts.map +1 -1
  72. package/dist/collab/agent-presence.js +2 -4
  73. package/dist/collab/agent-presence.js.map +1 -1
  74. package/dist/collab/awareness.d.ts.map +1 -1
  75. package/dist/collab/awareness.js +3 -1
  76. package/dist/collab/awareness.js.map +1 -1
  77. package/dist/collab/storage.d.ts.map +1 -1
  78. package/dist/collab/storage.js +5 -1
  79. package/dist/collab/storage.js.map +1 -1
  80. package/dist/collab/ydoc-manager.d.ts.map +1 -1
  81. package/dist/collab/ydoc-manager.js +35 -8
  82. package/dist/collab/ydoc-manager.js.map +1 -1
  83. package/dist/extensions/content-patch.js +1 -1
  84. package/dist/extensions/content-patch.js.map +1 -1
  85. package/dist/extensions/routes.js +12 -12
  86. package/dist/extensions/routes.js.map +1 -1
  87. package/dist/extensions/slots/store.d.ts.map +1 -1
  88. package/dist/extensions/slots/store.js +5 -1
  89. package/dist/extensions/slots/store.js.map +1 -1
  90. package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
  91. package/dist/integrations/a2a-continuations-store.js +5 -1
  92. package/dist/integrations/a2a-continuations-store.js.map +1 -1
  93. package/dist/integrations/adapters/email.d.ts.map +1 -1
  94. package/dist/integrations/adapters/email.js +5 -2
  95. package/dist/integrations/adapters/email.js.map +1 -1
  96. package/dist/integrations/google-docs-poller.d.ts.map +1 -1
  97. package/dist/integrations/google-docs-poller.js +2 -4
  98. package/dist/integrations/google-docs-poller.js.map +1 -1
  99. package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
  100. package/dist/integrations/pending-tasks-retry-job.js +6 -2
  101. package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
  102. package/dist/integrations/pending-tasks-store.d.ts.map +1 -1
  103. package/dist/integrations/pending-tasks-store.js +5 -1
  104. package/dist/integrations/pending-tasks-store.js.map +1 -1
  105. package/dist/integrations/plugin.d.ts.map +1 -1
  106. package/dist/integrations/plugin.js +14 -3
  107. package/dist/integrations/plugin.js.map +1 -1
  108. package/dist/integrations/remote-commands-store.d.ts.map +1 -1
  109. package/dist/integrations/remote-commands-store.js +5 -1
  110. package/dist/integrations/remote-commands-store.js.map +1 -1
  111. package/dist/integrations/remote-devices-store.d.ts.map +1 -1
  112. package/dist/integrations/remote-devices-store.js +5 -1
  113. package/dist/integrations/remote-devices-store.js.map +1 -1
  114. package/dist/integrations/remote-push-store.d.ts.map +1 -1
  115. package/dist/integrations/remote-push-store.js +5 -1
  116. package/dist/integrations/remote-push-store.js.map +1 -1
  117. package/dist/integrations/remote-retry-job.js +1 -1
  118. package/dist/integrations/remote-retry-job.js.map +1 -1
  119. package/dist/integrations/remote-run-events-store.d.ts.map +1 -1
  120. package/dist/integrations/remote-run-events-store.js +5 -1
  121. package/dist/integrations/remote-run-events-store.js.map +1 -1
  122. package/dist/integrations/thread-mapping-store.d.ts.map +1 -1
  123. package/dist/integrations/thread-mapping-store.js +5 -1
  124. package/dist/integrations/thread-mapping-store.js.map +1 -1
  125. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  126. package/dist/integrations/webhook-handler.js.map +1 -1
  127. package/dist/jobs/scheduler.d.ts.map +1 -1
  128. package/dist/jobs/scheduler.js +31 -15
  129. package/dist/jobs/scheduler.js.map +1 -1
  130. package/dist/jobs/tools.d.ts.map +1 -1
  131. package/dist/jobs/tools.js +4 -1
  132. package/dist/jobs/tools.js.map +1 -1
  133. package/dist/mcp/build-server.d.ts.map +1 -1
  134. package/dist/mcp/build-server.js +4 -1
  135. package/dist/mcp/build-server.js.map +1 -1
  136. package/dist/mcp/connect-store.d.ts +3 -4
  137. package/dist/mcp/connect-store.d.ts.map +1 -1
  138. package/dist/mcp/connect-store.js +4 -4
  139. package/dist/mcp/connect-store.js.map +1 -1
  140. package/dist/mcp-client/routes.js +6 -1
  141. package/dist/mcp-client/routes.js.map +1 -1
  142. package/dist/oauth-tokens/store.d.ts.map +1 -1
  143. package/dist/oauth-tokens/store.js +5 -1
  144. package/dist/oauth-tokens/store.js.map +1 -1
  145. package/dist/org/accept-pending.js +1 -1
  146. package/dist/org/accept-pending.js.map +1 -1
  147. package/dist/progress/store.d.ts.map +1 -1
  148. package/dist/progress/store.js +11 -1
  149. package/dist/progress/store.js.map +1 -1
  150. package/dist/resources/handlers.d.ts.map +1 -1
  151. package/dist/resources/handlers.js +0 -2
  152. package/dist/resources/handlers.js.map +1 -1
  153. package/dist/resources/store.d.ts.map +1 -1
  154. package/dist/resources/store.js +23 -13
  155. package/dist/resources/store.js.map +1 -1
  156. package/dist/scripts/db/query.d.ts.map +1 -1
  157. package/dist/scripts/db/query.js +1 -2
  158. package/dist/scripts/db/query.js.map +1 -1
  159. package/dist/server/action-discovery.d.ts.map +1 -1
  160. package/dist/server/action-discovery.js +10 -3
  161. package/dist/server/action-discovery.js.map +1 -1
  162. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  163. package/dist/server/agent-chat-plugin.js +3 -0
  164. package/dist/server/agent-chat-plugin.js.map +1 -1
  165. package/dist/server/auth.d.ts.map +1 -1
  166. package/dist/server/auth.js +13 -9
  167. package/dist/server/auth.js.map +1 -1
  168. package/dist/server/identity-sso-store.d.ts.map +1 -1
  169. package/dist/server/identity-sso-store.js +14 -3
  170. package/dist/server/identity-sso-store.js.map +1 -1
  171. package/dist/server/poll.d.ts.map +1 -1
  172. package/dist/server/poll.js +18 -0
  173. package/dist/server/poll.js.map +1 -1
  174. package/dist/server/schema-prompt.js +1 -1
  175. package/dist/server/schema-prompt.js.map +1 -1
  176. package/dist/server/security-headers.d.ts +5 -4
  177. package/dist/server/security-headers.d.ts.map +1 -1
  178. package/dist/server/security-headers.js +5 -4
  179. package/dist/server/security-headers.js.map +1 -1
  180. package/dist/settings/store.d.ts.map +1 -1
  181. package/dist/settings/store.js +5 -1
  182. package/dist/settings/store.js.map +1 -1
  183. package/dist/sharing/actions/set-resource-visibility.d.ts.map +1 -1
  184. package/dist/sharing/actions/set-resource-visibility.js +8 -1
  185. package/dist/sharing/actions/set-resource-visibility.js.map +1 -1
  186. package/dist/triggers/actions.d.ts.map +1 -1
  187. package/dist/triggers/actions.js +1 -2
  188. package/dist/triggers/actions.js.map +1 -1
  189. package/dist/triggers/dispatcher.d.ts.map +1 -1
  190. package/dist/triggers/dispatcher.js +36 -8
  191. package/dist/triggers/dispatcher.js.map +1 -1
  192. package/dist/usage/store.d.ts.map +1 -1
  193. package/dist/usage/store.js +5 -1
  194. package/dist/usage/store.js.map +1 -1
  195. package/dist/vite/client.js +5 -5
  196. package/dist/vite/client.js.map +1 -1
  197. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"email.js","sourceRoot":"","sources":["../../../src/integrations/adapters/email.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,WAAW,IAAI,aAAa,EAAE,MAAM,IAAI,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAS9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAE/B,wCAAwC;AACxC,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAEpC,0DAA0D;AAC1D,MAAM,cAAc,GAAG,EAAE,CAAC;AAC1B,uCAAuC;AACvC,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE5C;;;;;GAKG;AACH,IAAI,uBAAuB,GAAG,KAAK,CAAC;AACpC,IAAI,yBAAyB,GAAG,KAAK,CAAC;AAEtC;;;;;;;GAOG;AACH,SAAS,6BAA6B;IACpC,IAAI,OAAO,CAAC,GAAG,CAAC,sCAAsC,KAAK,GAAG;QAAE,OAAO,KAAK,CAAC;IAC7E,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC;AAC/C,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO;QACL,QAAQ,EAAE,OAAO;QACjB,KAAK,EAAE,OAAO;QAEd,kBAAkB;YAChB,OAAO;gBACL;oBACE,GAAG,EAAE,qBAAqB;oBAC1B,KAAK,EAAE,qBAAqB;oBAC5B,QAAQ,EAAE,IAAI;oBACd,QAAQ,EACN,wIAAwI;iBAC3I;gBACD;oBACE,GAAG,EAAE,gBAAgB;oBACrB,KAAK,EAAE,gBAAgB;oBACvB,QAAQ,EAAE,KAAK;oBACf,QAAQ,EACN,uHAAuH;iBAC1H;gBACD;oBACE,GAAG,EAAE,kBAAkB;oBACvB,KAAK,EAAE,kBAAkB;oBACzB,QAAQ,EAAE,KAAK;oBACf,QAAQ,EACN,qGAAqG;iBACxG;gBACD;oBACE,GAAG,EAAE,8BAA8B;oBACnC,KAAK,EAAE,wBAAwB;oBAC/B,QAAQ,EAAE,KAAK;oBACf,QAAQ,EACN,uKAAuK;iBAC1K;aACF,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,kBAAkB,CACtB,MAAe;YAEf,iDAAiD;YACjD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC5B,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,KAAc;YAChC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC;YACxD,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAC;YAEpC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC1B,OAAO,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAC5C,CAAC;YAED,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;gBAC5B,OAAO,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAC9C,CAAC;YAED,kCAAkC;YAClC,OAAO,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;YACxE,OAAO,KAAK,CAAC;QACf,CAAC;QAED,KAAK,CAAC,oBAAoB,CACxB,KAAc;YAEd,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAC;YACpC,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,WAAW,EAAE,CAAC;YACpE,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,OAAO,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;gBAC3D,OAAO,IAAI,CAAC;YACd,CAAC;YAED,IAAI,MAAM,GAAuB,IAAI,CAAC;YAEtC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC1B,MAAM,GAAG,MAAM,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAC3C,CAAC;iBAAM,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;gBACnC,MAAM,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC;YAC7C,CAAC;YAED,IAAI,CAAC,MAAM;gBAAE,OAAO,IAAI,CAAC;YAEzB,2EAA2E;YAC3E,yEAAyE;YACzE,gEAAgE;YAChE,yEAAyE;YACzE,0DAA0D;YAC1D,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;YACpD,IAAI,MAAM,aAAa,CAAC,WAAW,CAAC,EAAE,CAAC;gBACrC,OAAO,CAAC,IAAI,CACV,gCAAgC,WAAW,MAAM,cAAc,MAAM,CACtE,CAAC;gBACF,OAAO,IAAI,CAAC;YACd,CAAC;YAED,wBAAwB;YACxB,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;YACnD,IAAI,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;gBACvC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,cAA0B,CAAC;gBAC7D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACvB,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC/C,IAAI,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;wBACrD,OAAO,CAAC,IAAI,CACV,+BAA+B,WAAW,gCAAgC,CAC3E,CAAC;wBACF,OAAO,IAAI,CAAC;oBACd,CAAC;gBACH,CAAC;YACH,CAAC;YAED,qDAAqD;YACrD,MAAM,WAAW,GAAG,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YAC1D,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YAClE,MAAM,IAAI,GACR,CAAC,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC;gBACnC,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;YAErC,yFAAyF;YACzF,+EAA+E;YAC/E,8EAA8E;YAC9E,yEAAyE;YACzE,gFAAgF;YAChF,6EAA6E;YAC7E,6CAA6C;YAC7C,MAAM,YAAY,GAAG,qBAAqB,CACxC,eAAe,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,UAAU,CAAC,EACpD,WAAW,CACZ,CAAC;YAEF,kBAAkB;YAClB,IAAI,QAAQ,GAAG,MAAM,CAAC,IAAI,IAAI,qBAAqB,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YAEvE,qBAAqB;YACrB,IAAI,QAAQ,CAAC,MAAM,GAAG,qBAAqB,EAAE,CAAC;gBAC5C,QAAQ;oBACN,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,uBAAuB,CAAC;YACvE,CAAC;YAED,kCAAkC;YAClC,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,eAAe,GAAG,WAAW;qBAChC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,YAAY,CAAC;qBACjC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACd,QAAQ;oBACN,0BAA0B,WAAW,QAAQ,eAAe,IAAI,QAAQ,KAAK;wBAC7E,YAAY,MAAM,CAAC,OAAO,MAAM;wBAChC,QAAQ,CAAC;YACb,CAAC;YAED,OAAO;gBACL,QAAQ,EAAE,OAAO;gBACjB,gBAAgB,EAAE,YAAY;gBAC9B,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI;gBAC5B,QAAQ,EAAE,WAAW;gBACrB,6DAA6D;gBAC7D,gEAAgE;gBAChE,+DAA+D;gBAC/D,oEAAoE;gBACpE,cAAc,EAAE,MAAM,CAAC,cAAc;gBACrC,eAAe,EAAE;oBACf,SAAS,EAAE,MAAM,CAAC,SAAS;oBAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;oBACvB,IAAI,EAAE,WAAW;oBACjB,EAAE,EAAE,MAAM,CAAC,EAAE;oBACb,EAAE,EAAE,MAAM,CAAC,EAAE;oBACb,SAAS,EAAE,MAAM,CAAC,SAAS;oBAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;oBAC7B,IAAI;oBACJ,cAAc,EAAE,MAAM,CAAC,cAAc;iBACtC;gBACD,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;aACtE,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,YAAY,CAChB,OAAwB,EACxB,OAAwB;YAExB,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;YACrD,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;gBAC5D,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;YACnD,MAAM,WAAW,GACd,MAAM,EAAE,UAAU,EAAE,WAAsB,IAAI,gBAAgB,CAAC;YAElE,sEAAsE;YACtE,mEAAmE;YACnE,4DAA4D;YAC5D,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU;gBACxC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU;gBACxB,CAAC,CAAC,GAAG,WAAW,KAAK,YAAY,GAAG,CAAC;YAEvC,MAAM,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,OAAiB,CAAC;YAC1D,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,OAAO,EAAE,CAAC;YAE1E,IAAI,CAAC;gBACH,MAAM,SAAS,CAAC;oBACd,EAAE,EAAE,OAAO,CAAC,QAAS;oBACrB,IAAI,EAAE,WAAW;oBACjB,OAAO,EAAE,SAAS;oBAClB,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,IAAI,EAAE,qBAAqB,CAAC,OAAO,CAAC,IAAI,CAAC;oBACzC,SAAS,EAAE,OAAO,CAAC,eAAe,CAAC,SAAmB;oBACtD,UAAU,EAAE,qBAAqB,CAAC,OAAO,CAAC,eAAe,CAAC;oBAC1D,EAAE,EAAE,OAAO,CAAC,eAAe,CAAC,IAAI;wBAC9B,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC;wBAC1B,CAAC,CAAC,SAAS;iBACd,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;QAED,KAAK,CAAC,mBAAmB,CACvB,OAAwB,EACxB,MAAsB;YAEtB,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;YACrD,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;gBAC5D,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;YACnD,MAAM,WAAW,GACd,MAAM,EAAE,UAAU,EAAE,WAAsB,IAAI,gBAAgB,CAAC;YAElE,IAAI,CAAC;gBACH,MAAM,SAAS,CAAC;oBACd,EAAE,EAAE,MAAM,CAAC,WAAW;oBACtB,IAAI,EAAE,GAAG,WAAW,KAAK,YAAY,GAAG;oBACxC,OAAO,EAAE,MAAM,CAAC,KAAK,IAAI,6BAA6B;oBACtD,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,IAAI,EAAE,qBAAqB,CAAC,OAAO,CAAC,IAAI,CAAC;oBACzC,GAAG,CAAC,MAAM,CAAC,SAAS;wBAClB,CAAC,CAAC;4BACE,SAAS,EAAE,MAAM,CAAC,SAAS;4BAC3B,UAAU,EAAE,MAAM,CAAC,SAAS;yBAC7B;wBACH,CAAC,CAAC,EAAE,CAAC;iBACR,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,GAAG,CAAC,CAAC;gBAChE,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC;QAED,mBAAmB,CAAC,IAAY;YAC9B,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,IAAI,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;YAC3C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC;QAC7C,CAAC;QAED,KAAK,CAAC,SAAS,CAAC,QAAiB;YAC/B,MAAM,eAAe,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;YAC1D,MAAM,gBAAgB,GAAG,iBAAiB,EAAE,CAAC;YAC7C,MAAM,gBAAgB,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC;YACpE,MAAM,UAAU,GAAG,eAAe,IAAI,gBAAgB,CAAC;YAEvD,OAAO;gBACL,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,OAAO;gBACd,OAAO,EAAE,KAAK,EAAE,uBAAuB;gBACvC,UAAU;gBACV,OAAO,EAAE;oBACP,eAAe;oBACf,gBAAgB;oBAChB,gBAAgB;oBAChB,QAAQ,EAAE,gBAAgB,EAAE;iBAC7B;gBACD,KAAK,EAAE,CAAC,UAAU;oBAChB,CAAC,CAAC,uEAAuE;oBACzE,CAAC,CAAC,SAAS;aACd,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AA4BD,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,KAAK,UAAU,mBAAmB,CAChC,KAAc,EACd,MAAe;IAEf,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,IAAI,6BAA6B,EAAE,EAAE,CAAC;YACpC,IAAI,CAAC,uBAAuB,EAAE,CAAC;gBAC7B,uBAAuB,GAAG,IAAI,CAAC;gBAC/B,OAAO,CAAC,KAAK,CACX,wFAAwF;oBACtF,2GAA2G,CAC9G,CAAC;YACJ,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC,uBAAuB,EAAE,CAAC;YAC7B,uBAAuB,GAAG,IAAI,CAAC;YAC/B,OAAO,CAAC,IAAI,CACV,yGAAyG,CAC1G,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAC3C,MAAM,aAAa,GAAG,SAAS,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;IACzD,MAAM,aAAa,GAAG,SAAS,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;IAEzD,IAAI,CAAC,MAAM,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,EAAE,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;QACvD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,2DAA2D;IAC3D,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IACvC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC;QAC3C,OAAO,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QAC1D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IAE3C,oDAAoD;IACpD,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACzE,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAErD,MAAM,aAAa,GAAG,GAAG,MAAM,IAAI,aAAa,IAAI,IAAI,EAAE,CAAC;IAC3D,MAAM,iBAAiB,GAAG,MAAM;SAC7B,UAAU,CAAC,QAAQ,EAAE,WAAW,CAAC;SACjC,MAAM,CAAC,aAAa,CAAC;SACrB,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEpB,+EAA+E;IAC/E,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5C,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAC5D,IAAI,CAAC;YACH,IACE,MAAM,CAAC,eAAe,CACpB,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAC9B,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CACtB,EACD,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,uCAAuC;QACzC,CAAC;IACH,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IAC3D,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,MAAM,CAAC,CAAS,EAAE,CAAS;IAClC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC9C,OAAO,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC;AAED,KAAK,UAAU,qBAAqB,CAClC,KAAc,EACd,MAAe;IAEf,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,IAAI,6BAA6B,EAAE,EAAE,CAAC;YACpC,IAAI,CAAC,yBAAyB,EAAE,CAAC;gBAC/B,yBAAyB,GAAG,IAAI,CAAC;gBACjC,OAAO,CAAC,KAAK,CACX,0FAA0F;oBACxF,2GAA2G,CAC9G,CAAC;YACJ,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC,yBAAyB,EAAE,CAAC;YAC/B,yBAAyB,GAAG,IAAI,CAAC;YACjC,OAAO,CAAC,IAAI,CACV,2GAA2G,CAC5G,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,wDAAwD;IACxD,MAAM,UAAU,GAAG,SAAS,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;IACrD,IAAI,UAAU,EAAE,CAAC;QACf,iEAAiE;QACjE,IAAI,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;YACtE,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACvC,IAAI,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC;QACtE,CAAC;IACH,CAAC;IAED,qEAAqE;IACrE,MAAM,YAAY,GAAG,SAAS,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC;IAC1D,IAAI,YAAY,KAAK,SAAS,IAAI,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAE5E,OAAO,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;IACpE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E,KAAK,UAAU,kBAAkB,CAAC,KAAc;IAC9C,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,gBAAgB;QAAE,OAAO,IAAI,CAAC;IAEzD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACvB,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,kEAAkE;IAClE,iEAAiE;IACjE,MAAM,OAAO,GAAG,IAAI,CAAC,IAA0B,CAAC;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACzD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,MAAM,KAAK,GAAG,IAAI,CAAC,EAAmC,CAAC;IACvD,MAAM,EAAE,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,EAAmC,CAAC;IACvD,MAAM,EAAE,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAEvC,wDAAwD;IACxD,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,SAAS,GACb,OAAO,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,QAAQ,IAAI,UAAU,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAEnE,wEAAwE;IACxE,wEAAwE;IACxE,iEAAiE;IACjE,MAAM,cAAc,GAAG,qBAAqB,CAAC;QAC3C,SAAS,EAAE,IAAI,CAAC,KAAK;QACrB,WAAW,EAAE,OAAO,CAAC,wBAAwB,CAAC;QAC9C,IAAI,EAAE,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QAC3D,GAAG,EAAE,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;KACzD,CAAC,CAAC;IAEH,OAAO;QACL,SAAS;QACT,OAAO,EAAG,IAAI,CAAC,OAAkB,IAAI,cAAc;QACnD,IAAI;QACJ,EAAE;QACF,EAAE,EAAE,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;QAClC,IAAI,EAAE,IAAI,CAAC,IAA0B;QACrC,IAAI,EAAE,IAAI,CAAC,IAA0B;QACrC,SAAS,EAAE,OAAO,CAAC,aAAa,CAAC,IAAI,SAAS;QAC9C,UAAU,EAAE,qBAAqB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACxD,IAAI,EAAG,IAAI,CAAC,UAAqB,IAAI,SAAS;QAC9C,cAAc;KACf,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,oBAAoB,CACjC,KAAc;IAEd,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,sDAAsD;IACtD,uDAAuD;IACvD,MAAM,OAAO,GAAG,IAAI,CAAC,IAA0B,CAAC;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACzD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,MAAM,KAAK,GAAG,IAAI,CAAC,EAAwB,CAAC;IAC5C,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,MAAM,KAAK,GAAG,IAAI,CAAC,EAAwB,CAAC;IAC5C,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEtE,2BAA2B;IAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,OAA6B,CAAC;IACtD,MAAM,OAAO,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,YAAY,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAEpE,8EAA8E;IAC9E,wDAAwD;IACxD,0EAA0E;IAC1E,oDAAoD;IACpD,MAAM,cAAc,GAAG,qBAAqB,CAAC;QAC3C,SAAS,EAAE,IAAI,CAAC,KAAK;QACrB,WAAW,EAAE,OAAO,CAAC,wBAAwB,CAAC;QAC9C,IAAI,EAAE,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QAC3D,GAAG,EAAE,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;KACzD,CAAC,CAAC;IAEH,OAAO;QACL,SAAS;QACT,OAAO,EAAG,IAAI,CAAC,OAAkB,IAAI,cAAc;QACnD,IAAI;QACJ,EAAE;QACF,EAAE,EAAE,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;QAClC,IAAI,EAAE,IAAI,CAAC,IAA0B;QACrC,IAAI,EAAE,IAAI,CAAC,IAA0B;QACrC,SAAS,EAAE,OAAO,CAAC,aAAa,CAAC,IAAI,SAAS;QAC9C,UAAU,EAAE,qBAAqB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACxD,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,SAAS;QAClC,cAAc;KACf,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,+CAA+C;AAC/C,8EAA8E;AAE9E;;;;;;GAMG;AACH,SAAS,WAAW,CAAC,KAAa;IAChC,MAAM,EAAE,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,EAAE,IAAI,CAAC;QACZ,CAAC,CAAC,KAAK;aACF,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;aACb,IAAI,EAAE;aACN,WAAW,EAAE;QAClB,CAAC,CAAC,EAAE,CAAC;AACT,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY,CAAC,UAAkB,EAAE,aAAqB;IAC7D,IAAI,CAAC,UAAU,IAAI,CAAC,aAAa;QAAE,OAAO,KAAK,CAAC;IAChD,IAAI,UAAU,KAAK,aAAa;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,CACL,UAAU,CAAC,QAAQ,CAAC,IAAI,aAAa,EAAE,CAAC;QACxC,aAAa,CAAC,QAAQ,CAAC,IAAI,UAAU,EAAE,CAAC,CACzC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,qBAAqB,CAAC,KAK9B;IACC,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAChD,IAAI,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IAE9B,mEAAmE;IACnE,iDAAiD;IACjD,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CACrC,8EAA8E,CAC/E,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;YAC5B,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;YACnC,IAAI,OAAO,KAAK,MAAM,IAAI,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC1E,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,0EAA0E;IAC1E,sEAAsE;IACtE,0EAA0E;IAC1E,2EAA2E;IAC3E,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;QACd,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAClD,IAAI,UAAU,KAAK,MAAM;YAAE,OAAO,IAAI,CAAC;IACzC,CAAC;IAED,2EAA2E;IAC3E,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACtB,MAAM,EAAE,GAAG,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;QAC3C,+BAA+B;QAC/B,MAAM,MAAM,GAAG,qDAAqD,CAAC;QACrE,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACpC,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACtC,IAAI,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC;QACpD,CAAC;QACD,wDAAwD;QACxD,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;IACzC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,KAAK,UAAU,aAAa,CAAC,WAAmB;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,oBAAoB,CAAC;IACjD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;YACpC,GAAG,EAAE;;;;;;OAMJ;YACD,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,gBAAgB,WAAW,IAAI,CAAC;SACzD,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,CACjB,IAAI,CAAC,CAAC,CAAyC,EAAE,CAAC,IAAI,CAAC,CACzD,CAAC;QACF,OAAO,KAAK,IAAI,cAAc,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;QACzE,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,kCAAkC;AAClC,8EAA8E;AAE9E,kEAAkE;AAClE,SAAS,iBAAiB,CAAC,GAAW;IACpC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACrD,IAAI,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACtB,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,SAAS;YAC9D,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;SACvB,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;AAC/B,CAAC;AAED,qGAAqG;AACrG,SAAS,oBAAoB,CAAC,GAAkC;IAC9D,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACxD,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED,8EAA8E;AAC9E,2BAA2B;AAC3B,8EAA8E;AAE9E,+EAA+E;AAC/E,SAAS,kBAAkB,CAAC,OAAgB;IAC1C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,IAAI,CAAC,OAAO;QAAE,OAAO,MAAM,CAAC;IAE5B,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;gBAC9D,MAAM,CAAE,CAAC,CAAC,IAAe,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,KAAe,CAAC;YAC/D,CAAC;QACH,CAAC;IACH,CAAC;SAAM,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QACvC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CACvC,OAAkC,CACnC,EAAE,CAAC;YACF,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,kFAAkF;AAClF,SAAS,kBAAkB,CAAC,GAAuB;IACjD,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,IAAI,CAAC,GAAG;QAAE,OAAO,MAAM,CAAC;IAExB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,UAAU,GAAG,EAAE,CAAC;IACpB,IAAI,YAAY,GAAG,EAAE,CAAC;IAEtB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,6CAA6C;QAC7C,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,UAAU,EAAE,CAAC;YACnC,YAAY,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAClC,SAAS;QACX,CAAC;QACD,uBAAuB;QACvB,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,GAAG,YAAY,CAAC;QAClD,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5C,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,UAAU,GAAG,EAAE,CAAC;YAChB,YAAY,GAAG,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IACD,mBAAmB;IACnB,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,GAAG,YAAY,CAAC;IAClD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,mEAAmE;AACnE,SAAS,qBAAqB,CAC5B,UAA8B;IAE9B,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAC;IAClC,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACzC,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AACjD,CAAC;AAED,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E;;;;GAIG;AACH,SAAS,eAAe,CAAC,SAAiB,EAAE,UAAqB;IAC/D,IAAI,UAAU,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,qBAAqB,CAC5B,WAAmB,EACnB,WAAmB;IAEnB,OAAO,GAAG,WAAW,CAAC,WAAW,EAAE,KAAK,WAAW,EAAE,CAAC;AACxD,CAAC;AAED,8EAA8E;AAC9E,2BAA2B;AAC3B,8EAA8E;AAE9E,0DAA0D;AAC1D,SAAS,qBAAqB,CAAC,GAA4B;IACzD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,8BAA8B;IAC9B,MAAM,IAAI,GAAG,GAAG,CAAC,UAAkC,CAAC;IACpD,IAAI,IAAI,EAAE,CAAC;QACT,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;IACtB,CAAC;IAED,gCAAgC;IAChC,MAAM,SAAS,GAAG,GAAG,CAAC,SAA+B,CAAC;IACtD,IAAI,SAAS,EAAE,CAAC;QACd,mBAAmB;QACnB,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,OAAwB;IAC/C,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,WAAW,EAAE,CAAC;IACpE,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACpD,MAAM,WAAW,GAAI,OAAO,CAAC,eAAe,CAAC,EAAe,IAAI,EAAE,CAAC;IACnE,MAAM,WAAW,GAAI,OAAO,CAAC,eAAe,CAAC,EAAe,IAAI,EAAE,CAAC;IAEnE,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,WAAW,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC;QACpD,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAC7C,gEAAgE;QAChE,IAAI,UAAU,KAAK,YAAY,IAAI,UAAU,KAAK,WAAW,EAAE,CAAC;YAC9D,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,OAAO,aAAa,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACxE,CAAC;AAED,8EAA8E;AAC9E,4BAA4B;AAC5B,8EAA8E;AAE9E,4DAA4D;AAC5D,SAAS,qBAAqB,CAAC,IAAY;IACzC,OAAO,IAAI;SACR,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC;SAC7B,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;SAC1B,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC;SAC1B,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC;SACzB,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC;SAC5B,OAAO,CAAC,cAAc,EAAE,MAAM,CAAC;SAC/B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;SAC1B,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC;SACL,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,uBAAuB,CAAC,CAAS;IACxC,OAAO,CAAC;SACL,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,2BAA2B,CAAC,GAAW;IAI9C,IAAI,GAAG,GAAG,GAAG,CAAC;IACd,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAE7C,SAAS,CAAC;QACR,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CACjD,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CACxB,CAAC;QACF,IAAI,CAAC,MAAM;YAAE,MAAM;QACnB,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACnC,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC/B,CAAC;IAED,OAAO,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7B,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;QACpC,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,QAAQ,GAAG,GAAG,GAAG,QAAQ,CAAC;QAC1B,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;AAC3B,CAAC;AAED,SAAS,WAAW,CAAC,MAAc;IACjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,WAAW,CAAC;IACrB,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAe;IACzC,OAAO,OAAO,CAAC,OAAO,CAAC,2BAA2B,EAAE,CAAC,GAAG,EAAE,EAAE;QAC1D,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,2BAA2B,CAAC,GAAG,CAAC,CAAC;QAC3D,MAAM,IAAI,GAAG,uBAAuB,CAAC,GAAG,CAAC,CAAC;QAC1C,OAAO,YAAY,UAAU,CAAC,IAAI,CAAC,sDAAsD,UAAU,CACjG,WAAW,CAAC,GAAG,CAAC,CACjB,OAAO,QAAQ,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAC1C,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,IAAI,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACpC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC;YACzC,CAAC;iBAAM,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzC,SAAS,IAAI,CAAC,CAAC;YACjB,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACzD,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,yDAAyD;AACzD,SAAS,cAAc,CAAC,EAAU;IAChC,IAAI,IAAI,GAAG,EAAE,CAAC;IAEd,kEAAkE;IAClE,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAExB,6BAA6B;IAC7B,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,CAAC;IAC7D,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,qBAAqB,CAAC,CAAC;IAEzD,mEAAmE;IACnE,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,4BAA4B,EAAE,aAAa,CAAC,CAAC;IACjE,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,0BAA0B,EAAE,aAAa,CAAC,CAAC;IAE/D,qBAAqB;IACrB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,0BAA0B,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACrE,MAAM,YAAY,GAAG,eAAe,CAAC,IAAI,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;YACvE,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAChC,CAAC,CAAC,KAAK,CAAC;QACV,OAAO,YAAY,UAAU,CAC3B,uBAAuB,CAAC,GAAG,CAAC,CAC7B,sDAAsD,YAAY,MAAM,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,sBAAsB;IACtB,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,YAAY,EACZ,+FAA+F,CAChG,CAAC;IAEF,4EAA4E;IAC5E,IAAI,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAEnC,oDAAoD;IACpD,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC;IACtD,gCAAgC;IAChC,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,sBAAsB,EACtB,qDAAqD,CACtD,CAAC;IAEF,uDAAuD;IACvD,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;IACrD,oDAAoD;IACpD,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,iCAAiC,EAAE,CAAC,KAAK,EAAE,EAAE;QAC/D,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACxC,OAAO,+CAA+C,KAAK,OAAO,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,0BAA0B;IAC1B,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,cAAc,EACd,wDAAwD,CACzD,CAAC;IACF,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,aAAa,EACb,yDAAyD,CAC1D,CAAC;IACF,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,YAAY,EACZ,wDAAwD,CACzD,CAAC;IAEF,+BAA+B;IAC/B,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,oBAAoB,EACpB,sEAAsE,CACvE,CAAC;IAEF,8BAA8B;IAC9B,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACxC,yBAAyB;IACzB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAEnC,yBAAyB;IACzB,IAAI,GAAG,MAAM,IAAI,MAAM,CAAC;IACxB,4BAA4B;IAC5B,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IAExC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,oEAAoE;AACpE,SAAS,mBAAmB,CAAC,QAAgB;IAC3C,OAAO;;;;;;;;EAQP,QAAQ;;;QAGF,CAAC;AACT,CAAC;AAED,8EAA8E;AAC9E,kDAAkD;AAClD,8EAA8E;AAE9E;;;;;GAKG;AACH,KAAK,UAAU,WAAW,CAAC,KAAc;IACvC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;IACvC,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC9C,MAAM,GAAG,GAAG,CAAC,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/C,KAAK,CAAC,OAAO,CAAC,SAAS,GAAG,GAAG,CAAC;IAC9B,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["import type { H3Event } from \"h3\";\nimport { getHeader, readRawBody as h3ReadRawBody } from \"h3\";\nimport { timingSafeEqual } from \"node:crypto\";\nimport type {\n PlatformAdapter,\n IncomingMessage,\n OutgoingMessage,\n IntegrationStatus,\n OutboundTarget,\n} from \"../types.js\";\nimport type { EnvKeyConfig } from \"../../server/create-server.js\";\nimport { getIntegrationConfig } from \"../config-store.js\";\nimport { getDbExec } from \"../../db/client.js\";\nimport {\n sendEmail,\n isEmailConfigured,\n getEmailProvider,\n} from \"../../server/email.js\";\n\n/** Max body length before truncation */\nconst EMAIL_MAX_BODY_LENGTH = 15000;\n\n/** Rate limit: max emails per sender within the window */\nconst RATE_LIMIT_MAX = 20;\n/** Rate limit window in ms (1 hour) */\nconst RATE_LIMIT_WINDOW_MS = 60 * 60 * 1000;\n\n/**\n * One-shot warning flags so we don't spam logs on every webhook.\n * Cleared per process — one warning per cold start is enough to surface\n * a misconfiguration without leaking config status to anyone with log access\n * (M6 in the webhook security audit).\n */\nlet _resendUnverifiedWarned = false;\nlet _sendgridUnverifiedWarned = false;\n\n/**\n * Returns true when the deployment is running in production mode and the\n * operator has NOT explicitly opted into accepting unverified webhooks for\n * local testing. In production we MUST refuse webhooks whose signature can't\n * be verified — accepting them with attacker-controlled `from:` addresses\n * lets the dispatch owner-resolution path run as the victim (C1 in the\n * webhook security audit).\n */\nfunction shouldRefuseWhenSecretMissing(): boolean {\n if (process.env.AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS === \"1\") return false;\n return process.env.NODE_ENV === \"production\";\n}\n\n/**\n * Create an Email platform adapter for inbound/outbound email via\n * Resend or SendGrid webhooks.\n *\n * Required env vars:\n * - EMAIL_AGENT_ADDRESS — The email address the agent receives mail at\n *\n * One of these must also be set (checked via isEmailConfigured()):\n * - RESEND_API_KEY — For sending/receiving via Resend\n * - SENDGRID_API_KEY — For sending/receiving via SendGrid\n *\n * Optional:\n * - EMAIL_INBOUND_WEBHOOK_SECRET — Webhook signature verification secret\n */\nexport function emailAdapter(): PlatformAdapter {\n return {\n platform: \"email\",\n label: \"Email\",\n\n getRequiredEnvKeys(): EnvKeyConfig[] {\n return [\n {\n key: \"EMAIL_AGENT_ADDRESS\",\n label: \"Agent Email Address\",\n required: true,\n helpText:\n \"The email address people will use to message your agent (e.g. `agent@yourcompany.com`, or pick from your `<slug>.resend.app` sandbox).\",\n },\n {\n key: \"RESEND_API_KEY\",\n label: \"Resend API Key\",\n required: false,\n helpText:\n \"From resend.com → API keys (starts with `re_`). Either Resend or SendGrid is required for sending and receiving mail.\",\n },\n {\n key: \"SENDGRID_API_KEY\",\n label: \"SendGrid API Key\",\n required: false,\n helpText:\n \"From sendgrid.com → Settings → API Keys (starts with `SG.`). Either Resend or SendGrid is required.\",\n },\n {\n key: \"EMAIL_INBOUND_WEBHOOK_SECRET\",\n label: \"Inbound Webhook Secret\",\n required: false,\n helpText:\n \"Optional. From Resend (Webhooks → Signing Secret, starts with `whsec_`) or your SendGrid Inbound Parse basic-auth password. Used to verify inbound webhooks are real.\",\n },\n ];\n },\n\n async handleVerification(\n _event: H3Event,\n ): Promise<{ handled: boolean; response?: unknown }> {\n // Email webhooks don't need challenge handshakes\n return { handled: false };\n },\n\n async verifyWebhook(event: H3Event): Promise<boolean> {\n const secret = process.env.EMAIL_INBOUND_WEBHOOK_SECRET;\n const provider = getEmailProvider();\n\n if (provider === \"resend\") {\n return verifyResendWebhook(event, secret);\n }\n\n if (provider === \"sendgrid\") {\n return verifySendGridWebhook(event, secret);\n }\n\n // No provider configured — reject\n console.warn(\"[email] No email provider configured, rejecting webhook\");\n return false;\n },\n\n async parseIncomingMessage(\n event: H3Event,\n ): Promise<IncomingMessage | null> {\n const provider = getEmailProvider();\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS?.toLowerCase();\n if (!agentAddress) {\n console.warn(\"[email] EMAIL_AGENT_ADDRESS not configured\");\n return null;\n }\n\n let parsed: ParsedEmail | null = null;\n\n if (provider === \"resend\") {\n parsed = await parseResendWebhook(event);\n } else if (provider === \"sendgrid\") {\n parsed = await parseSendGridWebhook(event);\n }\n\n if (!parsed) return null;\n\n // Rate limiting (SQL-backed heuristic — counts the sender's already-queued\n // tasks within the last hour). The previous in-memory map reset on every\n // serverless cold start, so the actual ceiling per attacker was\n // RATE_LIMIT_MAX × number_of_active_instances. SQL-backed counting holds\n // across instances. See H4 in the webhook security audit.\n const senderEmail = parsed.from.email.toLowerCase();\n if (await isRateLimited(senderEmail)) {\n console.warn(\n `[email] Rate limited sender: ${senderEmail} (>${RATE_LIMIT_MAX}/hr)`,\n );\n return null;\n }\n\n // Check allowed domains\n const config = await getIntegrationConfig(\"email\");\n if (config?.configData?.allowedDomains) {\n const allowed = config.configData.allowedDomains as string[];\n if (allowed.length > 0) {\n const senderDomain = senderEmail.split(\"@\")[1];\n if (!senderDomain || !allowed.includes(senderDomain)) {\n console.warn(\n `[email] Rejected email from ${senderEmail}: domain not in allowedDomains`,\n );\n return null;\n }\n }\n }\n\n // Determine if agent was CC'd (not in To, but in CC)\n const toAddresses = parsed.to.map((a) => a.toLowerCase());\n const ccAddresses = (parsed.cc ?? []).map((a) => a.toLowerCase());\n const isCC =\n !toAddresses.includes(agentAddress) &&\n ccAddresses.includes(agentAddress);\n\n // Build thread ID from References chain (Gmail-style: oldest Message-ID is thread root).\n // Scope the thread root by sender so an attacker who can forge a `References:`\n // header pointing at someone else's thread root can't graft into that thread.\n // Without this scoping, a third party could craft an inbound email whose\n // References chain matches a known victim's Message-ID and inject messages into\n // the victim's existing conversation — leaking prior content via the agent's\n // reply (M1 in the webhooks security audit).\n const threadRootId = scopeThreadIdToSender(\n getThreadRootId(parsed.messageId, parsed.references),\n senderEmail,\n );\n\n // Build body text\n let bodyText = parsed.text || stripHtmlForPlainText(parsed.html || \"\");\n\n // Truncate if needed\n if (bodyText.length > EMAIL_MAX_BODY_LENGTH) {\n bodyText =\n bodyText.slice(0, EMAIL_MAX_BODY_LENGTH) + \"\\n[Message truncated]\";\n }\n\n // Prefix CC'd emails with context\n if (isCC) {\n const otherRecipients = toAddresses\n .filter((a) => a !== agentAddress)\n .join(\", \");\n bodyText =\n `[CC'd on email between ${senderEmail} and ${otherRecipients || \"others\"}]\\n` +\n `Subject: ${parsed.subject}\\n\\n` +\n bodyText;\n }\n\n return {\n platform: \"email\",\n externalThreadId: threadRootId,\n text: bodyText,\n senderName: parsed.from.name,\n senderId: senderEmail,\n // Carry the message-authentication verdict downstream. Owner\n // resolution (dispatch) must NOT grant a real user's identity /\n // credentials unless the sender is verified — an unverified or\n // spoofed `From:` falls back to a synthetic, credential-less owner.\n senderVerified: parsed.senderVerified,\n platformContext: {\n messageId: parsed.messageId,\n subject: parsed.subject,\n from: senderEmail,\n to: parsed.to,\n cc: parsed.cc,\n inReplyTo: parsed.inReplyTo,\n references: parsed.references,\n isCC,\n senderVerified: parsed.senderVerified,\n },\n timestamp: parsed.date ? new Date(parsed.date).getTime() : Date.now(),\n };\n },\n\n async sendResponse(\n message: OutgoingMessage,\n context: IncomingMessage,\n ): Promise<void> {\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS;\n if (!agentAddress) {\n console.error(\"[email] EMAIL_AGENT_ADDRESS not configured\");\n return;\n }\n\n const config = await getIntegrationConfig(\"email\");\n const displayName =\n (config?.configData?.displayName as string) || \"Dispatch Agent\";\n\n // EMAIL_FROM overrides the from-address — required when the receiving\n // address is on a sub-domain that can't be a verified sender (e.g.\n // *.resend.app). Inbound and outbound addresses can differ.\n const fromAddress = process.env.EMAIL_FROM\n ? process.env.EMAIL_FROM\n : `${displayName} <${agentAddress}>`;\n\n const subject = context.platformContext.subject as string;\n const reSubject = subject.startsWith(\"Re: \") ? subject : `Re: ${subject}`;\n\n try {\n await sendEmail({\n to: context.senderId!,\n from: fromAddress,\n subject: reSubject,\n html: message.text,\n text: stripHtmlForPlainText(message.text),\n inReplyTo: context.platformContext.messageId as string,\n references: buildReferencesHeader(context.platformContext),\n cc: context.platformContext.isCC\n ? buildReplyAllCc(context)\n : undefined,\n });\n } catch (err) {\n console.error(\"[email] Failed to send response:\", err);\n }\n },\n\n async sendMessageToTarget(\n message: OutgoingMessage,\n target: OutboundTarget,\n ): Promise<void> {\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS;\n if (!agentAddress) {\n console.error(\"[email] EMAIL_AGENT_ADDRESS not configured\");\n return;\n }\n\n const config = await getIntegrationConfig(\"email\");\n const displayName =\n (config?.configData?.displayName as string) || \"Dispatch Agent\";\n\n try {\n await sendEmail({\n to: target.destination,\n from: `${displayName} <${agentAddress}>`,\n subject: target.label || \"Message from Dispatch Agent\",\n html: message.text,\n text: stripHtmlForPlainText(message.text),\n ...(target.threadRef\n ? {\n inReplyTo: target.threadRef,\n references: target.threadRef,\n }\n : {}),\n });\n } catch (err) {\n console.error(\"[email] Failed to send proactive message:\", err);\n throw err;\n }\n },\n\n formatAgentResponse(text: string): OutgoingMessage {\n const bodyHtml = markdownToHtml(text);\n const html = wrapInEmailTemplate(bodyHtml);\n return { text: html, platformContext: {} };\n },\n\n async getStatus(_baseUrl?: string): Promise<IntegrationStatus> {\n const hasAgentAddress = !!process.env.EMAIL_AGENT_ADDRESS;\n const hasEmailProvider = isEmailConfigured();\n const hasWebhookSecret = !!process.env.EMAIL_INBOUND_WEBHOOK_SECRET;\n const configured = hasAgentAddress && hasEmailProvider;\n\n return {\n platform: \"email\",\n label: \"Email\",\n enabled: false, // overridden by plugin\n configured,\n details: {\n hasAgentAddress,\n hasEmailProvider,\n hasWebhookSecret,\n provider: getEmailProvider(),\n },\n error: !configured\n ? \"Set EMAIL_AGENT_ADDRESS and either RESEND_API_KEY or SENDGRID_API_KEY\"\n : undefined,\n };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Parsed email shape\n// ---------------------------------------------------------------------------\n\ninterface ParsedEmail {\n messageId: string;\n subject: string;\n from: { name?: string; email: string };\n to: string[];\n cc?: string[];\n text?: string;\n html?: string;\n inReplyTo?: string;\n references?: string[];\n date?: string;\n /**\n * True when the provider's message-authentication results show that the\n * mail genuinely originated from the From domain: DKIM `pass` aligned with\n * the From domain, or an aligned SPF `pass`. False when results are absent\n * or fail — we fail closed so a spoofed `From:` can never be treated as\n * verified. See FINDING 3 (inbound-email impersonation) in the webhook\n * security audit.\n */\n senderVerified: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Webhook verification\n// ---------------------------------------------------------------------------\n\nasync function verifyResendWebhook(\n event: H3Event,\n secret?: string,\n): Promise<boolean> {\n if (!secret) {\n if (shouldRefuseWhenSecretMissing()) {\n if (!_resendUnverifiedWarned) {\n _resendUnverifiedWarned = true;\n console.error(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — refusing Resend webhook in production. \" +\n \"Set EMAIL_INBOUND_WEBHOOK_SECRET, or set AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS=1 for local testing only.\",\n );\n }\n return false;\n }\n if (!_resendUnverifiedWarned) {\n _resendUnverifiedWarned = true;\n console.warn(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — accepting Resend webhook without verification (dev mode)\",\n );\n }\n return true;\n }\n\n const svixId = getHeader(event, \"svix-id\");\n const svixTimestamp = getHeader(event, \"svix-timestamp\");\n const svixSignature = getHeader(event, \"svix-signature\");\n\n if (!svixId || !svixTimestamp || !svixSignature) {\n console.warn(\"[email] Missing Svix signature headers\");\n return false;\n }\n\n // Reject requests older than 5 minutes (replay protection)\n const ts = parseInt(svixTimestamp, 10);\n if (Math.abs(Date.now() / 1000 - ts) > 300) {\n console.warn(\"[email] Svix timestamp too old, rejecting\");\n return false;\n }\n\n const body = await readRawBody(event);\n const crypto = await import(\"node:crypto\");\n\n // Svix signing secret may be prefixed with \"whsec_\"\n const rawSecret = secret.startsWith(\"whsec_\") ? secret.slice(6) : secret;\n const secretBytes = Buffer.from(rawSecret, \"base64\");\n\n const signedContent = `${svixId}.${svixTimestamp}.${body}`;\n const expectedSignature = crypto\n .createHmac(\"sha256\", secretBytes)\n .update(signedContent)\n .digest(\"base64\");\n\n // Svix sends multiple signatures separated by spaces, each prefixed with \"v1,\"\n const signatures = svixSignature.split(\" \");\n for (const sig of signatures) {\n const sigValue = sig.startsWith(\"v1,\") ? sig.slice(3) : sig;\n try {\n if (\n crypto.timingSafeEqual(\n Buffer.from(expectedSignature),\n Buffer.from(sigValue),\n )\n ) {\n return true;\n }\n } catch {\n // Length mismatch — try next signature\n }\n }\n\n console.warn(\"[email] Svix signature verification failed\");\n return false;\n}\n\nfunction safeEq(a: string, b: string): boolean {\n const aBuf = Buffer.from(a);\n const bBuf = Buffer.from(b);\n if (aBuf.length !== bBuf.length) return false;\n return timingSafeEqual(aBuf, bBuf);\n}\n\nasync function verifySendGridWebhook(\n event: H3Event,\n secret?: string,\n): Promise<boolean> {\n if (!secret) {\n if (shouldRefuseWhenSecretMissing()) {\n if (!_sendgridUnverifiedWarned) {\n _sendgridUnverifiedWarned = true;\n console.error(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — refusing SendGrid webhook in production. \" +\n \"Set EMAIL_INBOUND_WEBHOOK_SECRET, or set AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS=1 for local testing only.\",\n );\n }\n return false;\n }\n if (!_sendgridUnverifiedWarned) {\n _sendgridUnverifiedWarned = true;\n console.warn(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — accepting SendGrid webhook without verification (dev mode)\",\n );\n }\n return true;\n }\n\n // Check for the secret in a custom header or basic auth\n const authHeader = getHeader(event, \"authorization\");\n if (authHeader) {\n // Basic auth: \"Basic base64(user:pass)\" — secret is the password\n if (authHeader.startsWith(\"Basic \")) {\n const decoded = Buffer.from(authHeader.slice(6), \"base64\").toString();\n const password = decoded.split(\":\")[1];\n if (password !== undefined && safeEq(password, secret)) return true;\n }\n }\n\n // Also check a custom header (common SendGrid Inbound Parse pattern)\n const customSecret = getHeader(event, \"x-webhook-secret\");\n if (customSecret !== undefined && safeEq(customSecret, secret)) return true;\n\n console.warn(\"[email] SendGrid webhook secret verification failed\");\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Inbound email parsing\n// ---------------------------------------------------------------------------\n\nasync function parseResendWebhook(event: H3Event): Promise<ParsedEmail | null> {\n const raw = await readRawBody(event);\n const body = JSON.parse(raw);\n if (!body || body.type !== \"email.received\") return null;\n\n const data = body.data;\n if (!data) return null;\n\n // Resend webhook payload provides email metadata directly in data\n // Fields: from, to, cc, subject, text, html, headers, created_at\n const fromRaw = data.from as string | undefined;\n const from = fromRaw ? parseEmailAddress(fromRaw) : null;\n if (!from) return null;\n\n const toRaw = data.to as string | string[] | undefined;\n const to = normalizeAddressList(toRaw);\n const ccRaw = data.cc as string | string[] | undefined;\n const cc = normalizeAddressList(ccRaw);\n\n // Parse headers for Message-ID, In-Reply-To, References\n const headers = parseHeadersObject(data.headers);\n const messageId =\n headers[\"message-id\"] || data.email_id || `resend-${Date.now()}`;\n\n // Resend forwards the raw `Authentication-Results` header (and may also\n // surface explicit `dkim`/`spf` fields). Derive a verified verdict from\n // whichever is present; absent results fail closed (unverified).\n const senderVerified = computeSenderVerified({\n fromEmail: from.email,\n authResults: headers[\"authentication-results\"],\n dkim: typeof data.dkim === \"string\" ? data.dkim : undefined,\n spf: typeof data.spf === \"string\" ? data.spf : undefined,\n });\n\n return {\n messageId,\n subject: (data.subject as string) || \"(no subject)\",\n from,\n to,\n cc: cc.length > 0 ? cc : undefined,\n text: data.text as string | undefined,\n html: data.html as string | undefined,\n inReplyTo: headers[\"in-reply-to\"] || undefined,\n references: parseReferencesHeader(headers[\"references\"]),\n date: (data.created_at as string) || undefined,\n senderVerified,\n };\n}\n\nasync function parseSendGridWebhook(\n event: H3Event,\n): Promise<ParsedEmail | null> {\n const raw = await readRawBody(event);\n const body = JSON.parse(raw);\n if (!body) return null;\n\n // SendGrid Inbound Parse sends form data with fields:\n // from, to, cc, subject, text, html, headers, envelope\n const fromRaw = body.from as string | undefined;\n const from = fromRaw ? parseEmailAddress(fromRaw) : null;\n if (!from) return null;\n\n const toRaw = body.to as string | undefined;\n const to = toRaw ? toRaw.split(\",\").map((a: string) => a.trim()) : [];\n const ccRaw = body.cc as string | undefined;\n const cc = ccRaw ? ccRaw.split(\",\").map((a: string) => a.trim()) : [];\n\n // Parse raw headers string\n const headersStr = body.headers as string | undefined;\n const headers = parseHeadersString(headersStr);\n const messageId = headers[\"message-id\"] || `sendgrid-${Date.now()}`;\n\n // SendGrid Inbound Parse posts explicit `dkim` (e.g. `{@example.com : pass}`)\n // and `SPF` (e.g. `pass`) form fields, and also carries\n // `Authentication-Results` inside the raw headers blob. Use all available\n // signals; absent results fail closed (unverified).\n const senderVerified = computeSenderVerified({\n fromEmail: from.email,\n authResults: headers[\"authentication-results\"],\n dkim: typeof body.dkim === \"string\" ? body.dkim : undefined,\n spf: typeof body.SPF === \"string\" ? body.SPF : undefined,\n });\n\n return {\n messageId,\n subject: (body.subject as string) || \"(no subject)\",\n from,\n to,\n cc: cc.length > 0 ? cc : undefined,\n text: body.text as string | undefined,\n html: body.html as string | undefined,\n inReplyTo: headers[\"in-reply-to\"] || undefined,\n references: parseReferencesHeader(headers[\"references\"]),\n date: headers[\"date\"] || undefined,\n senderVerified,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — sender authentication (DKIM / SPF)\n// ---------------------------------------------------------------------------\n\n/**\n * Extract the registrable-ish domain from an email address (lowercased).\n * We keep the full host rather than collapsing to an eTLD+1 — exact-domain\n * alignment is the conservative choice here, and avoids bundling a public\n * suffix list. Subdomain senders that legitimately DKIM-sign with the parent\n * domain are handled by the suffix check in `domainsAlign`.\n */\nfunction emailDomain(email: string): string {\n const at = email.lastIndexOf(\"@\");\n return at >= 0\n ? email\n .slice(at + 1)\n .trim()\n .toLowerCase()\n : \"\";\n}\n\n/**\n * True when `signingDomain` is the From domain or a parent of it (e.g.\n * From `user@mail.example.com` aligned with a `d=example.com` signature).\n * Both directions of subdomain nesting are accepted because senders sign\n * with either the exact From host or the organizational parent.\n */\nfunction domainsAlign(fromDomain: string, signingDomain: string): boolean {\n if (!fromDomain || !signingDomain) return false;\n if (fromDomain === signingDomain) return true;\n return (\n fromDomain.endsWith(`.${signingDomain}`) ||\n signingDomain.endsWith(`.${fromDomain}`)\n );\n}\n\n/**\n * Compute whether an inbound email is authenticated as genuinely coming from\n * its `From:` domain. Returns true only when DKIM passes for an aligned\n * domain, or SPF passes for an aligned domain. Anything else — missing\n * results, `fail`, `softfail`, `none`, `neutral`, `temperror`, `permerror`\n * — returns false (fail closed).\n *\n * Inputs may come from provider-specific fields (`dkim`, `spf`) and/or the\n * RFC 8601 `Authentication-Results` header, in any combination. We treat the\n * union: if ANY source shows an aligned pass, the sender is verified.\n */\nfunction computeSenderVerified(input: {\n fromEmail: string;\n authResults?: string;\n dkim?: string;\n spf?: string;\n}): boolean {\n const fromDomain = emailDomain(input.fromEmail);\n if (!fromDomain) return false;\n\n // 1. Provider DKIM field, e.g. SendGrid `{@example.com : pass}` or\n // `{@example.com : pass; @other.com : fail}`.\n if (input.dkim) {\n const dkimEntries = input.dkim.matchAll(\n /@([a-z0-9.-]+)\\s*:\\s*(pass|fail|none|neutral|softfail|temperror|permerror)/gi,\n );\n for (const m of dkimEntries) {\n const domain = m[1].toLowerCase();\n const verdict = m[2].toLowerCase();\n if (verdict === \"pass\" && domainsAlign(fromDomain, domain)) return true;\n }\n }\n\n // 2. Provider SPF field. SendGrid posts a bare verdict (e.g. `pass`); since\n // SPF authenticates the envelope/MailFrom rather than the header From,\n // a bare `pass` with no domain only counts when we can't tell it's\n // misaligned. We accept a bare `pass` as an aligned SPF pass — this is\n // the same trust level Gmail-style routing assigns to a plain SPF pass.\n if (input.spf) {\n const spfVerdict = input.spf.trim().toLowerCase();\n if (spfVerdict === \"pass\") return true;\n }\n\n // 3. RFC 8601 `Authentication-Results` header (may list multiple methods).\n if (input.authResults) {\n const ar = input.authResults.toLowerCase();\n // DKIM with an aligned domain.\n const dkimRe = /dkim=pass[^;]*?(?:header\\.(?:d|i)=|@)([a-z0-9.-]+)/g;\n for (const m of ar.matchAll(dkimRe)) {\n const domain = m[1].replace(/^@/, \"\");\n if (domainsAlign(fromDomain, domain)) return true;\n }\n // SPF pass (envelope auth) — accept as an aligned pass.\n if (/spf=pass\\b/.test(ar)) return true;\n }\n\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Rate limiting\n// ---------------------------------------------------------------------------\n\n/**\n * Rate-limit heuristic backed by the `integration_pending_tasks` queue.\n *\n * Counts how many tasks this sender has produced in the last hour. The count\n * INCLUDES tasks already processed (status = completed/failed) because the\n * rows aren't deleted on completion — that's enough signal to throttle a\n * single noisy/abusive sender without needing a dedicated counter table.\n *\n * Two trade-offs worth knowing:\n * - This is a coarse heuristic, not exact metering. Within one hour the\n * count is correct; rows produced more than an hour ago naturally drop\n * off. We don't try to be precise, only to raise the bar past the\n * \"send 10K emails through one Lambda burst\" failure mode.\n * - The query relies on the `idx_pending_tasks_status_created` index plus\n * a sender substring match. A targeted attacker could amortise the cost\n * by reusing one sender address — that's fine, the goal here is to bound\n * the attack within a single attacker identity, not to detect spoofing.\n *\n * If the table doesn't yet exist on this deployment (no inbound webhook has\n * been processed before), we silently allow the message — the schema is\n * provisioned on first task insert. See H4 in the webhook security audit.\n */\nasync function isRateLimited(senderEmail: string): Promise<boolean> {\n const cutoff = Date.now() - RATE_LIMIT_WINDOW_MS;\n try {\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `\n SELECT COUNT(*) AS c\n FROM integration_pending_tasks\n WHERE platform = ?\n AND created_at >= ?\n AND payload LIKE ?\n `,\n args: [\"email\", cutoff, `%\"senderId\":\"${senderEmail}\"%`],\n });\n const count = Number(\n (rows[0] as Record<string, unknown> | undefined)?.c ?? 0,\n );\n return count >= RATE_LIMIT_MAX;\n } catch {\n // Table doesn't exist yet (first webhook on a fresh deployment) — allow.\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — email address parsing\n// ---------------------------------------------------------------------------\n\n/** Parse \"Name <addr@example.com>\" or plain \"addr@example.com\" */\nfunction parseEmailAddress(raw: string): { name?: string; email: string } {\n const match = raw.match(/^\\s*(.*?)\\s*<([^>]+)>\\s*$/);\n if (match && match[2]) {\n return {\n name: match[1].replace(/^[\"']|[\"']$/g, \"\").trim() || undefined,\n email: match[2].trim(),\n };\n }\n return { email: raw.trim() };\n}\n\n/** Normalize a to/cc field that may be a string, array, or undefined into a string[] of addresses */\nfunction normalizeAddressList(raw: string | string[] | undefined): string[] {\n if (!raw) return [];\n if (Array.isArray(raw)) return raw.map((a) => a.trim());\n return raw.split(\",\").map((a) => a.trim());\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — header parsing\n// ---------------------------------------------------------------------------\n\n/** Parse a headers object (Resend format: array of {name, value} or Record) */\nfunction parseHeadersObject(headers: unknown): Record<string, string> {\n const result: Record<string, string> = {};\n if (!headers) return result;\n\n if (Array.isArray(headers)) {\n for (const h of headers) {\n if (h && typeof h === \"object\" && \"name\" in h && \"value\" in h) {\n result[(h.name as string).toLowerCase()] = h.value as string;\n }\n }\n } else if (typeof headers === \"object\") {\n for (const [key, value] of Object.entries(\n headers as Record<string, unknown>,\n )) {\n result[key.toLowerCase()] = String(value);\n }\n }\n return result;\n}\n\n/** Parse a raw headers string (SendGrid format: \"Key: Value\\nKey: Value\\n...\") */\nfunction parseHeadersString(raw: string | undefined): Record<string, string> {\n const result: Record<string, string> = {};\n if (!raw) return result;\n\n const lines = raw.split(/\\r?\\n/);\n let currentKey = \"\";\n let currentValue = \"\";\n\n for (const line of lines) {\n // Continuation line (starts with whitespace)\n if (/^\\s/.test(line) && currentKey) {\n currentValue += \" \" + line.trim();\n continue;\n }\n // Save previous header\n if (currentKey) {\n result[currentKey.toLowerCase()] = currentValue;\n }\n const colonIdx = line.indexOf(\":\");\n if (colonIdx > 0) {\n currentKey = line.slice(0, colonIdx).trim();\n currentValue = line.slice(colonIdx + 1).trim();\n } else {\n currentKey = \"\";\n currentValue = \"\";\n }\n }\n // Save last header\n if (currentKey) {\n result[currentKey.toLowerCase()] = currentValue;\n }\n return result;\n}\n\n/** Parse a References header value into an array of Message-IDs */\nfunction parseReferencesHeader(\n references: string | undefined,\n): string[] | undefined {\n if (!references) return undefined;\n const ids = references.match(/<[^>]+>/g);\n return ids && ids.length > 0 ? ids : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — threading\n// ---------------------------------------------------------------------------\n\n/**\n * Get the thread root ID using a Gmail-style approach:\n * the oldest Message-ID from the References chain is the thread root.\n * If no References, use the current Message-ID.\n */\nfunction getThreadRootId(messageId: string, references?: string[]): string {\n if (references && references.length > 0) {\n return references[0];\n }\n return messageId;\n}\n\n/**\n * Scope a raw thread root id by the sender's email address. Two different\n * senders crafting the same `References:` header value should NOT collide\n * onto the same internal thread mapping — that's the email-side fix for the\n * thread-injection finding (M1 in the webhook security audit).\n *\n * The returned id is opaque to callers and stays stable across messages\n * from the same sender on the same conversation thread, so reply behaviour\n * is unchanged.\n */\nfunction scopeThreadIdToSender(\n rawThreadId: string,\n senderEmail: string,\n): string {\n return `${senderEmail.toLowerCase()}::${rawThreadId}`;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — reply building\n// ---------------------------------------------------------------------------\n\n/** Build a References header from the platform context */\nfunction buildReferencesHeader(ctx: Record<string, unknown>): string {\n const parts: string[] = [];\n\n // Include existing references\n const refs = ctx.references as string[] | undefined;\n if (refs) {\n parts.push(...refs);\n }\n\n // Append the current message ID\n const messageId = ctx.messageId as string | undefined;\n if (messageId) {\n // Avoid duplicates\n if (!parts.includes(messageId)) {\n parts.push(messageId);\n }\n }\n\n return parts.join(\" \");\n}\n\n/**\n * Build CC list for reply-all when agent was CC'd.\n * Include original To addresses and other CC addresses, excluding the agent and the original sender.\n */\nfunction buildReplyAllCc(context: IncomingMessage): string[] | undefined {\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS?.toLowerCase();\n const senderEmail = context.senderId?.toLowerCase();\n const toAddresses = (context.platformContext.to as string[]) || [];\n const ccAddresses = (context.platformContext.cc as string[]) || [];\n\n const allRecipients = new Set<string>();\n for (const addr of [...toAddresses, ...ccAddresses]) {\n const normalized = addr.toLowerCase().trim();\n // Exclude agent address and original sender (sender goes in To)\n if (normalized !== agentAddress && normalized !== senderEmail) {\n allRecipients.add(normalized);\n }\n }\n\n return allRecipients.size > 0 ? Array.from(allRecipients) : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — text conversion\n// ---------------------------------------------------------------------------\n\n/** Strip HTML tags for a plain-text version of the email */\nfunction stripHtmlForPlainText(html: string): string {\n return html\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<\\/p>/gi, \"\\n\\n\")\n .replace(/<\\/div>/gi, \"\\n\")\n .replace(/<\\/li>/gi, \"\\n\")\n .replace(/<li[^>]*>/gi, \"- \")\n .replace(/<\\/h[1-6]>/gi, \"\\n\\n\")\n .replace(/<[^>]+>/g, \"\")\n .replace(/&nbsp;/g, \" \")\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim();\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction decodeBasicHtmlEntities(s: string): string {\n return s\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\");\n}\n\nfunction splitTrailingUrlPunctuation(raw: string): {\n url: string;\n trailing: string;\n} {\n let url = raw;\n let trailing = \"\";\n const trailingEntities = [\"&quot;\", \"&#39;\"];\n\n for (;;) {\n const entity = trailingEntities.find((candidate) =>\n url.endsWith(candidate),\n );\n if (!entity) break;\n url = url.slice(0, -entity.length);\n trailing = entity + trailing;\n }\n\n while (/[.,!?;:]$/.test(url)) {\n trailing = url.slice(-1) + trailing;\n url = url.slice(0, -1);\n }\n\n while (url.endsWith(\")\") && !url.includes(\"(\")) {\n trailing = \")\" + trailing;\n url = url.slice(0, -1);\n }\n\n return { url, trailing };\n}\n\nfunction labelForUrl(rawUrl: string): string {\n try {\n const parsed = new URL(decodeBasicHtmlEntities(rawUrl));\n const host = parsed.hostname.replace(/^www\\./, \"\");\n return host ? `Open ${host}` : \"Open link\";\n } catch {\n return \"Open link\";\n }\n}\n\nfunction linkifyTextSegment(segment: string): string {\n return segment.replace(/\\bhttps?:\\/\\/[^\\s<>\"']+/gi, (raw) => {\n const { url, trailing } = splitTrailingUrlPunctuation(raw);\n const href = decodeBasicHtmlEntities(url);\n return `<a href=\"${escapeHtml(href)}\" style=\"color:#2563eb;text-decoration:underline;\">${escapeHtml(\n labelForUrl(url),\n )}</a>${trailing}`;\n });\n}\n\nfunction linkifyBareUrlsInHtml(html: string): string {\n const parts = html.split(/(<\\/?[^>]+>)/g);\n let skipDepth = 0;\n\n return parts\n .map((part) => {\n if (part.startsWith(\"<\") && part.endsWith(\">\")) {\n if (/^<\\/\\s*(a|code)\\b/i.test(part)) {\n skipDepth = Math.max(0, skipDepth - 1);\n } else if (/^<\\s*(a|code)\\b/i.test(part)) {\n skipDepth += 1;\n }\n return part;\n }\n return skipDepth > 0 ? part : linkifyTextSegment(part);\n })\n .join(\"\");\n}\n\n/** Convert basic markdown to HTML for email rendering */\nfunction markdownToHtml(md: string): string {\n let html = md;\n\n // Escape HTML entities in the source (but not our generated tags)\n html = escapeHtml(html);\n\n // Bold: **text** or __text__\n html = html.replace(/\\*\\*(.+?)\\*\\*/g, \"<strong>$1</strong>\");\n html = html.replace(/__(.+?)__/g, \"<strong>$1</strong>\");\n\n // Italic: *text* or _text_ (but not inside words with underscores)\n html = html.replace(/(?<!\\w)\\*([^*]+?)\\*(?!\\w)/g, \"<em>$1</em>\");\n html = html.replace(/(?<!\\w)_([^_]+?)_(?!\\w)/g, \"<em>$1</em>\");\n\n // Links: [text](url)\n html = html.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (_match, label, url) => {\n const visibleLabel = /^https?:\\/\\//i.test(decodeBasicHtmlEntities(label))\n ? escapeHtml(labelForUrl(label))\n : label;\n return `<a href=\"${escapeHtml(\n decodeBasicHtmlEntities(url),\n )}\" style=\"color:#2563eb;text-decoration:underline;\">${visibleLabel}</a>`;\n });\n\n // Inline code: `code`\n html = html.replace(\n /`([^`]+)`/g,\n '<code style=\"background:#f1f5f9;padding:1px 4px;border-radius:3px;font-size:0.9em;\">$1</code>',\n );\n\n // Bare URLs: keep the destination in href but avoid spelling long URLs out.\n html = linkifyBareUrlsInHtml(html);\n\n // Unordered lists: lines starting with \"- \" or \"* \"\n html = html.replace(/^([*-]) (.+)$/gm, \"<li>$2</li>\");\n // Wrap consecutive <li> in <ul>\n html = html.replace(\n /(<li>.*?<\\/li>\\n?)+/g,\n '<ul style=\"margin:8px 0;padding-left:20px;\">$&</ul>',\n );\n\n // Ordered lists: lines starting with \"1. \", \"2. \" etc.\n html = html.replace(/^\\d+\\. (.+)$/gm, \"<li>$1</li>\");\n // Wrap consecutive <li> that aren't in <ul> in <ol>\n html = html.replace(/(?<!<\\/ul>)(<li>.*?<\\/li>\\n?)+/g, (match) => {\n if (match.includes(\"<ul\")) return match;\n return `<ol style=\"margin:8px 0;padding-left:20px;\">${match}</ol>`;\n });\n\n // Headings: # through ###\n html = html.replace(\n /^### (.+)$/gm,\n '<h3 style=\"margin:16px 0 8px;font-size:1.1em;\">$1</h3>',\n );\n html = html.replace(\n /^## (.+)$/gm,\n '<h2 style=\"margin:16px 0 8px;font-size:1.25em;\">$1</h2>',\n );\n html = html.replace(\n /^# (.+)$/gm,\n '<h1 style=\"margin:16px 0 8px;font-size:1.4em;\">$1</h1>',\n );\n\n // Horizontal rules: --- or ***\n html = html.replace(\n /^(-{3,}|\\*{3,})$/gm,\n '<hr style=\"border:none;border-top:1px solid #e2e8f0;margin:16px 0;\">',\n );\n\n // Paragraphs: double newlines\n html = html.replace(/\\n\\n/g, \"</p><p>\");\n // Single newlines → <br>\n html = html.replace(/\\n/g, \"<br>\");\n\n // Wrap in paragraph tags\n html = `<p>${html}</p>`;\n // Clean up empty paragraphs\n html = html.replace(/<p>\\s*<\\/p>/g, \"\");\n\n return html;\n}\n\n/** Wrap body HTML in a minimal email template with inline styles */\nfunction wrapInEmailTemplate(bodyHtml: string): string {\n return `<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n</head>\n<body style=\"margin:0;padding:0;background-color:#ffffff;\">\n<div style=\"max-width:600px;margin:0 auto;padding:20px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.6;color:#1a1a1a;\">\n${bodyHtml}\n</div>\n</body>\n</html>`;\n}\n\n// ---------------------------------------------------------------------------\n// Raw body reader (matches Slack adapter pattern)\n// ---------------------------------------------------------------------------\n\n/**\n * Read the raw request body as a string and cache on the event context.\n * Reads raw bytes from the request stream — never re-stringifies a parsed\n * body, since the Resend / Svix HMAC is computed over the exact bytes sent\n * (M2 in the webhook security audit).\n */\nasync function readRawBody(event: H3Event): Promise<string> {\n const cached = event.context.__rawBody;\n if (typeof cached === \"string\") return cached;\n const raw = (await h3ReadRawBody(event)) ?? \"\";\n event.context.__rawBody = raw;\n return raw;\n}\n"]}
1
+ {"version":3,"file":"email.js","sourceRoot":"","sources":["../../../src/integrations/adapters/email.ts"],"names":[],"mappings":"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","sourcesContent":["import type { H3Event } from \"h3\";\nimport { getHeader, readRawBody as h3ReadRawBody } from \"h3\";\nimport { timingSafeEqual } from \"node:crypto\";\nimport type {\n PlatformAdapter,\n IncomingMessage,\n OutgoingMessage,\n IntegrationStatus,\n OutboundTarget,\n} from \"../types.js\";\nimport type { EnvKeyConfig } from \"../../server/create-server.js\";\nimport { getIntegrationConfig } from \"../config-store.js\";\nimport { getDbExec } from \"../../db/client.js\";\nimport {\n sendEmail,\n isEmailConfigured,\n getEmailProvider,\n} from \"../../server/email.js\";\n\n/** Max body length before truncation */\nconst EMAIL_MAX_BODY_LENGTH = 15000;\n\n/** Rate limit: max emails per sender within the window */\nconst RATE_LIMIT_MAX = 20;\n/** Rate limit window in ms (1 hour) */\nconst RATE_LIMIT_WINDOW_MS = 60 * 60 * 1000;\n\n/**\n * One-shot warning flags so we don't spam logs on every webhook.\n * Cleared per process — one warning per cold start is enough to surface\n * a misconfiguration without leaking config status to anyone with log access\n * (M6 in the webhook security audit).\n */\nlet _resendUnverifiedWarned = false;\nlet _sendgridUnverifiedWarned = false;\n\nfunction escapeLike(value: string): string {\n return value.replace(/([\\\\%_])/g, \"\\\\$1\");\n}\n\n/**\n * Returns true when the deployment is running in production mode and the\n * operator has NOT explicitly opted into accepting unverified webhooks for\n * local testing. In production we MUST refuse webhooks whose signature can't\n * be verified — accepting them with attacker-controlled `from:` addresses\n * lets the dispatch owner-resolution path run as the victim (C1 in the\n * webhook security audit).\n */\nfunction shouldRefuseWhenSecretMissing(): boolean {\n if (process.env.AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS === \"1\") return false;\n return process.env.NODE_ENV === \"production\";\n}\n\n/**\n * Create an Email platform adapter for inbound/outbound email via\n * Resend or SendGrid webhooks.\n *\n * Required env vars:\n * - EMAIL_AGENT_ADDRESS — The email address the agent receives mail at\n *\n * One of these must also be set (checked via isEmailConfigured()):\n * - RESEND_API_KEY — For sending/receiving via Resend\n * - SENDGRID_API_KEY — For sending/receiving via SendGrid\n *\n * Optional:\n * - EMAIL_INBOUND_WEBHOOK_SECRET — Webhook signature verification secret\n */\nexport function emailAdapter(): PlatformAdapter {\n return {\n platform: \"email\",\n label: \"Email\",\n\n getRequiredEnvKeys(): EnvKeyConfig[] {\n return [\n {\n key: \"EMAIL_AGENT_ADDRESS\",\n label: \"Agent Email Address\",\n required: true,\n helpText:\n \"The email address people will use to message your agent (e.g. `agent@yourcompany.com`, or pick from your `<slug>.resend.app` sandbox).\",\n },\n {\n key: \"RESEND_API_KEY\",\n label: \"Resend API Key\",\n required: false,\n helpText:\n \"From resend.com → API keys (starts with `re_`). Either Resend or SendGrid is required for sending and receiving mail.\",\n },\n {\n key: \"SENDGRID_API_KEY\",\n label: \"SendGrid API Key\",\n required: false,\n helpText:\n \"From sendgrid.com → Settings → API Keys (starts with `SG.`). Either Resend or SendGrid is required.\",\n },\n {\n key: \"EMAIL_INBOUND_WEBHOOK_SECRET\",\n label: \"Inbound Webhook Secret\",\n required: false,\n helpText:\n \"Optional. From Resend (Webhooks → Signing Secret, starts with `whsec_`) or your SendGrid Inbound Parse basic-auth password. Used to verify inbound webhooks are real.\",\n },\n ];\n },\n\n async handleVerification(\n _event: H3Event,\n ): Promise<{ handled: boolean; response?: unknown }> {\n // Email webhooks don't need challenge handshakes\n return { handled: false };\n },\n\n async verifyWebhook(event: H3Event): Promise<boolean> {\n const secret = process.env.EMAIL_INBOUND_WEBHOOK_SECRET;\n const provider = getEmailProvider();\n\n if (provider === \"resend\") {\n return verifyResendWebhook(event, secret);\n }\n\n if (provider === \"sendgrid\") {\n return verifySendGridWebhook(event, secret);\n }\n\n // No provider configured — reject\n console.warn(\"[email] No email provider configured, rejecting webhook\");\n return false;\n },\n\n async parseIncomingMessage(\n event: H3Event,\n ): Promise<IncomingMessage | null> {\n const provider = getEmailProvider();\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS?.toLowerCase();\n if (!agentAddress) {\n console.warn(\"[email] EMAIL_AGENT_ADDRESS not configured\");\n return null;\n }\n\n let parsed: ParsedEmail | null = null;\n\n if (provider === \"resend\") {\n parsed = await parseResendWebhook(event);\n } else if (provider === \"sendgrid\") {\n parsed = await parseSendGridWebhook(event);\n }\n\n if (!parsed) return null;\n\n // Rate limiting (SQL-backed heuristic — counts the sender's already-queued\n // tasks within the last hour). The previous in-memory map reset on every\n // serverless cold start, so the actual ceiling per attacker was\n // RATE_LIMIT_MAX × number_of_active_instances. SQL-backed counting holds\n // across instances. See H4 in the webhook security audit.\n const senderEmail = parsed.from.email.toLowerCase();\n if (await isRateLimited(senderEmail)) {\n console.warn(\n `[email] Rate limited sender: ${senderEmail} (>${RATE_LIMIT_MAX}/hr)`,\n );\n return null;\n }\n\n // Check allowed domains\n const config = await getIntegrationConfig(\"email\");\n if (config?.configData?.allowedDomains) {\n const allowed = config.configData.allowedDomains as string[];\n if (allowed.length > 0) {\n const senderDomain = senderEmail.split(\"@\")[1];\n if (!senderDomain || !allowed.includes(senderDomain)) {\n console.warn(\n `[email] Rejected email from ${senderEmail}: domain not in allowedDomains`,\n );\n return null;\n }\n }\n }\n\n // Determine if agent was CC'd (not in To, but in CC)\n const toAddresses = parsed.to.map((a) => a.toLowerCase());\n const ccAddresses = (parsed.cc ?? []).map((a) => a.toLowerCase());\n const isCC =\n !toAddresses.includes(agentAddress) &&\n ccAddresses.includes(agentAddress);\n\n // Build thread ID from References chain (Gmail-style: oldest Message-ID is thread root).\n // Scope the thread root by sender so an attacker who can forge a `References:`\n // header pointing at someone else's thread root can't graft into that thread.\n // Without this scoping, a third party could craft an inbound email whose\n // References chain matches a known victim's Message-ID and inject messages into\n // the victim's existing conversation — leaking prior content via the agent's\n // reply (M1 in the webhooks security audit).\n const threadRootId = scopeThreadIdToSender(\n getThreadRootId(parsed.messageId, parsed.references),\n senderEmail,\n );\n\n // Build body text\n let bodyText = parsed.text || stripHtmlForPlainText(parsed.html || \"\");\n\n // Truncate if needed\n if (bodyText.length > EMAIL_MAX_BODY_LENGTH) {\n bodyText =\n bodyText.slice(0, EMAIL_MAX_BODY_LENGTH) + \"\\n[Message truncated]\";\n }\n\n // Prefix CC'd emails with context\n if (isCC) {\n const otherRecipients = toAddresses\n .filter((a) => a !== agentAddress)\n .join(\", \");\n bodyText =\n `[CC'd on email between ${senderEmail} and ${otherRecipients || \"others\"}]\\n` +\n `Subject: ${parsed.subject}\\n\\n` +\n bodyText;\n }\n\n return {\n platform: \"email\",\n externalThreadId: threadRootId,\n text: bodyText,\n senderName: parsed.from.name,\n senderId: senderEmail,\n // Carry the message-authentication verdict downstream. Owner\n // resolution (dispatch) must NOT grant a real user's identity /\n // credentials unless the sender is verified — an unverified or\n // spoofed `From:` falls back to a synthetic, credential-less owner.\n senderVerified: parsed.senderVerified,\n platformContext: {\n messageId: parsed.messageId,\n subject: parsed.subject,\n from: senderEmail,\n to: parsed.to,\n cc: parsed.cc,\n inReplyTo: parsed.inReplyTo,\n references: parsed.references,\n isCC,\n senderVerified: parsed.senderVerified,\n },\n timestamp: parsed.date ? new Date(parsed.date).getTime() : Date.now(),\n };\n },\n\n async sendResponse(\n message: OutgoingMessage,\n context: IncomingMessage,\n ): Promise<void> {\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS;\n if (!agentAddress) {\n console.error(\"[email] EMAIL_AGENT_ADDRESS not configured\");\n return;\n }\n\n const config = await getIntegrationConfig(\"email\");\n const displayName =\n (config?.configData?.displayName as string) || \"Dispatch Agent\";\n\n // EMAIL_FROM overrides the from-address — required when the receiving\n // address is on a sub-domain that can't be a verified sender (e.g.\n // *.resend.app). Inbound and outbound addresses can differ.\n const fromAddress = process.env.EMAIL_FROM\n ? process.env.EMAIL_FROM\n : `${displayName} <${agentAddress}>`;\n\n const subject = context.platformContext.subject as string;\n const reSubject = subject.startsWith(\"Re: \") ? subject : `Re: ${subject}`;\n\n try {\n await sendEmail({\n to: context.senderId!,\n from: fromAddress,\n subject: reSubject,\n html: message.text,\n text: stripHtmlForPlainText(message.text),\n inReplyTo: context.platformContext.messageId as string,\n references: buildReferencesHeader(context.platformContext),\n cc: context.platformContext.isCC\n ? buildReplyAllCc(context)\n : undefined,\n });\n } catch (err) {\n console.error(\"[email] Failed to send response:\", err);\n }\n },\n\n async sendMessageToTarget(\n message: OutgoingMessage,\n target: OutboundTarget,\n ): Promise<void> {\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS;\n if (!agentAddress) {\n console.error(\"[email] EMAIL_AGENT_ADDRESS not configured\");\n return;\n }\n\n const config = await getIntegrationConfig(\"email\");\n const displayName =\n (config?.configData?.displayName as string) || \"Dispatch Agent\";\n\n try {\n await sendEmail({\n to: target.destination,\n from: `${displayName} <${agentAddress}>`,\n subject: target.label || \"Message from Dispatch Agent\",\n html: message.text,\n text: stripHtmlForPlainText(message.text),\n ...(target.threadRef\n ? {\n inReplyTo: target.threadRef,\n references: target.threadRef,\n }\n : {}),\n });\n } catch (err) {\n console.error(\"[email] Failed to send proactive message:\", err);\n throw err;\n }\n },\n\n formatAgentResponse(text: string): OutgoingMessage {\n const bodyHtml = markdownToHtml(text);\n const html = wrapInEmailTemplate(bodyHtml);\n return { text: html, platformContext: {} };\n },\n\n async getStatus(_baseUrl?: string): Promise<IntegrationStatus> {\n const hasAgentAddress = !!process.env.EMAIL_AGENT_ADDRESS;\n const hasEmailProvider = isEmailConfigured();\n const hasWebhookSecret = !!process.env.EMAIL_INBOUND_WEBHOOK_SECRET;\n const configured = hasAgentAddress && hasEmailProvider;\n\n return {\n platform: \"email\",\n label: \"Email\",\n enabled: false, // overridden by plugin\n configured,\n details: {\n hasAgentAddress,\n hasEmailProvider,\n hasWebhookSecret,\n provider: getEmailProvider(),\n },\n error: !configured\n ? \"Set EMAIL_AGENT_ADDRESS and either RESEND_API_KEY or SENDGRID_API_KEY\"\n : undefined,\n };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Parsed email shape\n// ---------------------------------------------------------------------------\n\ninterface ParsedEmail {\n messageId: string;\n subject: string;\n from: { name?: string; email: string };\n to: string[];\n cc?: string[];\n text?: string;\n html?: string;\n inReplyTo?: string;\n references?: string[];\n date?: string;\n /**\n * True when the provider's message-authentication results show that the\n * mail genuinely originated from the From domain: DKIM `pass` aligned with\n * the From domain, or an aligned SPF `pass`. False when results are absent\n * or fail — we fail closed so a spoofed `From:` can never be treated as\n * verified. See FINDING 3 (inbound-email impersonation) in the webhook\n * security audit.\n */\n senderVerified: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Webhook verification\n// ---------------------------------------------------------------------------\n\nasync function verifyResendWebhook(\n event: H3Event,\n secret?: string,\n): Promise<boolean> {\n if (!secret) {\n if (shouldRefuseWhenSecretMissing()) {\n if (!_resendUnverifiedWarned) {\n _resendUnverifiedWarned = true;\n console.error(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — refusing Resend webhook in production. \" +\n \"Set EMAIL_INBOUND_WEBHOOK_SECRET, or set AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS=1 for local testing only.\",\n );\n }\n return false;\n }\n if (!_resendUnverifiedWarned) {\n _resendUnverifiedWarned = true;\n console.warn(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — accepting Resend webhook without verification (dev mode)\",\n );\n }\n return true;\n }\n\n const svixId = getHeader(event, \"svix-id\");\n const svixTimestamp = getHeader(event, \"svix-timestamp\");\n const svixSignature = getHeader(event, \"svix-signature\");\n\n if (!svixId || !svixTimestamp || !svixSignature) {\n console.warn(\"[email] Missing Svix signature headers\");\n return false;\n }\n\n // Reject requests older than 5 minutes (replay protection)\n const ts = parseInt(svixTimestamp, 10);\n if (Math.abs(Date.now() / 1000 - ts) > 300) {\n console.warn(\"[email] Svix timestamp too old, rejecting\");\n return false;\n }\n\n const body = await readRawBody(event);\n const crypto = await import(\"node:crypto\");\n\n // Svix signing secret may be prefixed with \"whsec_\"\n const rawSecret = secret.startsWith(\"whsec_\") ? secret.slice(6) : secret;\n const secretBytes = Buffer.from(rawSecret, \"base64\");\n\n const signedContent = `${svixId}.${svixTimestamp}.${body}`;\n const expectedSignature = crypto\n .createHmac(\"sha256\", secretBytes)\n .update(signedContent)\n .digest(\"base64\");\n\n // Svix sends multiple signatures separated by spaces, each prefixed with \"v1,\"\n const signatures = svixSignature.split(\" \");\n for (const sig of signatures) {\n const sigValue = sig.startsWith(\"v1,\") ? sig.slice(3) : sig;\n try {\n if (\n crypto.timingSafeEqual(\n Buffer.from(expectedSignature),\n Buffer.from(sigValue),\n )\n ) {\n return true;\n }\n } catch {\n // Length mismatch — try next signature\n }\n }\n\n console.warn(\"[email] Svix signature verification failed\");\n return false;\n}\n\nfunction safeEq(a: string, b: string): boolean {\n const aBuf = Buffer.from(a);\n const bBuf = Buffer.from(b);\n if (aBuf.length !== bBuf.length) return false;\n return timingSafeEqual(aBuf, bBuf);\n}\n\nasync function verifySendGridWebhook(\n event: H3Event,\n secret?: string,\n): Promise<boolean> {\n if (!secret) {\n if (shouldRefuseWhenSecretMissing()) {\n if (!_sendgridUnverifiedWarned) {\n _sendgridUnverifiedWarned = true;\n console.error(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — refusing SendGrid webhook in production. \" +\n \"Set EMAIL_INBOUND_WEBHOOK_SECRET, or set AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS=1 for local testing only.\",\n );\n }\n return false;\n }\n if (!_sendgridUnverifiedWarned) {\n _sendgridUnverifiedWarned = true;\n console.warn(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — accepting SendGrid webhook without verification (dev mode)\",\n );\n }\n return true;\n }\n\n // Check for the secret in a custom header or basic auth\n const authHeader = getHeader(event, \"authorization\");\n if (authHeader) {\n // Basic auth: \"Basic base64(user:pass)\" — secret is the password\n if (authHeader.startsWith(\"Basic \")) {\n const decoded = Buffer.from(authHeader.slice(6), \"base64\").toString();\n const password = decoded.split(\":\")[1];\n if (password !== undefined && safeEq(password, secret)) return true;\n }\n }\n\n // Also check a custom header (common SendGrid Inbound Parse pattern)\n const customSecret = getHeader(event, \"x-webhook-secret\");\n if (customSecret !== undefined && safeEq(customSecret, secret)) return true;\n\n console.warn(\"[email] SendGrid webhook secret verification failed\");\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Inbound email parsing\n// ---------------------------------------------------------------------------\n\nasync function parseResendWebhook(event: H3Event): Promise<ParsedEmail | null> {\n const raw = await readRawBody(event);\n const body = JSON.parse(raw);\n if (!body || body.type !== \"email.received\") return null;\n\n const data = body.data;\n if (!data) return null;\n\n // Resend webhook payload provides email metadata directly in data\n // Fields: from, to, cc, subject, text, html, headers, created_at\n const fromRaw = data.from as string | undefined;\n const from = fromRaw ? parseEmailAddress(fromRaw) : null;\n if (!from) return null;\n\n const toRaw = data.to as string | string[] | undefined;\n const to = normalizeAddressList(toRaw);\n const ccRaw = data.cc as string | string[] | undefined;\n const cc = normalizeAddressList(ccRaw);\n\n // Parse headers for Message-ID, In-Reply-To, References\n const headers = parseHeadersObject(data.headers);\n const messageId =\n headers[\"message-id\"] || data.email_id || `resend-${Date.now()}`;\n\n // Resend forwards the raw `Authentication-Results` header (and may also\n // surface explicit `dkim`/`spf` fields). Derive a verified verdict from\n // whichever is present; absent results fail closed (unverified).\n const senderVerified = computeSenderVerified({\n fromEmail: from.email,\n authResults: headers[\"authentication-results\"],\n dkim: typeof data.dkim === \"string\" ? data.dkim : undefined,\n spf: typeof data.spf === \"string\" ? data.spf : undefined,\n });\n\n return {\n messageId,\n subject: (data.subject as string) || \"(no subject)\",\n from,\n to,\n cc: cc.length > 0 ? cc : undefined,\n text: data.text as string | undefined,\n html: data.html as string | undefined,\n inReplyTo: headers[\"in-reply-to\"] || undefined,\n references: parseReferencesHeader(headers[\"references\"]),\n date: (data.created_at as string) || undefined,\n senderVerified,\n };\n}\n\nasync function parseSendGridWebhook(\n event: H3Event,\n): Promise<ParsedEmail | null> {\n const raw = await readRawBody(event);\n const body = JSON.parse(raw);\n if (!body) return null;\n\n // SendGrid Inbound Parse sends form data with fields:\n // from, to, cc, subject, text, html, headers, envelope\n const fromRaw = body.from as string | undefined;\n const from = fromRaw ? parseEmailAddress(fromRaw) : null;\n if (!from) return null;\n\n const toRaw = body.to as string | undefined;\n const to = toRaw ? toRaw.split(\",\").map((a: string) => a.trim()) : [];\n const ccRaw = body.cc as string | undefined;\n const cc = ccRaw ? ccRaw.split(\",\").map((a: string) => a.trim()) : [];\n\n // Parse raw headers string\n const headersStr = body.headers as string | undefined;\n const headers = parseHeadersString(headersStr);\n const messageId = headers[\"message-id\"] || `sendgrid-${Date.now()}`;\n\n // SendGrid Inbound Parse posts explicit `dkim` (e.g. `{@example.com : pass}`)\n // and `SPF` (e.g. `pass`) form fields, and also carries\n // `Authentication-Results` inside the raw headers blob. Use all available\n // signals; absent results fail closed (unverified).\n const senderVerified = computeSenderVerified({\n fromEmail: from.email,\n authResults: headers[\"authentication-results\"],\n dkim: typeof body.dkim === \"string\" ? body.dkim : undefined,\n spf: typeof body.SPF === \"string\" ? body.SPF : undefined,\n });\n\n return {\n messageId,\n subject: (body.subject as string) || \"(no subject)\",\n from,\n to,\n cc: cc.length > 0 ? cc : undefined,\n text: body.text as string | undefined,\n html: body.html as string | undefined,\n inReplyTo: headers[\"in-reply-to\"] || undefined,\n references: parseReferencesHeader(headers[\"references\"]),\n date: headers[\"date\"] || undefined,\n senderVerified,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — sender authentication (DKIM / SPF)\n// ---------------------------------------------------------------------------\n\n/**\n * Extract the registrable-ish domain from an email address (lowercased).\n * We keep the full host rather than collapsing to an eTLD+1 — exact-domain\n * alignment is the conservative choice here, and avoids bundling a public\n * suffix list. Subdomain senders that legitimately DKIM-sign with the parent\n * domain are handled by the suffix check in `domainsAlign`.\n */\nfunction emailDomain(email: string): string {\n const at = email.lastIndexOf(\"@\");\n return at >= 0\n ? email\n .slice(at + 1)\n .trim()\n .toLowerCase()\n : \"\";\n}\n\n/**\n * True when `signingDomain` is the From domain or a parent of it (e.g.\n * From `user@mail.example.com` aligned with a `d=example.com` signature).\n * Both directions of subdomain nesting are accepted because senders sign\n * with either the exact From host or the organizational parent.\n */\nfunction domainsAlign(fromDomain: string, signingDomain: string): boolean {\n if (!fromDomain || !signingDomain) return false;\n if (fromDomain === signingDomain) return true;\n return (\n fromDomain.endsWith(`.${signingDomain}`) ||\n signingDomain.endsWith(`.${fromDomain}`)\n );\n}\n\n/**\n * Compute whether an inbound email is authenticated as genuinely coming from\n * its `From:` domain. Returns true only when DKIM passes for an aligned\n * domain, or SPF passes for an aligned domain. Anything else — missing\n * results, `fail`, `softfail`, `none`, `neutral`, `temperror`, `permerror`\n * — returns false (fail closed).\n *\n * Inputs may come from provider-specific fields (`dkim`, `spf`) and/or the\n * RFC 8601 `Authentication-Results` header, in any combination. We treat the\n * union: if ANY source shows an aligned pass, the sender is verified.\n */\nfunction computeSenderVerified(input: {\n fromEmail: string;\n authResults?: string;\n dkim?: string;\n spf?: string;\n}): boolean {\n const fromDomain = emailDomain(input.fromEmail);\n if (!fromDomain) return false;\n\n // 1. Provider DKIM field, e.g. SendGrid `{@example.com : pass}` or\n // `{@example.com : pass; @other.com : fail}`.\n if (input.dkim) {\n const dkimEntries = input.dkim.matchAll(\n /@([a-z0-9.-]+)\\s*:\\s*(pass|fail|none|neutral|softfail|temperror|permerror)/gi,\n );\n for (const m of dkimEntries) {\n const domain = m[1].toLowerCase();\n const verdict = m[2].toLowerCase();\n if (verdict === \"pass\" && domainsAlign(fromDomain, domain)) return true;\n }\n }\n\n // 2. Provider SPF field. SendGrid posts a bare verdict (e.g. `pass`); since\n // SPF authenticates the envelope/MailFrom rather than the header From,\n // a bare `pass` with no domain only counts when we can't tell it's\n // misaligned. We accept a bare `pass` as an aligned SPF pass — this is\n // the same trust level Gmail-style routing assigns to a plain SPF pass.\n if (input.spf) {\n const spfVerdict = input.spf.trim().toLowerCase();\n if (spfVerdict === \"pass\") return true;\n }\n\n // 3. RFC 8601 `Authentication-Results` header (may list multiple methods).\n if (input.authResults) {\n const ar = input.authResults.toLowerCase();\n // DKIM with an aligned domain.\n const dkimRe = /dkim=pass[^;]*?(?:header\\.(?:d|i)=|@)([a-z0-9.-]+)/g;\n for (const m of ar.matchAll(dkimRe)) {\n const domain = m[1].replace(/^@/, \"\");\n if (domainsAlign(fromDomain, domain)) return true;\n }\n // SPF pass (envelope auth) — accept as an aligned pass.\n if (/spf=pass\\b/.test(ar)) return true;\n }\n\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Rate limiting\n// ---------------------------------------------------------------------------\n\n/**\n * Rate-limit heuristic backed by the `integration_pending_tasks` queue.\n *\n * Counts how many tasks this sender has produced in the last hour. The count\n * INCLUDES tasks already processed (status = completed/failed) because the\n * rows aren't deleted on completion — that's enough signal to throttle a\n * single noisy/abusive sender without needing a dedicated counter table.\n *\n * Two trade-offs worth knowing:\n * - This is a coarse heuristic, not exact metering. Within one hour the\n * count is correct; rows produced more than an hour ago naturally drop\n * off. We don't try to be precise, only to raise the bar past the\n * \"send 10K emails through one Lambda burst\" failure mode.\n * - The query relies on the `idx_pending_tasks_status_created` index plus\n * a sender substring match. A targeted attacker could amortise the cost\n * by reusing one sender address — that's fine, the goal here is to bound\n * the attack within a single attacker identity, not to detect spoofing.\n *\n * If the table doesn't yet exist on this deployment (no inbound webhook has\n * been processed before), we silently allow the message — the schema is\n * provisioned on first task insert. See H4 in the webhook security audit.\n */\nasync function isRateLimited(senderEmail: string): Promise<boolean> {\n const cutoff = Date.now() - RATE_LIMIT_WINDOW_MS;\n try {\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `\n SELECT COUNT(*) AS c\n FROM integration_pending_tasks\n WHERE platform = ?\n AND created_at >= ?\n AND payload LIKE ? ESCAPE '\\\\'\n `,\n args: [\"email\", cutoff, `%\"senderId\":\"${escapeLike(senderEmail)}\"%`],\n });\n const count = Number(\n (rows[0] as Record<string, unknown> | undefined)?.c ?? 0,\n );\n return count >= RATE_LIMIT_MAX;\n } catch {\n // Table doesn't exist yet (first webhook on a fresh deployment) — allow.\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — email address parsing\n// ---------------------------------------------------------------------------\n\n/** Parse \"Name <addr@example.com>\" or plain \"addr@example.com\" */\nfunction parseEmailAddress(raw: string): { name?: string; email: string } {\n const match = raw.match(/^\\s*(.*?)\\s*<([^>]+)>\\s*$/);\n if (match && match[2]) {\n return {\n name: match[1].replace(/^[\"']|[\"']$/g, \"\").trim() || undefined,\n email: match[2].trim(),\n };\n }\n return { email: raw.trim() };\n}\n\n/** Normalize a to/cc field that may be a string, array, or undefined into a string[] of addresses */\nfunction normalizeAddressList(raw: string | string[] | undefined): string[] {\n if (!raw) return [];\n if (Array.isArray(raw)) return raw.map((a) => a.trim());\n return raw.split(\",\").map((a) => a.trim());\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — header parsing\n// ---------------------------------------------------------------------------\n\n/** Parse a headers object (Resend format: array of {name, value} or Record) */\nfunction parseHeadersObject(headers: unknown): Record<string, string> {\n const result: Record<string, string> = {};\n if (!headers) return result;\n\n if (Array.isArray(headers)) {\n for (const h of headers) {\n if (h && typeof h === \"object\" && \"name\" in h && \"value\" in h) {\n result[(h.name as string).toLowerCase()] = h.value as string;\n }\n }\n } else if (typeof headers === \"object\") {\n for (const [key, value] of Object.entries(\n headers as Record<string, unknown>,\n )) {\n result[key.toLowerCase()] = String(value);\n }\n }\n return result;\n}\n\n/** Parse a raw headers string (SendGrid format: \"Key: Value\\nKey: Value\\n...\") */\nfunction parseHeadersString(raw: string | undefined): Record<string, string> {\n const result: Record<string, string> = {};\n if (!raw) return result;\n\n const lines = raw.split(/\\r?\\n/);\n let currentKey = \"\";\n let currentValue = \"\";\n\n for (const line of lines) {\n // Continuation line (starts with whitespace)\n if (/^\\s/.test(line) && currentKey) {\n currentValue += \" \" + line.trim();\n continue;\n }\n // Save previous header\n if (currentKey) {\n result[currentKey.toLowerCase()] = currentValue;\n }\n const colonIdx = line.indexOf(\":\");\n if (colonIdx > 0) {\n currentKey = line.slice(0, colonIdx).trim();\n currentValue = line.slice(colonIdx + 1).trim();\n } else {\n currentKey = \"\";\n currentValue = \"\";\n }\n }\n // Save last header\n if (currentKey) {\n result[currentKey.toLowerCase()] = currentValue;\n }\n return result;\n}\n\n/** Parse a References header value into an array of Message-IDs */\nfunction parseReferencesHeader(\n references: string | undefined,\n): string[] | undefined {\n if (!references) return undefined;\n const ids = references.match(/<[^>]+>/g);\n return ids && ids.length > 0 ? ids : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — threading\n// ---------------------------------------------------------------------------\n\n/**\n * Get the thread root ID using a Gmail-style approach:\n * the oldest Message-ID from the References chain is the thread root.\n * If no References, use the current Message-ID.\n */\nfunction getThreadRootId(messageId: string, references?: string[]): string {\n if (references && references.length > 0) {\n return references[0];\n }\n return messageId;\n}\n\n/**\n * Scope a raw thread root id by the sender's email address. Two different\n * senders crafting the same `References:` header value should NOT collide\n * onto the same internal thread mapping — that's the email-side fix for the\n * thread-injection finding (M1 in the webhook security audit).\n *\n * The returned id is opaque to callers and stays stable across messages\n * from the same sender on the same conversation thread, so reply behaviour\n * is unchanged.\n */\nfunction scopeThreadIdToSender(\n rawThreadId: string,\n senderEmail: string,\n): string {\n return `${senderEmail.toLowerCase()}::${rawThreadId}`;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — reply building\n// ---------------------------------------------------------------------------\n\n/** Build a References header from the platform context */\nfunction buildReferencesHeader(ctx: Record<string, unknown>): string {\n const parts: string[] = [];\n\n // Include existing references\n const refs = ctx.references as string[] | undefined;\n if (refs) {\n parts.push(...refs);\n }\n\n // Append the current message ID\n const messageId = ctx.messageId as string | undefined;\n if (messageId) {\n // Avoid duplicates\n if (!parts.includes(messageId)) {\n parts.push(messageId);\n }\n }\n\n return parts.join(\" \");\n}\n\n/**\n * Build CC list for reply-all when agent was CC'd.\n * Include original To addresses and other CC addresses, excluding the agent and the original sender.\n */\nfunction buildReplyAllCc(context: IncomingMessage): string[] | undefined {\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS?.toLowerCase();\n const senderEmail = context.senderId?.toLowerCase();\n const toAddresses = (context.platformContext.to as string[]) || [];\n const ccAddresses = (context.platformContext.cc as string[]) || [];\n\n const allRecipients = new Set<string>();\n for (const addr of [...toAddresses, ...ccAddresses]) {\n const normalized = addr.toLowerCase().trim();\n // Exclude agent address and original sender (sender goes in To)\n if (normalized !== agentAddress && normalized !== senderEmail) {\n allRecipients.add(normalized);\n }\n }\n\n return allRecipients.size > 0 ? Array.from(allRecipients) : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — text conversion\n// ---------------------------------------------------------------------------\n\n/** Strip HTML tags for a plain-text version of the email */\nfunction stripHtmlForPlainText(html: string): string {\n return html\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<\\/p>/gi, \"\\n\\n\")\n .replace(/<\\/div>/gi, \"\\n\")\n .replace(/<\\/li>/gi, \"\\n\")\n .replace(/<li[^>]*>/gi, \"- \")\n .replace(/<\\/h[1-6]>/gi, \"\\n\\n\")\n .replace(/<[^>]+>/g, \"\")\n .replace(/&nbsp;/g, \" \")\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim();\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction decodeBasicHtmlEntities(s: string): string {\n return s\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\");\n}\n\nfunction splitTrailingUrlPunctuation(raw: string): {\n url: string;\n trailing: string;\n} {\n let url = raw;\n let trailing = \"\";\n const trailingEntities = [\"&quot;\", \"&#39;\"];\n\n for (;;) {\n const entity = trailingEntities.find((candidate) =>\n url.endsWith(candidate),\n );\n if (!entity) break;\n url = url.slice(0, -entity.length);\n trailing = entity + trailing;\n }\n\n while (/[.,!?;:]$/.test(url)) {\n trailing = url.slice(-1) + trailing;\n url = url.slice(0, -1);\n }\n\n while (url.endsWith(\")\") && !url.includes(\"(\")) {\n trailing = \")\" + trailing;\n url = url.slice(0, -1);\n }\n\n return { url, trailing };\n}\n\nfunction labelForUrl(rawUrl: string): string {\n try {\n const parsed = new URL(decodeBasicHtmlEntities(rawUrl));\n const host = parsed.hostname.replace(/^www\\./, \"\");\n return host ? `Open ${host}` : \"Open link\";\n } catch {\n return \"Open link\";\n }\n}\n\nfunction linkifyTextSegment(segment: string): string {\n return segment.replace(/\\bhttps?:\\/\\/[^\\s<>\"']+/gi, (raw) => {\n const { url, trailing } = splitTrailingUrlPunctuation(raw);\n const href = decodeBasicHtmlEntities(url);\n return `<a href=\"${escapeHtml(href)}\" style=\"color:#2563eb;text-decoration:underline;\">${escapeHtml(\n labelForUrl(url),\n )}</a>${trailing}`;\n });\n}\n\nfunction linkifyBareUrlsInHtml(html: string): string {\n const parts = html.split(/(<\\/?[^>]+>)/g);\n let skipDepth = 0;\n\n return parts\n .map((part) => {\n if (part.startsWith(\"<\") && part.endsWith(\">\")) {\n if (/^<\\/\\s*(a|code)\\b/i.test(part)) {\n skipDepth = Math.max(0, skipDepth - 1);\n } else if (/^<\\s*(a|code)\\b/i.test(part)) {\n skipDepth += 1;\n }\n return part;\n }\n return skipDepth > 0 ? part : linkifyTextSegment(part);\n })\n .join(\"\");\n}\n\n/** Convert basic markdown to HTML for email rendering */\nfunction markdownToHtml(md: string): string {\n let html = md;\n\n // Escape HTML entities in the source (but not our generated tags)\n html = escapeHtml(html);\n\n // Bold: **text** or __text__\n html = html.replace(/\\*\\*(.+?)\\*\\*/g, \"<strong>$1</strong>\");\n html = html.replace(/__(.+?)__/g, \"<strong>$1</strong>\");\n\n // Italic: *text* or _text_ (but not inside words with underscores)\n html = html.replace(/(?<!\\w)\\*([^*]+?)\\*(?!\\w)/g, \"<em>$1</em>\");\n html = html.replace(/(?<!\\w)_([^_]+?)_(?!\\w)/g, \"<em>$1</em>\");\n\n // Links: [text](url)\n html = html.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (_match, label, url) => {\n const visibleLabel = /^https?:\\/\\//i.test(decodeBasicHtmlEntities(label))\n ? escapeHtml(labelForUrl(label))\n : label;\n return `<a href=\"${escapeHtml(\n decodeBasicHtmlEntities(url),\n )}\" style=\"color:#2563eb;text-decoration:underline;\">${visibleLabel}</a>`;\n });\n\n // Inline code: `code`\n html = html.replace(\n /`([^`]+)`/g,\n '<code style=\"background:#f1f5f9;padding:1px 4px;border-radius:3px;font-size:0.9em;\">$1</code>',\n );\n\n // Bare URLs: keep the destination in href but avoid spelling long URLs out.\n html = linkifyBareUrlsInHtml(html);\n\n // Unordered lists: lines starting with \"- \" or \"* \"\n html = html.replace(/^([*-]) (.+)$/gm, \"<li>$2</li>\");\n // Wrap consecutive <li> in <ul>\n html = html.replace(\n /(<li>.*?<\\/li>\\n?)+/g,\n '<ul style=\"margin:8px 0;padding-left:20px;\">$&</ul>',\n );\n\n // Ordered lists: lines starting with \"1. \", \"2. \" etc.\n html = html.replace(/^\\d+\\. (.+)$/gm, \"<li>$1</li>\");\n // Wrap consecutive <li> that aren't in <ul> in <ol>\n html = html.replace(/(?<!<\\/ul>)(<li>.*?<\\/li>\\n?)+/g, (match) => {\n if (match.includes(\"<ul\")) return match;\n return `<ol style=\"margin:8px 0;padding-left:20px;\">${match}</ol>`;\n });\n\n // Headings: # through ###\n html = html.replace(\n /^### (.+)$/gm,\n '<h3 style=\"margin:16px 0 8px;font-size:1.1em;\">$1</h3>',\n );\n html = html.replace(\n /^## (.+)$/gm,\n '<h2 style=\"margin:16px 0 8px;font-size:1.25em;\">$1</h2>',\n );\n html = html.replace(\n /^# (.+)$/gm,\n '<h1 style=\"margin:16px 0 8px;font-size:1.4em;\">$1</h1>',\n );\n\n // Horizontal rules: --- or ***\n html = html.replace(\n /^(-{3,}|\\*{3,})$/gm,\n '<hr style=\"border:none;border-top:1px solid #e2e8f0;margin:16px 0;\">',\n );\n\n // Paragraphs: double newlines\n html = html.replace(/\\n\\n/g, \"</p><p>\");\n // Single newlines → <br>\n html = html.replace(/\\n/g, \"<br>\");\n\n // Wrap in paragraph tags\n html = `<p>${html}</p>`;\n // Clean up empty paragraphs\n html = html.replace(/<p>\\s*<\\/p>/g, \"\");\n\n return html;\n}\n\n/** Wrap body HTML in a minimal email template with inline styles */\nfunction wrapInEmailTemplate(bodyHtml: string): string {\n return `<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n</head>\n<body style=\"margin:0;padding:0;background-color:#ffffff;\">\n<div style=\"max-width:600px;margin:0 auto;padding:20px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.6;color:#1a1a1a;\">\n${bodyHtml}\n</div>\n</body>\n</html>`;\n}\n\n// ---------------------------------------------------------------------------\n// Raw body reader (matches Slack adapter pattern)\n// ---------------------------------------------------------------------------\n\n/**\n * Read the raw request body as a string and cache on the event context.\n * Reads raw bytes from the request stream — never re-stringifies a parsed\n * body, since the Resend / Svix HMAC is computed over the exact bytes sent\n * (M2 in the webhook security audit).\n */\nasync function readRawBody(event: H3Event): Promise<string> {\n const cached = event.context.__rawBody;\n if (typeof cached === \"string\") return cached;\n const raw = (await h3ReadRawBody(event)) ?? \"\";\n event.context.__rawBody = raw;\n return raw;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"google-docs-poller.d.ts","sourceRoot":"","sources":["../../src/integrations/google-docs-poller.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAC;AAsBtC,MAAM,WAAW,uBAAuB;IACtC,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrC,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAWD;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAqExE;AAiMD;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAmCf;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAa5D;AA+JD;;;;;;;;;;GAUG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAmCf;AAgCD;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAW1D"}
1
+ {"version":3,"file":"google-docs-poller.d.ts","sourceRoot":"","sources":["../../src/integrations/google-docs-poller.ts"],"names":[],"mappings":"AAeA,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAC;AAoBtC,MAAM,WAAW,uBAAuB;IACtC,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrC,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAWD;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAqExE;AAiMD;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAmCf;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAa5D;AA+JD;;;;;;;;;;GAUG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAmCf;AAgCD;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAW1D"}
@@ -1,15 +1,13 @@
1
- import { getServiceAccountAccessToken, getServiceAccountEmail, getStartPageToken, listChanges, listDocComments, } from "./adapters/google-docs.js";
1
+ import { getServiceAccountAccessToken, getServiceAccountEmail, getStartPageToken, googleDocsAdapter, listChanges, listDocComments, } from "./adapters/google-docs.js";
2
2
  import { getIntegrationConfig, saveIntegrationConfig } from "./config-store.js";
3
3
  import { getThreadMapping, saveThreadMapping } from "./thread-mapping-store.js";
4
- import { createThread, getThread } from "../chat-threads/store.js";
4
+ import { createThread, getThread, updateThreadData, } from "../chat-threads/store.js";
5
5
  import { runAgentLoop, actionsToEngineTools, } from "../agent/production-agent.js";
6
6
  import { runWithRequestContext } from "../server/request-context.js";
7
7
  import { resolveOrgIdForEmail } from "../org/context.js";
8
8
  import { createAnthropicEngine } from "../agent/engine/index.js";
9
9
  import { startRun } from "../agent/run-manager.js";
10
10
  import { buildAssistantMessage, extractThreadMeta, } from "../agent/thread-data-builder.js";
11
- import { updateThreadData } from "../chat-threads/store.js";
12
- import { googleDocsAdapter } from "./adapters/google-docs.js";
13
11
  const PLATFORM = "google-docs";
14
12
  const DEFAULT_TRIGGER = "@agent";
15
13
  /** Track processed comment IDs to avoid reprocessing */
@@ -1 +1 @@
1
- {"version":3,"file":"google-docs-poller.js","sourceRoot":"","sources":["../../src/integrations/google-docs-poller.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getServiceAccountAccessToken,\n getServiceAccountEmail,\n getStartPageToken,\n listChanges,\n listDocComments,\n} from \"./adapters/google-docs.js\";\nimport { getIntegrationConfig, saveIntegrationConfig } from \"./config-store.js\";\nimport { getThreadMapping, saveThreadMapping } from \"./thread-mapping-store.js\";\nimport { createThread, getThread } from \"../chat-threads/store.js\";\nimport {\n runAgentLoop,\n actionsToEngineTools,\n type ActionEntry,\n} from \"../agent/production-agent.js\";\nimport { runWithRequestContext } from \"../server/request-context.js\";\nimport { resolveOrgIdForEmail } from \"../org/context.js\";\nimport { createAnthropicEngine } from \"../agent/engine/index.js\";\nimport type { EngineMessage } from \"../agent/engine/types.js\";\nimport { startRun, type ActiveRun } from \"../agent/run-manager.js\";\nimport {\n buildAssistantMessage,\n extractThreadMeta,\n} from \"../agent/thread-data-builder.js\";\nimport { updateThreadData } from \"../chat-threads/store.js\";\nimport { googleDocsAdapter } from \"./adapters/google-docs.js\";\nimport type { IncomingMessage } from \"./types.js\";\n\nconst PLATFORM = \"google-docs\";\nconst DEFAULT_TRIGGER = \"@agent\";\n\n/** Track processed comment IDs to avoid reprocessing */\nconst processedComments = new Set<string>();\n/** Track last-checked time per document for comment filtering */\nconst lastCheckedTimes = new Map<string, string>();\n\nexport interface GoogleDocsPollerOptions {\n /** Polling interval in milliseconds (fallback mode). Default: 30000 (30s) */\n intervalMs?: number;\n /** Trigger keyword in comments. Default: \"@agent\" (case-insensitive) */\n triggerKeyword?: string;\n /** System prompt for the agent */\n systemPrompt: string;\n /** Action entries for the agent */\n actions: Record<string, ActionEntry>;\n /** Model to use */\n model: string;\n /** Anthropic API key */\n apiKey: string;\n /** Thread owner email */\n ownerEmail: string;\n /** Webhook URL for push mode (set by plugin from WEBHOOK_BASE_URL) */\n webhookUrl?: string;\n}\n\nlet pollerInterval: ReturnType<typeof setInterval> | null = null;\nlet activeOptions: GoogleDocsPollerOptions | null = null;\n\n// ─── Watch Channel Management ───────────────────────────────────────────────\n\n/** How long a watch channel lasts (Google max is ~24h, we use 23h to renew early) */\nconst WATCH_CHANNEL_TTL_MS = 23 * 60 * 60 * 1000;\nlet watchRenewalTimer: ReturnType<typeof setTimeout> | null = null;\n\n/**\n * Register a Google Drive changes.watch channel so Google pushes\n * notifications to our webhook instead of us polling.\n *\n * Returns true if the watch was registered successfully.\n */\nexport async function registerWatch(webhookUrl: string): Promise<boolean> {\n const accessToken = await getServiceAccountAccessToken();\n if (!accessToken) return false;\n\n // Get the current page token as the starting point\n let pageToken = await getPageToken();\n if (!pageToken) {\n pageToken = await getStartPageToken(accessToken);\n await setPageToken(pageToken);\n }\n\n const channelId = `gdocs-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n const expiration = Date.now() + WATCH_CHANNEL_TTL_MS;\n\n try {\n const res = await fetch(\n \"https://www.googleapis.com/drive/v3/changes/watch\",\n {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n id: channelId,\n type: \"web_hook\",\n address: webhookUrl,\n expiration: expiration,\n payload: true,\n }),\n },\n );\n\n if (!res.ok) {\n const err = await res.text();\n console.error(\"[google-docs] Failed to register watch:\", err);\n return false;\n }\n\n const data = (await res.json()) as {\n id: string;\n resourceId: string;\n expiration: string;\n };\n\n // Save channel info for renewal and stopping\n await saveIntegrationConfig(\n PLATFORM,\n {\n channelId: data.id,\n resourceId: data.resourceId,\n expiration: data.expiration,\n webhookUrl,\n },\n \"watch-channel\",\n );\n\n console.log(\n `[google-docs] Watch registered (channel: ${data.id}, expires: ${new Date(parseInt(data.expiration)).toISOString()})`,\n );\n\n // Schedule renewal before expiration\n scheduleWatchRenewal(webhookUrl);\n\n return true;\n } catch (err) {\n console.error(\"[google-docs] Watch registration error:\", err);\n return false;\n }\n}\n\n/**\n * Stop an existing watch channel.\n */\nasync function stopWatch(): Promise<void> {\n const config = await getIntegrationConfig(PLATFORM, \"watch-channel\");\n if (!config?.configData?.channelId) return;\n\n const accessToken = await getServiceAccountAccessToken();\n if (!accessToken) return;\n\n try {\n await fetch(\"https://www.googleapis.com/drive/v3/channels/stop\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n id: config.configData.channelId,\n resourceId: config.configData.resourceId,\n }),\n });\n } catch {\n // Best effort — channel may have expired already\n }\n\n await saveIntegrationConfig(PLATFORM, {}, \"watch-channel\");\n}\n\n/**\n * Schedule automatic watch renewal before the channel expires.\n */\nfunction scheduleWatchRenewal(webhookUrl: string): void {\n if (watchRenewalTimer) clearTimeout(watchRenewalTimer);\n\n // Renew 1 hour before expiration\n const renewIn = WATCH_CHANNEL_TTL_MS - 60 * 60 * 1000;\n\n watchRenewalTimer = setTimeout(async () => {\n console.log(\"[google-docs] Renewing watch channel...\");\n await stopWatch();\n await registerWatch(webhookUrl);\n }, renewIn);\n}\n\n// ─── Page Token Management ──────────────────────────────────────────────────\n\nasync function getPageToken(): Promise<string | null> {\n const config = await getIntegrationConfig(PLATFORM, \"page-token\");\n return (config?.configData?.pageToken as string) ?? null;\n}\n\nasync function setPageToken(token: string): Promise<void> {\n await saveIntegrationConfig(PLATFORM, { pageToken: token }, \"page-token\");\n}\n\n// ─── Comment Detection ──────────────────────────────────────────────────────\n\nfunction isAgentMention(commentText: string, triggerKeyword: string): boolean {\n return commentText.toLowerCase().includes(triggerKeyword.toLowerCase());\n}\n\nfunction commentKey(fileId: string, commentId: string): string {\n return `${fileId}:${commentId}`;\n}\n\n/**\n * Check a single document for new agent-directed comments.\n */\nasync function checkDocumentComments(\n fileId: string,\n accessToken: string,\n options: GoogleDocsPollerOptions,\n): Promise<void> {\n const triggerKeyword = options.triggerKeyword ?? DEFAULT_TRIGGER;\n const serviceEmail = getServiceAccountEmail();\n\n const lastChecked = lastCheckedTimes.get(fileId);\n const comments = await listDocComments(fileId, accessToken, lastChecked);\n const now = new Date().toISOString();\n\n for (const comment of comments) {\n if (comment.resolved) continue;\n\n const key = commentKey(fileId, comment.id);\n\n // Skip comments authored by the service account\n if (\n serviceEmail &&\n comment.author.emailAddress?.toLowerCase() === serviceEmail.toLowerCase()\n ) {\n continue;\n }\n\n const existingMapping = await getThreadMapping(PLATFORM, key);\n\n if (existingMapping) {\n // Durable per-reply dedup: the in-memory `processedComments` Set does not\n // survive serverless cold starts (see pending-tasks-store H3 note), which\n // would let already-answered replies be reprocessed and double-posted.\n // Persist processed reply ids in the existing SQL thread mapping instead.\n const persistedReplyIds =\n existingMapping.platformContext.processedReplyIds;\n const processedReplyIds = new Set<string>(\n Array.isArray(persistedReplyIds) ? (persistedReplyIds as string[]) : [],\n );\n\n // Check for new follow-up replies from users\n const newUserReplies = (comment.replies ?? []).filter((r) => {\n if (\n serviceEmail &&\n r.author.emailAddress?.toLowerCase() === serviceEmail.toLowerCase()\n ) {\n return false;\n }\n const replyKey = `${key}:reply:${r.id}`;\n if (processedReplyIds.has(r.id) || processedComments.has(replyKey))\n return false;\n if (!isAgentMention(r.content, triggerKeyword)) return false;\n return true;\n });\n\n for (const reply of newUserReplies) {\n const replyKey = `${key}:reply:${reply.id}`;\n processedComments.add(replyKey);\n processedReplyIds.add(reply.id);\n // Persist immediately so a crash/cold-start between replies cannot\n // re-answer this reply on the next invocation.\n await saveThreadMapping(\n PLATFORM,\n key,\n existingMapping.internalThreadId,\n {\n ...existingMapping.platformContext,\n processedReplyIds: Array.from(processedReplyIds),\n },\n );\n\n const text = reply.content\n .replace(\n new RegExp(\n triggerKeyword.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"),\n \"gi\",\n ),\n \"\",\n )\n .trim();\n\n await processComment(\n fileId,\n comment.id,\n text,\n reply.author.displayName,\n options,\n existingMapping.internalThreadId,\n );\n }\n continue;\n }\n\n // New comment — check if it mentions the agent\n if (!isAgentMention(comment.content, triggerKeyword)) continue;\n\n processedComments.add(key);\n\n let text = comment.content;\n if (comment.quotedFileContent?.value) {\n text = `[Highlighted text: \"${comment.quotedFileContent.value}\"]\\n\\n${text}`;\n }\n\n text = text\n .replace(\n new RegExp(triggerKeyword.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"), \"gi\"),\n \"\",\n )\n .trim();\n\n await processComment(\n fileId,\n comment.id,\n text,\n comment.author.displayName,\n options,\n );\n }\n\n lastCheckedTimes.set(fileId, now);\n}\n\n// ─── Process Changes ────────────────────────────────────────────────────────\n\n/**\n * Process pending Drive changes — called by both push notifications and polling.\n * Fetches changes since the last page token, finds Google Docs that changed,\n * and checks their comments for agent mentions.\n */\nexport async function processChanges(\n options: GoogleDocsPollerOptions,\n): Promise<void> {\n const accessToken = await getServiceAccountAccessToken();\n if (!accessToken) return;\n\n let pageToken = await getPageToken();\n if (!pageToken) {\n pageToken = await getStartPageToken(accessToken);\n await setPageToken(pageToken);\n return; // First run — just save the cursor\n }\n\n const { changes, nextPageToken } = await listChanges(pageToken, accessToken);\n await setPageToken(nextPageToken);\n\n if (changes.length === 0) return;\n\n // Deduplicate and filter to Google Docs\n const docFileIds = new Set<string>();\n for (const change of changes) {\n if (change.removed) continue;\n if (\n change.file?.mimeType === \"application/vnd.google-apps.document\" ||\n !change.file?.mimeType\n ) {\n docFileIds.add(change.fileId);\n }\n }\n\n for (const fileId of docFileIds) {\n try {\n await checkDocumentComments(fileId, accessToken, options);\n } catch (err) {\n console.error(`[google-docs] Error checking comments on ${fileId}:`, err);\n }\n }\n}\n\n/**\n * Handle a push notification from Google Drive changes.watch.\n * Called from the integration webhook route.\n */\nexport async function handlePushNotification(): Promise<void> {\n if (!activeOptions) {\n console.warn(\n \"[google-docs] Push notification received but poller not configured\",\n );\n return;\n }\n\n try {\n await processChanges(activeOptions);\n } catch (err) {\n console.error(\"[google-docs] Error processing push notification:\", err);\n }\n}\n\n// ─── Agent Processing ───────────────────────────────────────────────────────\n\nasync function processComment(\n fileId: string,\n commentId: string,\n text: string,\n senderName: string,\n options: GoogleDocsPollerOptions,\n existingThreadId?: string,\n): Promise<void> {\n const adapter = googleDocsAdapter();\n const key = commentKey(fileId, commentId);\n\n const incoming: IncomingMessage = {\n platform: PLATFORM,\n externalThreadId: key,\n text,\n senderName,\n platformContext: { fileId, commentId },\n timestamp: Date.now(),\n };\n\n let threadId = existingThreadId;\n if (!threadId) {\n const thread = await createThread(options.ownerEmail, {\n title: `Google Doc: ${senderName}`,\n });\n await saveThreadMapping(PLATFORM, key, thread.id, { fileId, commentId });\n threadId = thread.id;\n }\n\n const thread = await getThread(threadId);\n const existingMessages: EngineMessage[] = [];\n if (thread?.threadData) {\n try {\n const data = JSON.parse(thread.threadData);\n if (Array.isArray(data.messages)) {\n for (const msg of data.messages) {\n const m = msg.message ?? msg;\n const textContent =\n typeof m.content === \"string\"\n ? m.content\n : Array.isArray(m.content)\n ? m.content\n .filter((c: any) => c.type === \"text\")\n .map((c: any) => c.text)\n .join(\"\\n\")\n : \"\";\n if (m.role === \"user\") {\n existingMessages.push({\n role: \"user\",\n content: [{ type: \"text\", text: textContent }],\n });\n } else if (m.role === \"assistant\") {\n existingMessages.push({\n role: \"assistant\",\n content: [{ type: \"text\", text: textContent }],\n });\n }\n }\n }\n } catch {}\n }\n\n const messages: EngineMessage[] = [\n ...existingMessages,\n { role: \"user\", content: [{ type: \"text\", text }] },\n ];\n\n const engine = createAnthropicEngine({ apiKey: options.apiKey });\n const tools = actionsToEngineTools(options.actions);\n const runId = `gdocs-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n const capturedThreadId = threadId;\n const orgId = (await resolveOrgIdForEmail(options.ownerEmail)) ?? undefined;\n\n startRun(\n runId,\n capturedThreadId,\n async (send, signal) => {\n await runWithRequestContext(\n { userEmail: options.ownerEmail, orgId, isIntegrationCaller: true },\n () =>\n runAgentLoop({\n engine,\n model: options.model,\n systemPrompt: options.systemPrompt,\n tools,\n messages,\n actions: options.actions,\n send,\n signal,\n }),\n );\n },\n async (completedRun: ActiveRun) => {\n try {\n let responseText = \"\";\n for (const runEvent of completedRun.events) {\n if (runEvent.event.type === \"text\") {\n responseText += runEvent.event.text;\n }\n }\n if (!responseText.trim()) responseText = \"(No response)\";\n\n const outgoing = adapter.formatAgentResponse(responseText);\n await adapter.sendResponse(outgoing, incoming);\n await persistThreadData(capturedThreadId, text, completedRun, thread);\n } catch (err) {\n console.error(\"[google-docs] Error sending response:\", err);\n }\n },\n );\n}\n\nasync function persistThreadData(\n threadId: string,\n userText: string,\n completedRun: ActiveRun,\n thread: any,\n): Promise<void> {\n try {\n let repo: any;\n try {\n repo = JSON.parse(thread?.threadData || \"{}\");\n } catch {\n repo = {};\n }\n if (!Array.isArray(repo.messages)) repo.messages = [];\n\n repo.messages.push({\n id: `msg-${Date.now()}-user`,\n role: \"user\",\n content: [{ type: \"text\", text: userText }],\n createdAt: new Date().toISOString(),\n });\n\n const assistantMsg = buildAssistantMessage(\n completedRun.events ?? [],\n completedRun.runId,\n );\n if (assistantMsg) repo.messages.push(assistantMsg);\n\n const meta = extractThreadMeta(repo);\n await updateThreadData(\n threadId,\n JSON.stringify(repo),\n meta.title || thread?.title || \"Google Doc Comment\",\n meta.preview || thread?.preview || \"\",\n repo.messages.length,\n );\n } catch {\n // Best-effort\n }\n}\n\n// ─── Poller (Hybrid: Push Primary, Poll Fallback) ───────────────────────────\n\n/**\n * Start the Google Docs integration.\n *\n * Hybrid approach:\n * 1. Attempts to register a Google Drive changes.watch webhook for\n * near-instant push notifications (~seconds latency)\n * 2. Falls back to polling if the watch registration fails\n * (e.g. domain not verified, local dev)\n * 3. Even in push mode, polls at a slow interval (5min) as a safety net\n * in case a push notification is missed\n */\nexport async function startGoogleDocsPoller(\n options: GoogleDocsPollerOptions,\n): Promise<void> {\n if (pollerInterval) {\n console.warn(\"[google-docs] Already running\");\n return;\n }\n\n activeOptions = options;\n\n // Check if integration is enabled before trying to register watch\n const config = await getIntegrationConfig(PLATFORM);\n if (!config?.configData?.enabled) {\n // Still start the poll loop so it picks up when enabled later\n startPollLoop(options, options.intervalMs ?? 30_000);\n return;\n }\n\n // Try to register push notifications\n const webhookUrl = options.webhookUrl;\n let pushMode = false;\n\n if (webhookUrl) {\n pushMode = await registerWatch(webhookUrl);\n if (pushMode) {\n console.log(\"[google-docs] Push mode active — using Drive webhooks\");\n // In push mode, still poll slowly as a safety net (every 5 min)\n startPollLoop(options, 5 * 60 * 1000);\n }\n }\n\n if (!pushMode) {\n console.log(\n \"[google-docs] Polling mode — push registration failed or no webhook URL\",\n );\n startPollLoop(options, options.intervalMs ?? 30_000);\n }\n}\n\nfunction startPollLoop(\n options: GoogleDocsPollerOptions,\n intervalMs: number,\n): void {\n async function poll() {\n try {\n const config = await getIntegrationConfig(PLATFORM);\n if (!config?.configData?.enabled) return;\n await processChanges(options);\n } catch (err) {\n // Unwrap ErrorEvent (Neon WS driver emits these on network failure) so logs show the real cause\n const detail =\n err instanceof Error\n ? err\n : ((err as any)?.error ?? (err as any)?.message ?? err);\n console.error(\"[google-docs] Poller error:\", detail);\n }\n }\n\n setTimeout(poll, 5000);\n pollerInterval = setInterval(poll, intervalMs);\n\n const email = getServiceAccountEmail();\n if (process.env.DEBUG) {\n console.log(\n `[google-docs] Poll loop started (interval: ${intervalMs / 1000}s, service account: ${email ?? \"not configured\"})`,\n );\n }\n}\n\n/**\n * Stop the Google Docs integration.\n */\nexport async function stopGoogleDocsPoller(): Promise<void> {\n if (pollerInterval) {\n clearInterval(pollerInterval);\n pollerInterval = null;\n }\n if (watchRenewalTimer) {\n clearTimeout(watchRenewalTimer);\n watchRenewalTimer = null;\n }\n await stopWatch();\n activeOptions = null;\n}\n"]}
1
+ {"version":3,"file":"google-docs-poller.js","sourceRoot":"","sources":["../../src/integrations/google-docs-poller.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getServiceAccountAccessToken,\n getServiceAccountEmail,\n getStartPageToken,\n googleDocsAdapter,\n listChanges,\n listDocComments,\n} from \"./adapters/google-docs.js\";\nimport { getIntegrationConfig, saveIntegrationConfig } from \"./config-store.js\";\nimport { getThreadMapping, saveThreadMapping } from \"./thread-mapping-store.js\";\nimport {\n createThread,\n getThread,\n updateThreadData,\n} from \"../chat-threads/store.js\";\nimport {\n runAgentLoop,\n actionsToEngineTools,\n type ActionEntry,\n} from \"../agent/production-agent.js\";\nimport { runWithRequestContext } from \"../server/request-context.js\";\nimport { resolveOrgIdForEmail } from \"../org/context.js\";\nimport { createAnthropicEngine } from \"../agent/engine/index.js\";\nimport type { EngineMessage } from \"../agent/engine/types.js\";\nimport { startRun, type ActiveRun } from \"../agent/run-manager.js\";\nimport {\n buildAssistantMessage,\n extractThreadMeta,\n} from \"../agent/thread-data-builder.js\";\nimport type { IncomingMessage } from \"./types.js\";\n\nconst PLATFORM = \"google-docs\";\nconst DEFAULT_TRIGGER = \"@agent\";\n\n/** Track processed comment IDs to avoid reprocessing */\nconst processedComments = new Set<string>();\n/** Track last-checked time per document for comment filtering */\nconst lastCheckedTimes = new Map<string, string>();\n\nexport interface GoogleDocsPollerOptions {\n /** Polling interval in milliseconds (fallback mode). Default: 30000 (30s) */\n intervalMs?: number;\n /** Trigger keyword in comments. Default: \"@agent\" (case-insensitive) */\n triggerKeyword?: string;\n /** System prompt for the agent */\n systemPrompt: string;\n /** Action entries for the agent */\n actions: Record<string, ActionEntry>;\n /** Model to use */\n model: string;\n /** Anthropic API key */\n apiKey: string;\n /** Thread owner email */\n ownerEmail: string;\n /** Webhook URL for push mode (set by plugin from WEBHOOK_BASE_URL) */\n webhookUrl?: string;\n}\n\nlet pollerInterval: ReturnType<typeof setInterval> | null = null;\nlet activeOptions: GoogleDocsPollerOptions | null = null;\n\n// ─── Watch Channel Management ───────────────────────────────────────────────\n\n/** How long a watch channel lasts (Google max is ~24h, we use 23h to renew early) */\nconst WATCH_CHANNEL_TTL_MS = 23 * 60 * 60 * 1000;\nlet watchRenewalTimer: ReturnType<typeof setTimeout> | null = null;\n\n/**\n * Register a Google Drive changes.watch channel so Google pushes\n * notifications to our webhook instead of us polling.\n *\n * Returns true if the watch was registered successfully.\n */\nexport async function registerWatch(webhookUrl: string): Promise<boolean> {\n const accessToken = await getServiceAccountAccessToken();\n if (!accessToken) return false;\n\n // Get the current page token as the starting point\n let pageToken = await getPageToken();\n if (!pageToken) {\n pageToken = await getStartPageToken(accessToken);\n await setPageToken(pageToken);\n }\n\n const channelId = `gdocs-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n const expiration = Date.now() + WATCH_CHANNEL_TTL_MS;\n\n try {\n const res = await fetch(\n \"https://www.googleapis.com/drive/v3/changes/watch\",\n {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n id: channelId,\n type: \"web_hook\",\n address: webhookUrl,\n expiration: expiration,\n payload: true,\n }),\n },\n );\n\n if (!res.ok) {\n const err = await res.text();\n console.error(\"[google-docs] Failed to register watch:\", err);\n return false;\n }\n\n const data = (await res.json()) as {\n id: string;\n resourceId: string;\n expiration: string;\n };\n\n // Save channel info for renewal and stopping\n await saveIntegrationConfig(\n PLATFORM,\n {\n channelId: data.id,\n resourceId: data.resourceId,\n expiration: data.expiration,\n webhookUrl,\n },\n \"watch-channel\",\n );\n\n console.log(\n `[google-docs] Watch registered (channel: ${data.id}, expires: ${new Date(parseInt(data.expiration)).toISOString()})`,\n );\n\n // Schedule renewal before expiration\n scheduleWatchRenewal(webhookUrl);\n\n return true;\n } catch (err) {\n console.error(\"[google-docs] Watch registration error:\", err);\n return false;\n }\n}\n\n/**\n * Stop an existing watch channel.\n */\nasync function stopWatch(): Promise<void> {\n const config = await getIntegrationConfig(PLATFORM, \"watch-channel\");\n if (!config?.configData?.channelId) return;\n\n const accessToken = await getServiceAccountAccessToken();\n if (!accessToken) return;\n\n try {\n await fetch(\"https://www.googleapis.com/drive/v3/channels/stop\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n id: config.configData.channelId,\n resourceId: config.configData.resourceId,\n }),\n });\n } catch {\n // Best effort — channel may have expired already\n }\n\n await saveIntegrationConfig(PLATFORM, {}, \"watch-channel\");\n}\n\n/**\n * Schedule automatic watch renewal before the channel expires.\n */\nfunction scheduleWatchRenewal(webhookUrl: string): void {\n if (watchRenewalTimer) clearTimeout(watchRenewalTimer);\n\n // Renew 1 hour before expiration\n const renewIn = WATCH_CHANNEL_TTL_MS - 60 * 60 * 1000;\n\n watchRenewalTimer = setTimeout(async () => {\n console.log(\"[google-docs] Renewing watch channel...\");\n await stopWatch();\n await registerWatch(webhookUrl);\n }, renewIn);\n}\n\n// ─── Page Token Management ──────────────────────────────────────────────────\n\nasync function getPageToken(): Promise<string | null> {\n const config = await getIntegrationConfig(PLATFORM, \"page-token\");\n return (config?.configData?.pageToken as string) ?? null;\n}\n\nasync function setPageToken(token: string): Promise<void> {\n await saveIntegrationConfig(PLATFORM, { pageToken: token }, \"page-token\");\n}\n\n// ─── Comment Detection ──────────────────────────────────────────────────────\n\nfunction isAgentMention(commentText: string, triggerKeyword: string): boolean {\n return commentText.toLowerCase().includes(triggerKeyword.toLowerCase());\n}\n\nfunction commentKey(fileId: string, commentId: string): string {\n return `${fileId}:${commentId}`;\n}\n\n/**\n * Check a single document for new agent-directed comments.\n */\nasync function checkDocumentComments(\n fileId: string,\n accessToken: string,\n options: GoogleDocsPollerOptions,\n): Promise<void> {\n const triggerKeyword = options.triggerKeyword ?? DEFAULT_TRIGGER;\n const serviceEmail = getServiceAccountEmail();\n\n const lastChecked = lastCheckedTimes.get(fileId);\n const comments = await listDocComments(fileId, accessToken, lastChecked);\n const now = new Date().toISOString();\n\n for (const comment of comments) {\n if (comment.resolved) continue;\n\n const key = commentKey(fileId, comment.id);\n\n // Skip comments authored by the service account\n if (\n serviceEmail &&\n comment.author.emailAddress?.toLowerCase() === serviceEmail.toLowerCase()\n ) {\n continue;\n }\n\n const existingMapping = await getThreadMapping(PLATFORM, key);\n\n if (existingMapping) {\n // Durable per-reply dedup: the in-memory `processedComments` Set does not\n // survive serverless cold starts (see pending-tasks-store H3 note), which\n // would let already-answered replies be reprocessed and double-posted.\n // Persist processed reply ids in the existing SQL thread mapping instead.\n const persistedReplyIds =\n existingMapping.platformContext.processedReplyIds;\n const processedReplyIds = new Set<string>(\n Array.isArray(persistedReplyIds) ? (persistedReplyIds as string[]) : [],\n );\n\n // Check for new follow-up replies from users\n const newUserReplies = (comment.replies ?? []).filter((r) => {\n if (\n serviceEmail &&\n r.author.emailAddress?.toLowerCase() === serviceEmail.toLowerCase()\n ) {\n return false;\n }\n const replyKey = `${key}:reply:${r.id}`;\n if (processedReplyIds.has(r.id) || processedComments.has(replyKey))\n return false;\n if (!isAgentMention(r.content, triggerKeyword)) return false;\n return true;\n });\n\n for (const reply of newUserReplies) {\n const replyKey = `${key}:reply:${reply.id}`;\n processedComments.add(replyKey);\n processedReplyIds.add(reply.id);\n // Persist immediately so a crash/cold-start between replies cannot\n // re-answer this reply on the next invocation.\n await saveThreadMapping(\n PLATFORM,\n key,\n existingMapping.internalThreadId,\n {\n ...existingMapping.platformContext,\n processedReplyIds: Array.from(processedReplyIds),\n },\n );\n\n const text = reply.content\n .replace(\n new RegExp(\n triggerKeyword.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"),\n \"gi\",\n ),\n \"\",\n )\n .trim();\n\n await processComment(\n fileId,\n comment.id,\n text,\n reply.author.displayName,\n options,\n existingMapping.internalThreadId,\n );\n }\n continue;\n }\n\n // New comment — check if it mentions the agent\n if (!isAgentMention(comment.content, triggerKeyword)) continue;\n\n processedComments.add(key);\n\n let text = comment.content;\n if (comment.quotedFileContent?.value) {\n text = `[Highlighted text: \"${comment.quotedFileContent.value}\"]\\n\\n${text}`;\n }\n\n text = text\n .replace(\n new RegExp(triggerKeyword.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"), \"gi\"),\n \"\",\n )\n .trim();\n\n await processComment(\n fileId,\n comment.id,\n text,\n comment.author.displayName,\n options,\n );\n }\n\n lastCheckedTimes.set(fileId, now);\n}\n\n// ─── Process Changes ────────────────────────────────────────────────────────\n\n/**\n * Process pending Drive changes — called by both push notifications and polling.\n * Fetches changes since the last page token, finds Google Docs that changed,\n * and checks their comments for agent mentions.\n */\nexport async function processChanges(\n options: GoogleDocsPollerOptions,\n): Promise<void> {\n const accessToken = await getServiceAccountAccessToken();\n if (!accessToken) return;\n\n let pageToken = await getPageToken();\n if (!pageToken) {\n pageToken = await getStartPageToken(accessToken);\n await setPageToken(pageToken);\n return; // First run — just save the cursor\n }\n\n const { changes, nextPageToken } = await listChanges(pageToken, accessToken);\n await setPageToken(nextPageToken);\n\n if (changes.length === 0) return;\n\n // Deduplicate and filter to Google Docs\n const docFileIds = new Set<string>();\n for (const change of changes) {\n if (change.removed) continue;\n if (\n change.file?.mimeType === \"application/vnd.google-apps.document\" ||\n !change.file?.mimeType\n ) {\n docFileIds.add(change.fileId);\n }\n }\n\n for (const fileId of docFileIds) {\n try {\n await checkDocumentComments(fileId, accessToken, options);\n } catch (err) {\n console.error(`[google-docs] Error checking comments on ${fileId}:`, err);\n }\n }\n}\n\n/**\n * Handle a push notification from Google Drive changes.watch.\n * Called from the integration webhook route.\n */\nexport async function handlePushNotification(): Promise<void> {\n if (!activeOptions) {\n console.warn(\n \"[google-docs] Push notification received but poller not configured\",\n );\n return;\n }\n\n try {\n await processChanges(activeOptions);\n } catch (err) {\n console.error(\"[google-docs] Error processing push notification:\", err);\n }\n}\n\n// ─── Agent Processing ───────────────────────────────────────────────────────\n\nasync function processComment(\n fileId: string,\n commentId: string,\n text: string,\n senderName: string,\n options: GoogleDocsPollerOptions,\n existingThreadId?: string,\n): Promise<void> {\n const adapter = googleDocsAdapter();\n const key = commentKey(fileId, commentId);\n\n const incoming: IncomingMessage = {\n platform: PLATFORM,\n externalThreadId: key,\n text,\n senderName,\n platformContext: { fileId, commentId },\n timestamp: Date.now(),\n };\n\n let threadId = existingThreadId;\n if (!threadId) {\n const thread = await createThread(options.ownerEmail, {\n title: `Google Doc: ${senderName}`,\n });\n await saveThreadMapping(PLATFORM, key, thread.id, { fileId, commentId });\n threadId = thread.id;\n }\n\n const thread = await getThread(threadId);\n const existingMessages: EngineMessage[] = [];\n if (thread?.threadData) {\n try {\n const data = JSON.parse(thread.threadData);\n if (Array.isArray(data.messages)) {\n for (const msg of data.messages) {\n const m = msg.message ?? msg;\n const textContent =\n typeof m.content === \"string\"\n ? m.content\n : Array.isArray(m.content)\n ? m.content\n .filter((c: any) => c.type === \"text\")\n .map((c: any) => c.text)\n .join(\"\\n\")\n : \"\";\n if (m.role === \"user\") {\n existingMessages.push({\n role: \"user\",\n content: [{ type: \"text\", text: textContent }],\n });\n } else if (m.role === \"assistant\") {\n existingMessages.push({\n role: \"assistant\",\n content: [{ type: \"text\", text: textContent }],\n });\n }\n }\n }\n } catch {}\n }\n\n const messages: EngineMessage[] = [\n ...existingMessages,\n { role: \"user\", content: [{ type: \"text\", text }] },\n ];\n\n const engine = createAnthropicEngine({ apiKey: options.apiKey });\n const tools = actionsToEngineTools(options.actions);\n const runId = `gdocs-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n const capturedThreadId = threadId;\n const orgId = (await resolveOrgIdForEmail(options.ownerEmail)) ?? undefined;\n\n startRun(\n runId,\n capturedThreadId,\n async (send, signal) => {\n await runWithRequestContext(\n { userEmail: options.ownerEmail, orgId, isIntegrationCaller: true },\n () =>\n runAgentLoop({\n engine,\n model: options.model,\n systemPrompt: options.systemPrompt,\n tools,\n messages,\n actions: options.actions,\n send,\n signal,\n }),\n );\n },\n async (completedRun: ActiveRun) => {\n try {\n let responseText = \"\";\n for (const runEvent of completedRun.events) {\n if (runEvent.event.type === \"text\") {\n responseText += runEvent.event.text;\n }\n }\n if (!responseText.trim()) responseText = \"(No response)\";\n\n const outgoing = adapter.formatAgentResponse(responseText);\n await adapter.sendResponse(outgoing, incoming);\n await persistThreadData(capturedThreadId, text, completedRun, thread);\n } catch (err) {\n console.error(\"[google-docs] Error sending response:\", err);\n }\n },\n );\n}\n\nasync function persistThreadData(\n threadId: string,\n userText: string,\n completedRun: ActiveRun,\n thread: any,\n): Promise<void> {\n try {\n let repo: any;\n try {\n repo = JSON.parse(thread?.threadData || \"{}\");\n } catch {\n repo = {};\n }\n if (!Array.isArray(repo.messages)) repo.messages = [];\n\n repo.messages.push({\n id: `msg-${Date.now()}-user`,\n role: \"user\",\n content: [{ type: \"text\", text: userText }],\n createdAt: new Date().toISOString(),\n });\n\n const assistantMsg = buildAssistantMessage(\n completedRun.events ?? [],\n completedRun.runId,\n );\n if (assistantMsg) repo.messages.push(assistantMsg);\n\n const meta = extractThreadMeta(repo);\n await updateThreadData(\n threadId,\n JSON.stringify(repo),\n meta.title || thread?.title || \"Google Doc Comment\",\n meta.preview || thread?.preview || \"\",\n repo.messages.length,\n );\n } catch {\n // Best-effort\n }\n}\n\n// ─── Poller (Hybrid: Push Primary, Poll Fallback) ───────────────────────────\n\n/**\n * Start the Google Docs integration.\n *\n * Hybrid approach:\n * 1. Attempts to register a Google Drive changes.watch webhook for\n * near-instant push notifications (~seconds latency)\n * 2. Falls back to polling if the watch registration fails\n * (e.g. domain not verified, local dev)\n * 3. Even in push mode, polls at a slow interval (5min) as a safety net\n * in case a push notification is missed\n */\nexport async function startGoogleDocsPoller(\n options: GoogleDocsPollerOptions,\n): Promise<void> {\n if (pollerInterval) {\n console.warn(\"[google-docs] Already running\");\n return;\n }\n\n activeOptions = options;\n\n // Check if integration is enabled before trying to register watch\n const config = await getIntegrationConfig(PLATFORM);\n if (!config?.configData?.enabled) {\n // Still start the poll loop so it picks up when enabled later\n startPollLoop(options, options.intervalMs ?? 30_000);\n return;\n }\n\n // Try to register push notifications\n const webhookUrl = options.webhookUrl;\n let pushMode = false;\n\n if (webhookUrl) {\n pushMode = await registerWatch(webhookUrl);\n if (pushMode) {\n console.log(\"[google-docs] Push mode active — using Drive webhooks\");\n // In push mode, still poll slowly as a safety net (every 5 min)\n startPollLoop(options, 5 * 60 * 1000);\n }\n }\n\n if (!pushMode) {\n console.log(\n \"[google-docs] Polling mode — push registration failed or no webhook URL\",\n );\n startPollLoop(options, options.intervalMs ?? 30_000);\n }\n}\n\nfunction startPollLoop(\n options: GoogleDocsPollerOptions,\n intervalMs: number,\n): void {\n async function poll() {\n try {\n const config = await getIntegrationConfig(PLATFORM);\n if (!config?.configData?.enabled) return;\n await processChanges(options);\n } catch (err) {\n // Unwrap ErrorEvent (Neon WS driver emits these on network failure) so logs show the real cause\n const detail =\n err instanceof Error\n ? err\n : ((err as any)?.error ?? (err as any)?.message ?? err);\n console.error(\"[google-docs] Poller error:\", detail);\n }\n }\n\n setTimeout(poll, 5000);\n pollerInterval = setInterval(poll, intervalMs);\n\n const email = getServiceAccountEmail();\n if (process.env.DEBUG) {\n console.log(\n `[google-docs] Poll loop started (interval: ${intervalMs / 1000}s, service account: ${email ?? \"not configured\"})`,\n );\n }\n}\n\n/**\n * Stop the Google Docs integration.\n */\nexport async function stopGoogleDocsPoller(): Promise<void> {\n if (pollerInterval) {\n clearInterval(pollerInterval);\n pollerInterval = null;\n }\n if (watchRenewalTimer) {\n clearTimeout(watchRenewalTimer);\n watchRenewalTimer = null;\n }\n await stopWatch();\n activeOptions = null;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"pending-tasks-retry-job.d.ts","sourceRoot":"","sources":["../../src/integrations/pending-tasks-retry-job.ts"],"names":[],"mappings":"AAwDA;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CA2Ff;AA8ED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GAAG,IAAI,CA0BP;AAED,2BAA2B;AAC3B,wBAAgB,wBAAwB,IAAI,IAAI,CAU/C"}
1
+ {"version":3,"file":"pending-tasks-retry-job.d.ts","sourceRoot":"","sources":["../../src/integrations/pending-tasks-retry-job.ts"],"names":[],"mappings":"AAwDA;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CA+Ff;AA8ED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GAAG,IAAI,CA0BP;AAED,2BAA2B;AAC3B,wBAAgB,wBAAwB,IAAI,IAAI,CAU/C"}
@@ -59,10 +59,14 @@ export async function retryStuckPendingTasks(webhookBaseUrl) {
59
59
  sql: `
60
60
  SELECT id, status, attempts
61
61
  FROM integration_pending_tasks
62
- WHERE (status = 'pending' AND created_at <= ?)
62
+ WHERE (status = 'pending' AND created_at <= ? AND updated_at <= ?)
63
63
  OR (status = 'processing' AND updated_at <= ?)
64
64
  `,
65
- args: [pendingCutoff, processingCutoff],
65
+ // `updated_at` is initialized to `created_at` on insert, so a genuinely
66
+ // stuck pending row still matches on the first sweep. The retry path
67
+ // below touches `updated_at`, which (with this predicate) keeps the row
68
+ // from being re-selected — and re-firing the processor — on every tick.
69
+ args: [pendingCutoff, pendingCutoff, processingCutoff],
66
70
  });
67
71
  stuckRows = rows.map((r) => ({
68
72
  id: r.id,