@agent-native/core 0.108.0 → 0.109.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (368) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +25 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/a2a/client.ts +162 -17
  5. package/corpus/core/src/a2a/correlation.ts +50 -0
  6. package/corpus/core/src/a2a/handlers.ts +200 -14
  7. package/corpus/core/src/a2a/index.ts +7 -1
  8. package/corpus/core/src/a2a/invoke.ts +77 -1
  9. package/corpus/core/src/a2a/server.ts +13 -1
  10. package/corpus/core/src/a2a/task-store.ts +146 -6
  11. package/corpus/core/src/a2a/types.ts +32 -0
  12. package/corpus/core/src/action.ts +5 -2
  13. package/corpus/core/src/agent/production-agent.ts +33 -4
  14. package/corpus/core/src/client/AssistantChat.tsx +648 -603
  15. package/corpus/core/src/client/MultiTabAssistantChat.tsx +31 -4
  16. package/corpus/core/src/client/agent-chat-adapter.ts +23 -37
  17. package/corpus/core/src/client/agent-sidebar-state.ts +4 -0
  18. package/corpus/core/src/client/analytics.ts +84 -0
  19. package/corpus/core/src/client/chat/message-components.tsx +94 -22
  20. package/corpus/core/src/client/chat/tool-call-display.tsx +170 -47
  21. package/corpus/core/src/client/chat/use-agent-chat-lifecycle-tracking.ts +74 -0
  22. package/corpus/core/src/client/chat-thread-url.ts +11 -0
  23. package/corpus/core/src/client/error-capture.ts +12 -0
  24. package/corpus/core/src/client/extensions/ExtensionSlot.tsx +37 -1
  25. package/corpus/core/src/client/index.ts +2 -0
  26. package/corpus/core/src/client/route-chunk-recovery.ts +20 -8
  27. package/corpus/core/src/client/session-replay.ts +31 -0
  28. package/corpus/core/src/client/use-run-stuck-detection.ts +27 -1
  29. package/corpus/core/src/db/client.ts +55 -0
  30. package/corpus/core/src/extensions/actions.ts +2 -14
  31. package/corpus/core/src/extensions/store.ts +1 -1
  32. package/corpus/core/src/localization/default-messages.ts +3 -0
  33. package/corpus/core/src/mcp/build-server.ts +2 -2
  34. package/corpus/core/src/observability/traces.ts +172 -19
  35. package/corpus/core/src/progress/actions.ts +4 -2
  36. package/corpus/core/src/provider-api/index.ts +205 -105
  37. package/corpus/core/src/scripts/call-agent.ts +190 -19
  38. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +112 -25
  39. package/corpus/core/src/server/agent-chat-plugin.ts +136 -4
  40. package/corpus/core/src/styles/agent-conversation.css +7 -0
  41. package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +20 -0
  42. package/corpus/core/src/templates/default/app/i18n/de-DE.ts +20 -0
  43. package/corpus/core/src/templates/default/app/i18n/en-US.ts +20 -0
  44. package/corpus/core/src/templates/default/app/i18n/es-ES.ts +20 -0
  45. package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +21 -0
  46. package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +19 -0
  47. package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +20 -0
  48. package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +19 -0
  49. package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +20 -0
  50. package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +19 -0
  51. package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +19 -0
  52. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
  53. package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  54. package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
  55. package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  56. package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  57. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -10
  58. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +54 -23
  59. package/corpus/templates/analytics/.builder/skills/apollo/SKILL.md +19 -41
  60. package/corpus/templates/analytics/.builder/skills/commonroom/SKILL.md +20 -35
  61. package/corpus/templates/analytics/.builder/skills/github/SKILL.md +23 -67
  62. package/corpus/templates/analytics/.builder/skills/pylon/SKILL.md +25 -43
  63. package/corpus/templates/analytics/AGENTS.md +22 -13
  64. package/corpus/templates/analytics/actions/account-deep-dive.ts +1 -0
  65. package/corpus/templates/analytics/actions/configure-gong-native-insights.ts +29 -0
  66. package/corpus/templates/analytics/actions/content-calendar-schema.ts +8 -4
  67. package/corpus/templates/analytics/actions/content-calendar.ts +12 -4
  68. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -1
  69. package/corpus/templates/analytics/actions/gong-calls.ts +113 -22
  70. package/corpus/templates/analytics/actions/gong-native-insights.ts +166 -0
  71. package/corpus/templates/analytics/actions/hubspot-deals.ts +190 -46
  72. package/corpus/templates/analytics/actions/pylon-issues.ts +123 -0
  73. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
  74. package/corpus/templates/analytics/actions/slack-messages.ts +179 -27
  75. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +48 -152
  76. package/corpus/templates/analytics/app/components/ui/chart.tsx +1 -1
  77. package/corpus/templates/analytics/app/hooks/use-chart-tooltip-flip.ts +21 -6
  78. package/corpus/templates/analytics/app/i18n/zh-TW.ts +13 -0
  79. package/corpus/templates/analytics/app/i18n-data.ts +134 -0
  80. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +181 -30
  81. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +6 -0
  82. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +4 -3
  83. package/corpus/templates/analytics/changelog/2026-07-17-analytics-now-includes-a-default-alert-for-spikes-in-stuck-agent-chats.md +6 -0
  84. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-editors-can-add-shared-extensions-or-opt-into-per-.md +6 -0
  85. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extensions-show-a-loading-skeleton.md +6 -0
  86. package/corpus/templates/analytics/changelog/2026-07-17-errors-now-group-repeat-failures-consistently-and-keep-priva.md +6 -0
  87. package/corpus/templates/analytics/changelog/2026-07-17-gong-transcript-reviews-now-batch-bounded-call-windows-for-f.md +6 -0
  88. package/corpus/templates/analytics/changelog/2026-07-17-hubspot-deal-filters-now-run-in-hubspot-before-paging-result.md +6 -0
  89. package/corpus/templates/analytics/changelog/2026-07-17-notion-content-calendars-now-discover-the-matching-database-.md +6 -0
  90. package/corpus/templates/analytics/changelog/2026-07-17-pylon-dashboard-reads-now-use-the-paginated-issue-search-api.md +6 -0
  91. package/corpus/templates/analytics/changelog/2026-07-17-slack-reads-no-longer-join-channels-and-report-pagination-coverage.md +6 -0
  92. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +23 -14
  93. package/corpus/templates/analytics/docs/schemas/tracked-events.md +5 -1
  94. package/corpus/templates/analytics/server/handlers/notion.ts +14 -3
  95. package/corpus/templates/analytics/server/handlers/slack.ts +182 -29
  96. package/corpus/templates/analytics/server/jobs/analytics-alerts.ts +3 -3
  97. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -6
  98. package/corpus/templates/analytics/server/lib/analytics-alerts.ts +209 -87
  99. package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +6 -2
  100. package/corpus/templates/analytics/server/lib/error-capture.ts +75 -8
  101. package/corpus/templates/analytics/server/lib/gong-native-policy.ts +72 -0
  102. package/corpus/templates/analytics/server/lib/gong.ts +54 -66
  103. package/corpus/templates/analytics/server/lib/hubspot.ts +40 -3
  104. package/corpus/templates/analytics/server/lib/notion.ts +83 -8
  105. package/corpus/templates/analytics/server/lib/real-data-actions.ts +4 -0
  106. package/corpus/templates/analytics/server/lib/slack.ts +242 -90
  107. package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -3
  108. package/corpus/templates/analytics/server/routes/api/pylon/accounts.get.ts +42 -1
  109. package/corpus/templates/analytics/server/routes/api/pylon/issues.get.ts +71 -1
  110. package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +44 -4
  111. package/corpus/templates/clips/actions/finalize-recording.ts +541 -62
  112. package/corpus/templates/clips/app/components/library/bulk-action-toolbar.tsx +19 -1
  113. package/corpus/templates/clips/app/components/library/create-folder-dialog.tsx +123 -0
  114. package/corpus/templates/clips/app/components/library/library-grid.tsx +42 -4
  115. package/corpus/templates/clips/app/components/library/recording-card.tsx +30 -0
  116. package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +17 -2
  117. package/corpus/templates/clips/app/components/player/video-player.tsx +14 -2
  118. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +2 -2
  119. package/corpus/templates/clips/app/entry.client.tsx +6 -1
  120. package/corpus/templates/clips/app/i18n/ar-SA.ts +12 -1
  121. package/corpus/templates/clips/app/i18n/de-DE.ts +12 -1
  122. package/corpus/templates/clips/app/i18n/en-US.ts +12 -1
  123. package/corpus/templates/clips/app/i18n/es-ES.ts +11 -1
  124. package/corpus/templates/clips/app/i18n/fr-FR.ts +11 -1
  125. package/corpus/templates/clips/app/i18n/hi-IN.ts +10 -1
  126. package/corpus/templates/clips/app/i18n/ja-JP.ts +12 -1
  127. package/corpus/templates/clips/app/i18n/ko-KR.ts +11 -1
  128. package/corpus/templates/clips/app/i18n/pt-BR.ts +11 -1
  129. package/corpus/templates/clips/app/i18n/zh-CN.ts +11 -1
  130. package/corpus/templates/clips/app/i18n/zh-TW.ts +11 -1
  131. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +72 -1
  132. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -1
  133. package/corpus/templates/clips/app/routes/record.tsx +3 -3
  134. package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -3
  135. package/corpus/templates/clips/changelog/2026-07-17-choose-which-workspace-receives-new-clips-recordings-and-des.md +6 -0
  136. package/corpus/templates/clips/changelog/2026-07-17-clips-now-retries-storage-verification-in-the-background-ins.md +6 -0
  137. package/corpus/templates/clips/changelog/2026-07-17-create-folders-directly-from-the-move-menu.md +6 -0
  138. package/corpus/templates/clips/changelog/2026-07-17-failed-desktop-uploads-now-offer-a-direct-way-to-reopen-clip.md +6 -0
  139. package/corpus/templates/clips/changelog/2026-07-17-fixed-broken-thumbnail-icons-appearing-over-playable-clip-em.md +6 -0
  140. package/corpus/templates/clips/changelog/2026-07-17-playback-comments-stay-readable-at-faster-playback-speeds.md +6 -0
  141. package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +3 -0
  142. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +3 -3
  143. package/corpus/templates/clips/desktop/src/app.tsx +19 -7
  144. package/corpus/templates/clips/desktop/src/lib/recorder.ts +111 -13
  145. package/corpus/templates/clips/desktop/src/lib/upload-verification.ts +16 -7
  146. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -4
  147. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/live_upload.rs +32 -15
  148. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +45 -18
  149. package/corpus/templates/clips/server/jobs/media-verification.ts +130 -0
  150. package/corpus/templates/clips/server/lib/builder-media-compression.ts +15 -0
  151. package/corpus/templates/clips/server/lib/media-verification-state.ts +38 -0
  152. package/corpus/templates/clips/server/lib/player-thumbnail-url.ts +31 -0
  153. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +10 -3
  154. package/corpus/templates/clips/server/plugins/auth.ts +5 -5
  155. package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
  156. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +12 -2
  157. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +6 -1
  158. package/corpus/templates/clips/server/routes/api/thumbnail/[recordingId].get.ts +340 -0
  159. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +24 -7
  160. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +91 -7
  161. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +14 -0
  162. package/corpus/templates/clips/shared/finalize-recovery.ts +61 -2
  163. package/corpus/templates/clips/shared/share-meta.ts +1 -1
  164. package/corpus/templates/content/app/entry.client.tsx +6 -1
  165. package/corpus/templates/dispatch/AGENTS.md +5 -0
  166. package/corpus/templates/dispatch/changelog/2026-07-17-apps-page-links-to-other-available-apps.md +6 -0
  167. package/corpus/templates/dispatch/changelog/2026-07-17-curated-template-remixes.md +6 -0
  168. package/corpus/templates/mail/app/entry.client.tsx +6 -1
  169. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +11 -7
  170. package/corpus/templates/slides/.env.example +0 -1
  171. package/corpus/templates/slides/AGENTS.md +4 -0
  172. package/corpus/templates/slides/DEVELOPING.md +2 -2
  173. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
  174. package/corpus/templates/slides/actions/logo-config.ts +6 -7
  175. package/corpus/templates/slides/actions/search-images.ts +11 -39
  176. package/corpus/templates/slides/actions/search-logos.ts +5 -52
  177. package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +1 -1
  178. package/corpus/templates/slides/app/components/editor/LogoSearchPanel.tsx +16 -26
  179. package/corpus/templates/slides/app/entry.client.tsx +6 -1
  180. package/corpus/templates/slides/server/lib/media-search-providers.ts +216 -0
  181. package/corpus/templates/slides/server/register-secrets.ts +30 -0
  182. package/dist/a2a/client.d.ts +47 -1
  183. package/dist/a2a/client.d.ts.map +1 -1
  184. package/dist/a2a/client.js +94 -12
  185. package/dist/a2a/client.js.map +1 -1
  186. package/dist/a2a/correlation.d.ts +10 -0
  187. package/dist/a2a/correlation.d.ts.map +1 -0
  188. package/dist/a2a/correlation.js +40 -0
  189. package/dist/a2a/correlation.js.map +1 -0
  190. package/dist/a2a/handlers.d.ts.map +1 -1
  191. package/dist/a2a/handlers.js +147 -15
  192. package/dist/a2a/handlers.js.map +1 -1
  193. package/dist/a2a/index.d.ts +4 -4
  194. package/dist/a2a/index.d.ts.map +1 -1
  195. package/dist/a2a/index.js +2 -2
  196. package/dist/a2a/index.js.map +1 -1
  197. package/dist/a2a/invoke.d.ts +29 -2
  198. package/dist/a2a/invoke.d.ts.map +1 -1
  199. package/dist/a2a/invoke.js +33 -1
  200. package/dist/a2a/invoke.js.map +1 -1
  201. package/dist/a2a/server.d.ts.map +1 -1
  202. package/dist/a2a/server.js +14 -1
  203. package/dist/a2a/server.js.map +1 -1
  204. package/dist/a2a/task-store.d.ts +12 -1
  205. package/dist/a2a/task-store.d.ts.map +1 -1
  206. package/dist/a2a/task-store.js +96 -6
  207. package/dist/a2a/task-store.js.map +1 -1
  208. package/dist/a2a/types.d.ts +27 -0
  209. package/dist/a2a/types.d.ts.map +1 -1
  210. package/dist/a2a/types.js.map +1 -1
  211. package/dist/action.d.ts +5 -2
  212. package/dist/action.d.ts.map +1 -1
  213. package/dist/action.js.map +1 -1
  214. package/dist/agent/production-agent.d.ts +14 -0
  215. package/dist/agent/production-agent.d.ts.map +1 -1
  216. package/dist/agent/production-agent.js +19 -3
  217. package/dist/agent/production-agent.js.map +1 -1
  218. package/dist/client/AssistantChat.d.ts +14 -1
  219. package/dist/client/AssistantChat.d.ts.map +1 -1
  220. package/dist/client/AssistantChat.js +158 -136
  221. package/dist/client/AssistantChat.js.map +1 -1
  222. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  223. package/dist/client/MultiTabAssistantChat.js +27 -4
  224. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  225. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  226. package/dist/client/agent-chat-adapter.js +21 -39
  227. package/dist/client/agent-chat-adapter.js.map +1 -1
  228. package/dist/client/agent-sidebar-state.d.ts +1 -0
  229. package/dist/client/agent-sidebar-state.d.ts.map +1 -1
  230. package/dist/client/agent-sidebar-state.js +4 -0
  231. package/dist/client/agent-sidebar-state.js.map +1 -1
  232. package/dist/client/analytics.d.ts +14 -0
  233. package/dist/client/analytics.d.ts.map +1 -1
  234. package/dist/client/analytics.js +67 -0
  235. package/dist/client/analytics.js.map +1 -1
  236. package/dist/client/chat/message-components.d.ts +8 -0
  237. package/dist/client/chat/message-components.d.ts.map +1 -1
  238. package/dist/client/chat/message-components.js +62 -19
  239. package/dist/client/chat/message-components.js.map +1 -1
  240. package/dist/client/chat/tool-call-display.d.ts +6 -0
  241. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  242. package/dist/client/chat/tool-call-display.js +83 -14
  243. package/dist/client/chat/tool-call-display.js.map +1 -1
  244. package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts +8 -0
  245. package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts.map +1 -0
  246. package/dist/client/chat/use-agent-chat-lifecycle-tracking.js +51 -0
  247. package/dist/client/chat/use-agent-chat-lifecycle-tracking.js.map +1 -0
  248. package/dist/client/chat-thread-url.d.ts +2 -0
  249. package/dist/client/chat-thread-url.d.ts.map +1 -0
  250. package/dist/client/chat-thread-url.js +12 -0
  251. package/dist/client/chat-thread-url.js.map +1 -0
  252. package/dist/client/error-capture.d.ts.map +1 -1
  253. package/dist/client/error-capture.js +7 -0
  254. package/dist/client/error-capture.js.map +1 -1
  255. package/dist/client/extensions/ExtensionSlot.d.ts +3 -1
  256. package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
  257. package/dist/client/extensions/ExtensionSlot.js +28 -3
  258. package/dist/client/extensions/ExtensionSlot.js.map +1 -1
  259. package/dist/client/index.d.ts +1 -1
  260. package/dist/client/index.d.ts.map +1 -1
  261. package/dist/client/index.js +1 -1
  262. package/dist/client/index.js.map +1 -1
  263. package/dist/client/route-chunk-recovery.d.ts.map +1 -1
  264. package/dist/client/route-chunk-recovery.js +14 -9
  265. package/dist/client/route-chunk-recovery.js.map +1 -1
  266. package/dist/client/session-replay.d.ts +15 -0
  267. package/dist/client/session-replay.d.ts.map +1 -1
  268. package/dist/client/session-replay.js +20 -0
  269. package/dist/client/session-replay.js.map +1 -1
  270. package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
  271. package/dist/client/use-run-stuck-detection.js +25 -1
  272. package/dist/client/use-run-stuck-detection.js.map +1 -1
  273. package/dist/db/client.d.ts +7 -0
  274. package/dist/db/client.d.ts.map +1 -1
  275. package/dist/db/client.js +33 -0
  276. package/dist/db/client.js.map +1 -1
  277. package/dist/extensions/actions.d.ts.map +1 -1
  278. package/dist/extensions/actions.js +2 -10
  279. package/dist/extensions/actions.js.map +1 -1
  280. package/dist/extensions/store.js +1 -1
  281. package/dist/extensions/store.js.map +1 -1
  282. package/dist/localization/default-messages.d.ts +3 -0
  283. package/dist/localization/default-messages.d.ts.map +1 -1
  284. package/dist/localization/default-messages.js +3 -0
  285. package/dist/localization/default-messages.js.map +1 -1
  286. package/dist/mcp/build-server.d.ts +2 -0
  287. package/dist/mcp/build-server.d.ts.map +1 -1
  288. package/dist/mcp/build-server.js +2 -2
  289. package/dist/mcp/build-server.js.map +1 -1
  290. package/dist/notifications/routes.d.ts +2 -2
  291. package/dist/observability/routes.d.ts +5 -5
  292. package/dist/observability/traces.d.ts +9 -0
  293. package/dist/observability/traces.d.ts.map +1 -1
  294. package/dist/observability/traces.js +137 -19
  295. package/dist/observability/traces.js.map +1 -1
  296. package/dist/progress/actions.d.ts.map +1 -1
  297. package/dist/progress/actions.js +3 -2
  298. package/dist/progress/actions.js.map +1 -1
  299. package/dist/progress/routes.d.ts +1 -1
  300. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  301. package/dist/provider-api/index.d.ts.map +1 -1
  302. package/dist/provider-api/index.js +91 -8
  303. package/dist/provider-api/index.js.map +1 -1
  304. package/dist/scripts/call-agent.d.ts.map +1 -1
  305. package/dist/scripts/call-agent.js +140 -17
  306. package/dist/scripts/call-agent.js.map +1 -1
  307. package/dist/secrets/routes.d.ts +9 -9
  308. package/dist/server/agent-chat/action-filters-a2a.d.ts +24 -2
  309. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  310. package/dist/server/agent-chat/action-filters-a2a.js +62 -7
  311. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  312. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  313. package/dist/server/agent-chat-plugin.js +118 -5
  314. package/dist/server/agent-chat-plugin.js.map +1 -1
  315. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  316. package/dist/server/transcribe-voice.d.ts +1 -1
  317. package/dist/styles/agent-conversation.css +7 -0
  318. package/dist/templates/default/app/i18n/ar-SA.ts +20 -0
  319. package/dist/templates/default/app/i18n/de-DE.ts +20 -0
  320. package/dist/templates/default/app/i18n/en-US.ts +20 -0
  321. package/dist/templates/default/app/i18n/es-ES.ts +20 -0
  322. package/dist/templates/default/app/i18n/fr-FR.ts +21 -0
  323. package/dist/templates/default/app/i18n/hi-IN.ts +19 -0
  324. package/dist/templates/default/app/i18n/ja-JP.ts +20 -0
  325. package/dist/templates/default/app/i18n/ko-KR.ts +19 -0
  326. package/dist/templates/default/app/i18n/pt-BR.ts +20 -0
  327. package/dist/templates/default/app/i18n/zh-CN.ts +19 -0
  328. package/dist/templates/default/app/i18n/zh-TW.ts +19 -0
  329. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
  330. package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  331. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
  332. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  333. package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  334. package/package.json +1 -1
  335. package/src/templates/default/app/i18n/ar-SA.ts +20 -0
  336. package/src/templates/default/app/i18n/de-DE.ts +20 -0
  337. package/src/templates/default/app/i18n/en-US.ts +20 -0
  338. package/src/templates/default/app/i18n/es-ES.ts +20 -0
  339. package/src/templates/default/app/i18n/fr-FR.ts +21 -0
  340. package/src/templates/default/app/i18n/hi-IN.ts +19 -0
  341. package/src/templates/default/app/i18n/ja-JP.ts +20 -0
  342. package/src/templates/default/app/i18n/ko-KR.ts +19 -0
  343. package/src/templates/default/app/i18n/pt-BR.ts +20 -0
  344. package/src/templates/default/app/i18n/zh-CN.ts +19 -0
  345. package/src/templates/default/app/i18n/zh-TW.ts +19 -0
  346. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
  347. package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  348. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
  349. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  350. package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  351. package/corpus/templates/analytics/server/handlers/github.ts +0 -200
  352. package/corpus/templates/analytics/server/handlers/pylon.ts +0 -43
  353. package/corpus/templates/analytics/server/lib/apollo.ts +0 -167
  354. package/corpus/templates/analytics/server/lib/commonroom.ts +0 -149
  355. package/corpus/templates/analytics/server/lib/github.ts +0 -660
  356. package/corpus/templates/analytics/server/lib/mixpanel.ts +0 -156
  357. package/corpus/templates/analytics/server/lib/posthog.ts +0 -194
  358. package/corpus/templates/analytics/server/lib/pylon.ts +0 -109
  359. package/corpus/templates/analytics/server/routes/api/github/graphql.post.ts +0 -1
  360. package/corpus/templates/analytics/server/routes/api/github/issue.get.ts +0 -1
  361. package/corpus/templates/analytics/server/routes/api/github/org-prs.get.ts +0 -1
  362. package/corpus/templates/analytics/server/routes/api/github/pr.get.ts +0 -1
  363. package/corpus/templates/analytics/server/routes/api/github/prs.get.ts +0 -1
  364. package/corpus/templates/analytics/server/routes/api/github/search.get.ts +0 -1
  365. package/corpus/templates/slides/actions/fetch-logos.ts +0 -90
  366. package/corpus/templates/slides/actions/image-search.ts +0 -64
  367. package/corpus/templates/slides/actions/import-github.ts +0 -182
  368. package/corpus/templates/slides/actions/logo-lookup.ts +0 -113
@@ -45,7 +45,7 @@ function expectedJwtAudience(event) {
45
45
  process.env.DEPLOY_URL ||
46
46
  process.env.BETTER_AUTH_URL;
47
47
  if (fromEnv)
48
- return String(fromEnv);
48
+ return String(fromEnv).replace(/\/$/, "");
49
49
  // Best-effort: derive from the inbound request host. This is forgeable
50
50
  // (Host-header attack), but only useful as a hint when env-derived URL
51
51
  // is unset; the rest of the JWT verification still uses the secret.
@@ -345,6 +345,7 @@ export function mountA2A(nitroApp, config, routePrefix = "/_agent-native") {
345
345
  const bearerToken = extractBearerToken(authHeader);
346
346
  let verifiedCallerEmail = null;
347
347
  let verifiedOrgDomain = null;
348
+ let verifiedAudienceBound = false;
348
349
  let legacyApiKeyAuthenticated = false;
349
350
  let bearerTokenRejectedByJwt = false;
350
351
  // SECURITY: when neither A2A_SECRET nor an apiKeyEnv is configured,
@@ -359,6 +360,15 @@ export function mountA2A(nitroApp, config, routePrefix = "/_agent-native") {
359
360
  const tokenPayload = await verifyA2AToken(bearerToken, event);
360
361
  verifiedCallerEmail = tokenPayload.email;
361
362
  verifiedOrgDomain = tokenPayload.orgDomain;
363
+ if (verifiedCallerEmail) {
364
+ try {
365
+ verifiedAudienceBound =
366
+ typeof jose.decodeJwt(bearerToken).aud !== "undefined";
367
+ }
368
+ catch {
369
+ verifiedAudienceBound = false;
370
+ }
371
+ }
362
372
  bearerTokenRejectedByJwt = !verifiedCallerEmail;
363
373
  }
364
374
  // Fall back to legacy API key check (exact string match)
@@ -431,6 +441,9 @@ export function mountA2A(nitroApp, config, routePrefix = "/_agent-native") {
431
441
  if (verifiedCallerEmail) {
432
442
  event.context.__a2aVerifiedEmail = verifiedCallerEmail;
433
443
  }
444
+ if (verifiedAudienceBound) {
445
+ event.context.__a2aAudienceVerified = true;
446
+ }
434
447
  if (verifiedOrgDomain) {
435
448
  event.context.__a2aOrgDomain = verifiedOrgDomain;
436
449
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/a2a/server.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n defineEventHandler,\n setResponseHeader,\n setResponseStatus,\n getMethod,\n getRequestHeader,\n} from \"h3\";\nimport * as jose from \"jose\";\n\nimport { redactArgsToJson } from \"../audit/redact.js\";\nimport {\n extractBearerToken,\n verifyInternalToken,\n} from \"../integrations/internal-token.js\";\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport { isSameOriginRequest } from \"../server/request-origin.js\";\nimport { generateAgentCard } from \"./agent-card.js\";\nimport {\n hasConfiguredA2ASecret,\n isA2AProductionRuntime,\n} from \"./auth-policy.js\";\nimport { handleJsonRpcH3, processA2ATaskFromQueue } from \"./handlers.js\";\nimport {\n claimA2AApproval,\n getA2AApprovalForOwner,\n settleA2AApproval,\n} from \"./task-store.js\";\nimport type { A2AConfig } from \"./types.js\";\n\n/**\n * One-time warning when A2A is running unauthenticated in development. We\n * don't refuse the request (local templates need to work out of the box),\n * but we log a single noisy line so operators notice if they accidentally\n * deploy with no auth configured.\n */\nlet _warnedUnauthA2A = false;\nfunction warnA2AUnauthOnce(): void {\n if (_warnedUnauthA2A) return;\n _warnedUnauthA2A = true;\n // eslint-disable-next-line no-console\n console.warn(\n \"[a2a] No A2A_SECRET or apiKeyEnv configured — A2A endpoint runs unauthenticated. \" +\n \"This is allowed in development but blocked in production. Set A2A_SECRET before deploying.\",\n );\n}\n\n/**\n * Result of verifying an inbound A2A JWT. `email` is the caller identity from\n * the token's `sub` claim (null when verification fails), `orgDomain` mirrors\n * the verified `org_domain` claim when present.\n */\nexport interface A2ATokenPayload {\n email: string | null;\n orgDomain: string | null;\n}\n\nfunction addSecretCandidate(\n candidates: string[],\n secret: string | undefined,\n): void {\n const trimmed = secret?.trim();\n if (!trimmed || candidates.includes(trimmed)) return;\n candidates.push(trimmed);\n}\n\n/**\n * Resolve the audience (`aud`) value to expect in an inbound JWT. We use the\n * receiver's app URL — it's the natural identifier of \"who this token was\n * minted for\". Returns undefined when no app URL is configured and no request\n * host is derivable; `verifyA2AToken` then rejects any token that carries an\n * `aud` claim (fail closed — a correctly signed token minted for another\n * service must not verify here). Only tokens without an `aud` claim (minted\n * before the audience claim shipped) skip the audience check.\n */\nfunction expectedJwtAudience(event: any | undefined): string | undefined {\n const fromEnv =\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n process.env.BETTER_AUTH_URL;\n if (fromEnv) return String(fromEnv);\n // Best-effort: derive from the inbound request host. This is forgeable\n // (Host-header attack), but only useful as a hint when env-derived URL\n // is unset; the rest of the JWT verification still uses the secret.\n try {\n const proto = getRequestHeader(event, \"x-forwarded-proto\") || \"https\";\n const host = getRequestHeader(event, \"host\");\n if (host) return `${proto}://${host}`;\n } catch {}\n return undefined;\n}\n\n/**\n * Verify an inbound A2A bearer token (HS256) exactly as the\n * `/_agent-native/a2a` endpoint does: it peeks at the unverified `org_domain`\n * claim to build an ordered candidate-secret set (`process.env.A2A_SECRET`\n * plus any org-level secret for that domain), then verifies the JWT — checking\n * `aud`/`iss` when the token carries them and `exp` always. Returns the\n * caller's email (`sub`) and org domain on success, or `{ email: null,\n * orgDomain: null }` on any failure (malformed, bad signature, expired, or no\n * secret configured), never throwing.\n *\n * Exported so workspaces can accept A2A callers on the HTTP action route with\n * the same routine — including org-level fallback secrets — instead of\n * reimplementing a partial verifier. Pass the H3 `event` to enable org-domain →\n * org-secret lookup and audience derivation; it is optional.\n */\nexport async function verifyA2AToken(\n token: string,\n event?: any,\n): Promise<A2ATokenPayload> {\n // Step 1: Peek at JWT claims WITHOUT verification to get org_domain.\n // This is safe because we only use org_domain to look up the secret,\n // then verify the full JWT with that secret. If someone forges a JWT\n // with a fake org_domain, verification will fail because they don't\n // have the real secret.\n let orgDomainHint: string | undefined;\n let unverifiedPayload: jose.JWTPayload | undefined;\n try {\n unverifiedPayload = jose.decodeJwt(token);\n orgDomainHint = unverifiedPayload.org_domain as string | undefined;\n } catch {\n // Malformed token — fall through to global secret attempt\n }\n\n // Step 2: Build a small, ordered set of candidate secrets. Tokens minted by\n // current callers prefer the shared A2A_SECRET; older callers may still use\n // an org-level secret. Try both without logging or reflecting secret details.\n const candidateSecrets: string[] = [];\n addSecretCandidate(candidateSecrets, process.env.A2A_SECRET);\n if (orgDomainHint) {\n try {\n const { getA2ASecretByDomain } = await import(\"../org/context.js\");\n const orgSecret = await getA2ASecretByDomain(orgDomainHint);\n addSecretCandidate(candidateSecrets, orgSecret ?? undefined);\n } catch {\n // DB not ready or column doesn't exist yet — fall through\n }\n }\n if (candidateSecrets.length === 0) return { email: null, orgDomain: null };\n\n // Step 3: Verify JWT with the candidate secrets.\n //\n // - `audience`: passed only when the token carries an `aud` claim\n // (backward-compat: tokens minted by older `signA2AToken` versions\n // don't include one).\n // - `issuer`: enforced when the token carries an `iss` claim. The\n // sender's `signA2AToken` (`a2a/client.ts:42`) sets the issuer to its\n // own app URL, so a verified token must self-identify a non-empty\n // string issuer. We accept any string the token claims (we don't pin\n // a specific expected issuer because dispatchers may legitimately\n // mint tokens from many sender URLs — dev tunnels, multi-deploy\n // setups). The pin is \"issuer must match the value the token says\n // it was minted from\", which `jose.jwtVerify` validates exactly when\n // `issuer` is supplied as a string. Backward-compat: when the token\n // has no `iss`, we skip the check.\n try {\n const verifyOptions: jose.JWTVerifyOptions = {};\n if (unverifiedPayload && typeof unverifiedPayload.aud !== \"undefined\") {\n // Fail closed: the token was minted for a specific audience, but this\n // receiver can't derive its own expected audience (no APP_URL/URL and no\n // usable request host). Accepting here would let a correctly-signed token\n // whose `aud` targets ANOTHER service verify against a shared secret. A\n // token that self-declares an audience must be checked against ours, so\n // when we have nothing to check it against we reject rather than skip.\n const aud = expectedJwtAudience(event);\n if (!aud) return { email: null, orgDomain: null };\n verifyOptions.audience = aud;\n }\n if (\n unverifiedPayload &&\n typeof unverifiedPayload.iss === \"string\" &&\n unverifiedPayload.iss.length > 0\n ) {\n verifyOptions.issuer = unverifiedPayload.iss;\n }\n for (const secret of candidateSecrets) {\n try {\n const { payload } = await jose.jwtVerify(\n token,\n new TextEncoder().encode(secret),\n verifyOptions,\n );\n return {\n email: (payload.sub as string) ?? null,\n orgDomain: (payload.org_domain as string) ?? null,\n };\n } catch {\n // Try the next candidate without leaking which secret failed.\n }\n }\n } catch {\n // Keep malformed option construction indistinguishable from auth failure.\n }\n return { email: null, orgDomain: null };\n}\n\n/**\n * Mount A2A protocol endpoints on an H3/Nitro app.\n *\n * - GET /.well-known/agent-card.json — public agent card (no auth)\n * - POST /_agent-native/a2a — JSON-RPC endpoint (with optional auth)\n *\n * When A2A_SECRET is set, inbound Bearer tokens are verified as JWTs\n * and the caller's email is extracted from the `sub` claim. This provides\n * cryptographic identity verification for cross-app A2A calls.\n */\nexport function mountA2A(\n nitroApp: any,\n config: A2AConfig,\n routePrefix = \"/_agent-native\",\n): void {\n // Public agent card endpoint (no auth required).\n //\n // SECURITY: per-user / per-org MCP tools are filtered out of the public\n // skills list. Their merged-key prefix (`mcp__user_<emailhash>_…` or\n // `mcp__org_<orgid>_…`) discloses (a) which users have integrations\n // attached, and (b) what those integrations are — fingerprinting the\n // tenant. Template- and framework-defined skills stay; only the dynamic\n // per-tenant MCP entries are dropped. See finding #7 in\n // /tmp/security-audit/12-mcp-a2a-agent.md.\n getH3App(nitroApp).use(\n \"/.well-known/agent-card.json\",\n defineEventHandler((event) => {\n if (getMethod(event) !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n const protocol =\n getRequestHeader(event, \"x-forwarded-proto\") ||\n (event.url?.protocol?.replace(\":\", \"\") ?? \"http\");\n const host = getRequestHeader(event, \"host\") ?? \"localhost\";\n const baseUrl = `${protocol}://${host}`;\n\n const filteredSkills = filterPublicAgentCardSkills(config);\n\n return generateAgentCard(\n { ...config, skills: filteredSkills },\n baseUrl,\n `${routePrefix}/a2a`,\n );\n }),\n );\n\n // Human-only continuation for consequential A2A tool calls. The opaque id\n // is a lookup handle, not authorization: every read and mutation also\n // requires the task owner's live browser session. Ordinary A2A bearer\n // tokens never reach this control plane and cannot approve themselves.\n getH3App(nitroApp).use(\n `${routePrefix}/a2a/approvals`,\n defineEventHandler(async (event) => {\n const approvalId = (event.path || \"\")\n .split(\"?\")[0]\n .replace(/^\\//, \"\")\n .split(\"/\")[0];\n if (!approvalId) {\n setResponseStatus(event, 404);\n return { error: \"Approval not found\" };\n }\n\n const { getSession } = await import(\"../server/auth.js\");\n const session = await getSession(event);\n if (!session?.email) {\n setResponseStatus(event, 401);\n return { error: \"Sign in to review this approval\" };\n }\n\n if (getMethod(event) === \"GET\") {\n const approval = await getA2AApprovalForOwner(\n approvalId,\n session.email,\n session.orgId ?? null,\n );\n if (!approval) {\n setResponseStatus(event, 404);\n return { error: \"Approval not found\" };\n }\n const safeInput = redactArgsToJson(approval.input) ?? \"{}\";\n const esc = (value: string) =>\n value.replace(\n /[&<>\"']/g,\n (char) =>\n ({\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#39;\",\n })[char] ?? char,\n );\n setResponseHeader(event, \"content-type\", \"text/html; charset=utf-8\");\n setResponseHeader(event, \"cache-control\", \"no-store\");\n setResponseHeader(event, \"x-frame-options\", \"DENY\");\n setResponseHeader(\n event,\n \"content-security-policy\",\n \"frame-ancestors 'none'\",\n );\n setResponseHeader(event, \"referrer-policy\", \"no-referrer\");\n const expired = approval.expiresAt <= Date.now();\n const active = approval.status === \"pending\" && !expired;\n const displayStatus = expired ? \"expired\" : approval.status;\n return `<!doctype html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>Review agent action</title><style>body{font:15px/1.5 ui-sans-serif,system-ui;background:#f7f7f5;color:#171717;margin:0}.card{max-width:680px;margin:8vh auto;background:white;border:1px solid #ddd;border-radius:14px;padding:28px;box-shadow:0 12px 36px #0001}h1{font-size:22px;margin:0 0 8px}p{color:#555}pre{white-space:pre-wrap;word-break:break-word;background:#f4f4f2;padding:16px;border-radius:9px;max-height:45vh;overflow:auto}button{background:#171717;color:white;border:0;border-radius:8px;padding:11px 16px;font-weight:650;cursor:pointer}button[disabled]{opacity:.5;cursor:default}#status{margin-left:10px;color:#555}</style></head><body><main class=\"card\"><h1>Review agent action</h1><p>This action is paused until you approve it. Approval can be used once.</p><h2>${esc(approval.tool)}</h2><pre>${esc(safeInput)}</pre><button id=\"approve\" ${active ? \"\" : \"disabled\"}>${active ? \"Approve and run\" : esc(displayStatus)}</button><span id=\"status\">${active ? \"\" : esc(approval.result ?? displayStatus)}</span><script>document.getElementById('approve').onclick=async function(){this.disabled=true;document.getElementById('status').textContent='Running…';try{const r=await fetch(location.href,{method:'POST',credentials:'include',headers:{'content-type':'application/json'}});const j=await r.json();document.getElementById('status').textContent=j.output||j.error||'Done';}catch(e){document.getElementById('status').textContent='Could not run the action.'}}</script></main></body></html>`;\n }\n\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n if (!isSameOriginRequest(event)) {\n setResponseStatus(event, 403);\n return { error: \"Cross-origin approval denied\" };\n }\n if (!config.executeApproval) {\n setResponseStatus(event, 501);\n return { error: \"Approval execution is not configured\" };\n }\n\n const approval = await claimA2AApproval(\n approvalId,\n session.email,\n session.orgId ?? null,\n );\n if (!approval) {\n const current = await getA2AApprovalForOwner(\n approvalId,\n session.email,\n session.orgId ?? null,\n );\n setResponseStatus(event, current ? 409 : 404);\n return {\n error: current\n ? `Approval is ${current.status} and cannot be run again`\n : \"Approval not found\",\n };\n }\n\n const { runWithRequestContext } =\n await import(\"../server/request-context.js\");\n let execution: { status: \"completed\" | \"failed\"; output: string };\n try {\n execution = await runWithRequestContext(\n { userEmail: session.email, orgId: session.orgId ?? undefined },\n () => config.executeApproval!(approval),\n );\n } catch (error) {\n execution = {\n status: \"failed\",\n output:\n error instanceof Error\n ? error.message\n : \"Approval execution failed\",\n };\n }\n await settleA2AApproval(approval.id, execution.status, execution.output);\n if (execution.status === \"failed\") setResponseStatus(event, 500);\n return execution;\n }),\n );\n\n // Async-mode processor route. MUST be mounted BEFORE the `/a2a` catch-all\n // below, since h3's `.use()` matches by prefix and `/a2a` would otherwise\n // swallow `/a2a/_process-task` and return a JSON-RPC \"Invalid token\" error\n // (the JSON-RPC handler doesn't know about taskId-only bodies).\n //\n // When `message/send` is called with `async: true`, the JSON-RPC handler\n // enqueues the task and self-fires a POST to this route on the same\n // deployment so the actual handler runs in a fresh function execution (its\n // own full timeout). Authenticated with an HMAC token bound to the task id\n // (5-minute lifetime, signed with A2A_SECRET — same scheme as the\n // integration webhook queue).\n getH3App(nitroApp).use(\n `${routePrefix}/a2a/_process-task`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n const body = (await readBody(event)) as { taskId?: unknown } | null;\n const taskId = body && typeof body.taskId === \"string\" ? body.taskId : \"\";\n if (!taskId) {\n setResponseStatus(event, 400);\n return { error: \"taskId required\" };\n }\n\n // When A2A_SECRET is set, require a valid HMAC token bound to this\n // taskId. In production, we REQUIRE A2A_SECRET to be set so unsigned\n // dispatches are never accepted (an attacker who fishes a taskId out\n // of logs / a share link could otherwise force-replay it). In\n // development, a missing secret is permitted so local templates work\n // out of the box, but we log a one-time warning so operators notice.\n if (hasConfiguredA2ASecret()) {\n const auth = getRequestHeader(event, \"authorization\");\n const tok = extractBearerToken(auth);\n if (!verifyInternalToken(taskId, tok ?? \"\")) {\n setResponseStatus(event, 401);\n return { error: \"Invalid or expired processor token\" };\n }\n } else if (isA2AProductionRuntime()) {\n setResponseStatus(event, 503);\n return {\n error:\n \"A2A processor not configured — set A2A_SECRET on this deployment to enable async A2A.\",\n };\n } else {\n warnA2AUnauthOnce();\n }\n\n try {\n await processA2ATaskFromQueue(taskId, config, event);\n return { ok: true };\n } catch (err: any) {\n console.error(\"[a2a] process-task failed:\", err);\n setResponseStatus(event, 500);\n return { error: err?.message ?? \"process-task failed\" };\n }\n }),\n );\n\n // JSON-RPC A2A endpoint (with optional auth)\n getH3App(nitroApp).use(\n `${routePrefix}/a2a`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n // h3 prefix-matches mounts, so a request to `/a2a/_process-task`\n // reaches this handler too. The dedicated mount above runs first and\n // takes the request, but if that returns `undefined` (or h3 ever\n // changes ordering semantics) defensively bail here. event.path is\n // stripped to the remainder after the mount prefix.\n const sub = (event.path || \"/\").split(\"?\")[0].replace(/^\\//, \"\");\n if (sub.startsWith(\"_process-task\")) return;\n\n const authHeader = getRequestHeader(event, \"authorization\");\n const bearerToken = extractBearerToken(authHeader);\n let verifiedCallerEmail: string | null = null;\n let verifiedOrgDomain: string | null = null;\n let legacyApiKeyAuthenticated = false;\n let bearerTokenRejectedByJwt = false;\n\n // SECURITY: when neither A2A_SECRET nor an apiKeyEnv is configured,\n // there's no way to authenticate the caller. Default to \"auth required\"\n // in production — return 503 with a clear message instead of running\n // the agent loop unauthenticated. In development, log a one-time\n // warning but allow so local templates work out of the box.\n const hasA2ASecret = hasConfiguredA2ASecret();\n const hasApiKey = !!(config.apiKeyEnv && process.env[config.apiKeyEnv]);\n\n // Try JWT verification first (org-level or global A2A_SECRET-based identity)\n if (bearerToken) {\n const tokenPayload = await verifyA2AToken(bearerToken, event);\n verifiedCallerEmail = tokenPayload.email;\n verifiedOrgDomain = tokenPayload.orgDomain;\n bearerTokenRejectedByJwt = !verifiedCallerEmail;\n }\n\n // Fall back to legacy API key check (exact string match)\n if (!verifiedCallerEmail && config.apiKeyEnv) {\n const expectedKey = process.env[config.apiKeyEnv];\n if (expectedKey) {\n if (!bearerToken) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32001, message: \"Authentication required\" },\n };\n }\n if (bearerToken !== expectedKey) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32001, message: \"Invalid API key\" },\n };\n }\n legacyApiKeyAuthenticated = true;\n }\n }\n\n if (!verifiedCallerEmail && !legacyApiKeyAuthenticated) {\n // Any supplied bearer token that failed JWT verification is an auth\n // failure after the legacy exact-match apiKeyEnv path has had a\n // chance to succeed. Do not let bad tokens fall through to tasks/get\n // and get reported as lookup misses.\n if (bearerTokenRejectedByJwt) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32001,\n message: \"Invalid or expired A2A token\",\n },\n };\n }\n\n if (!hasA2ASecret && !hasApiKey) {\n if (isA2AProductionRuntime()) {\n setResponseStatus(event, 503);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32001,\n message:\n \"A2A authentication not configured. Set A2A_SECRET (preferred) or configure apiKeyEnv to accept inbound A2A traffic.\",\n },\n };\n }\n warnA2AUnauthOnce();\n } else if (isA2AProductionRuntime()) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32001,\n message: \"Authentication required\",\n },\n };\n }\n }\n\n // Store verified caller identity on the event context so the handler\n // can set request context from a trusted source instead of metadata\n if (verifiedCallerEmail) {\n event.context.__a2aVerifiedEmail = verifiedCallerEmail;\n }\n if (verifiedOrgDomain) {\n event.context.__a2aOrgDomain = verifiedOrgDomain;\n }\n\n const body = await readBody(event);\n return handleJsonRpcH3(body, event, config);\n }),\n );\n}\n\nexport function filterPublicAgentCardSkills(config: A2AConfig) {\n return (config.skills ?? []).filter((skill) => {\n const id =\n (skill as { id?: string; name?: string }).id ??\n (skill as { name?: string }).name ??\n \"\";\n if (typeof id === \"string\") {\n if (id.startsWith(\"mcp__user_\") || id.startsWith(\"mcp__org_\")) {\n return false;\n }\n }\n\n if (skill.public === false || skill.requiresAuth || skill.isConsequential) {\n return false;\n }\n\n if (!config.publicSkillsOnly) return true;\n\n if (skill.publicAgent) {\n return (\n skill.publicAgent.expose === true &&\n skill.publicAgent.readOnly === true &&\n skill.publicAgent.requiresAuth !== true &&\n skill.publicAgent.isConsequential !== true\n );\n }\n\n return skill.public === true && skill.readOnly !== false;\n });\n}\n"]}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/a2a/server.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n defineEventHandler,\n setResponseHeader,\n setResponseStatus,\n getMethod,\n getRequestHeader,\n} from \"h3\";\nimport * as jose from \"jose\";\n\nimport { redactArgsToJson } from \"../audit/redact.js\";\nimport {\n extractBearerToken,\n verifyInternalToken,\n} from \"../integrations/internal-token.js\";\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport { isSameOriginRequest } from \"../server/request-origin.js\";\nimport { generateAgentCard } from \"./agent-card.js\";\nimport {\n hasConfiguredA2ASecret,\n isA2AProductionRuntime,\n} from \"./auth-policy.js\";\nimport { handleJsonRpcH3, processA2ATaskFromQueue } from \"./handlers.js\";\nimport {\n claimA2AApproval,\n getA2AApprovalForOwner,\n settleA2AApproval,\n} from \"./task-store.js\";\nimport type { A2AConfig } from \"./types.js\";\n\n/**\n * One-time warning when A2A is running unauthenticated in development. We\n * don't refuse the request (local templates need to work out of the box),\n * but we log a single noisy line so operators notice if they accidentally\n * deploy with no auth configured.\n */\nlet _warnedUnauthA2A = false;\nfunction warnA2AUnauthOnce(): void {\n if (_warnedUnauthA2A) return;\n _warnedUnauthA2A = true;\n // eslint-disable-next-line no-console\n console.warn(\n \"[a2a] No A2A_SECRET or apiKeyEnv configured — A2A endpoint runs unauthenticated. \" +\n \"This is allowed in development but blocked in production. Set A2A_SECRET before deploying.\",\n );\n}\n\n/**\n * Result of verifying an inbound A2A JWT. `email` is the caller identity from\n * the token's `sub` claim (null when verification fails), `orgDomain` mirrors\n * the verified `org_domain` claim when present.\n */\nexport interface A2ATokenPayload {\n email: string | null;\n orgDomain: string | null;\n}\n\nfunction addSecretCandidate(\n candidates: string[],\n secret: string | undefined,\n): void {\n const trimmed = secret?.trim();\n if (!trimmed || candidates.includes(trimmed)) return;\n candidates.push(trimmed);\n}\n\n/**\n * Resolve the audience (`aud`) value to expect in an inbound JWT. We use the\n * receiver's app URL — it's the natural identifier of \"who this token was\n * minted for\". Returns undefined when no app URL is configured and no request\n * host is derivable; `verifyA2AToken` then rejects any token that carries an\n * `aud` claim (fail closed — a correctly signed token minted for another\n * service must not verify here). Only tokens without an `aud` claim (minted\n * before the audience claim shipped) skip the audience check.\n */\nfunction expectedJwtAudience(event: any | undefined): string | undefined {\n const fromEnv =\n process.env.APP_URL ||\n process.env.URL ||\n process.env.DEPLOY_URL ||\n process.env.BETTER_AUTH_URL;\n if (fromEnv) return String(fromEnv).replace(/\\/$/, \"\");\n // Best-effort: derive from the inbound request host. This is forgeable\n // (Host-header attack), but only useful as a hint when env-derived URL\n // is unset; the rest of the JWT verification still uses the secret.\n try {\n const proto = getRequestHeader(event, \"x-forwarded-proto\") || \"https\";\n const host = getRequestHeader(event, \"host\");\n if (host) return `${proto}://${host}`;\n } catch {}\n return undefined;\n}\n\n/**\n * Verify an inbound A2A bearer token (HS256) exactly as the\n * `/_agent-native/a2a` endpoint does: it peeks at the unverified `org_domain`\n * claim to build an ordered candidate-secret set (`process.env.A2A_SECRET`\n * plus any org-level secret for that domain), then verifies the JWT — checking\n * `aud`/`iss` when the token carries them and `exp` always. Returns the\n * caller's email (`sub`) and org domain on success, or `{ email: null,\n * orgDomain: null }` on any failure (malformed, bad signature, expired, or no\n * secret configured), never throwing.\n *\n * Exported so workspaces can accept A2A callers on the HTTP action route with\n * the same routine — including org-level fallback secrets — instead of\n * reimplementing a partial verifier. Pass the H3 `event` to enable org-domain →\n * org-secret lookup and audience derivation; it is optional.\n */\nexport async function verifyA2AToken(\n token: string,\n event?: any,\n): Promise<A2ATokenPayload> {\n // Step 1: Peek at JWT claims WITHOUT verification to get org_domain.\n // This is safe because we only use org_domain to look up the secret,\n // then verify the full JWT with that secret. If someone forges a JWT\n // with a fake org_domain, verification will fail because they don't\n // have the real secret.\n let orgDomainHint: string | undefined;\n let unverifiedPayload: jose.JWTPayload | undefined;\n try {\n unverifiedPayload = jose.decodeJwt(token);\n orgDomainHint = unverifiedPayload.org_domain as string | undefined;\n } catch {\n // Malformed token — fall through to global secret attempt\n }\n\n // Step 2: Build a small, ordered set of candidate secrets. Tokens minted by\n // current callers prefer the shared A2A_SECRET; older callers may still use\n // an org-level secret. Try both without logging or reflecting secret details.\n const candidateSecrets: string[] = [];\n addSecretCandidate(candidateSecrets, process.env.A2A_SECRET);\n if (orgDomainHint) {\n try {\n const { getA2ASecretByDomain } = await import(\"../org/context.js\");\n const orgSecret = await getA2ASecretByDomain(orgDomainHint);\n addSecretCandidate(candidateSecrets, orgSecret ?? undefined);\n } catch {\n // DB not ready or column doesn't exist yet — fall through\n }\n }\n if (candidateSecrets.length === 0) return { email: null, orgDomain: null };\n\n // Step 3: Verify JWT with the candidate secrets.\n //\n // - `audience`: passed only when the token carries an `aud` claim\n // (backward-compat: tokens minted by older `signA2AToken` versions\n // don't include one).\n // - `issuer`: enforced when the token carries an `iss` claim. The\n // sender's `signA2AToken` (`a2a/client.ts:42`) sets the issuer to its\n // own app URL, so a verified token must self-identify a non-empty\n // string issuer. We accept any string the token claims (we don't pin\n // a specific expected issuer because dispatchers may legitimately\n // mint tokens from many sender URLs — dev tunnels, multi-deploy\n // setups). The pin is \"issuer must match the value the token says\n // it was minted from\", which `jose.jwtVerify` validates exactly when\n // `issuer` is supplied as a string. Backward-compat: when the token\n // has no `iss`, we skip the check.\n try {\n const verifyOptions: jose.JWTVerifyOptions = {};\n if (unverifiedPayload && typeof unverifiedPayload.aud !== \"undefined\") {\n // Fail closed: the token was minted for a specific audience, but this\n // receiver can't derive its own expected audience (no APP_URL/URL and no\n // usable request host). Accepting here would let a correctly-signed token\n // whose `aud` targets ANOTHER service verify against a shared secret. A\n // token that self-declares an audience must be checked against ours, so\n // when we have nothing to check it against we reject rather than skip.\n const aud = expectedJwtAudience(event);\n if (!aud) return { email: null, orgDomain: null };\n verifyOptions.audience = aud;\n }\n if (\n unverifiedPayload &&\n typeof unverifiedPayload.iss === \"string\" &&\n unverifiedPayload.iss.length > 0\n ) {\n verifyOptions.issuer = unverifiedPayload.iss;\n }\n for (const secret of candidateSecrets) {\n try {\n const { payload } = await jose.jwtVerify(\n token,\n new TextEncoder().encode(secret),\n verifyOptions,\n );\n return {\n email: (payload.sub as string) ?? null,\n orgDomain: (payload.org_domain as string) ?? null,\n };\n } catch {\n // Try the next candidate without leaking which secret failed.\n }\n }\n } catch {\n // Keep malformed option construction indistinguishable from auth failure.\n }\n return { email: null, orgDomain: null };\n}\n\n/**\n * Mount A2A protocol endpoints on an H3/Nitro app.\n *\n * - GET /.well-known/agent-card.json — public agent card (no auth)\n * - POST /_agent-native/a2a — JSON-RPC endpoint (with optional auth)\n *\n * When A2A_SECRET is set, inbound Bearer tokens are verified as JWTs\n * and the caller's email is extracted from the `sub` claim. This provides\n * cryptographic identity verification for cross-app A2A calls.\n */\nexport function mountA2A(\n nitroApp: any,\n config: A2AConfig,\n routePrefix = \"/_agent-native\",\n): void {\n // Public agent card endpoint (no auth required).\n //\n // SECURITY: per-user / per-org MCP tools are filtered out of the public\n // skills list. Their merged-key prefix (`mcp__user_<emailhash>_…` or\n // `mcp__org_<orgid>_…`) discloses (a) which users have integrations\n // attached, and (b) what those integrations are — fingerprinting the\n // tenant. Template- and framework-defined skills stay; only the dynamic\n // per-tenant MCP entries are dropped. See finding #7 in\n // /tmp/security-audit/12-mcp-a2a-agent.md.\n getH3App(nitroApp).use(\n \"/.well-known/agent-card.json\",\n defineEventHandler((event) => {\n if (getMethod(event) !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n const protocol =\n getRequestHeader(event, \"x-forwarded-proto\") ||\n (event.url?.protocol?.replace(\":\", \"\") ?? \"http\");\n const host = getRequestHeader(event, \"host\") ?? \"localhost\";\n const baseUrl = `${protocol}://${host}`;\n\n const filteredSkills = filterPublicAgentCardSkills(config);\n\n return generateAgentCard(\n { ...config, skills: filteredSkills },\n baseUrl,\n `${routePrefix}/a2a`,\n );\n }),\n );\n\n // Human-only continuation for consequential A2A tool calls. The opaque id\n // is a lookup handle, not authorization: every read and mutation also\n // requires the task owner's live browser session. Ordinary A2A bearer\n // tokens never reach this control plane and cannot approve themselves.\n getH3App(nitroApp).use(\n `${routePrefix}/a2a/approvals`,\n defineEventHandler(async (event) => {\n const approvalId = (event.path || \"\")\n .split(\"?\")[0]\n .replace(/^\\//, \"\")\n .split(\"/\")[0];\n if (!approvalId) {\n setResponseStatus(event, 404);\n return { error: \"Approval not found\" };\n }\n\n const { getSession } = await import(\"../server/auth.js\");\n const session = await getSession(event);\n if (!session?.email) {\n setResponseStatus(event, 401);\n return { error: \"Sign in to review this approval\" };\n }\n\n if (getMethod(event) === \"GET\") {\n const approval = await getA2AApprovalForOwner(\n approvalId,\n session.email,\n session.orgId ?? null,\n );\n if (!approval) {\n setResponseStatus(event, 404);\n return { error: \"Approval not found\" };\n }\n const safeInput = redactArgsToJson(approval.input) ?? \"{}\";\n const esc = (value: string) =>\n value.replace(\n /[&<>\"']/g,\n (char) =>\n ({\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#39;\",\n })[char] ?? char,\n );\n setResponseHeader(event, \"content-type\", \"text/html; charset=utf-8\");\n setResponseHeader(event, \"cache-control\", \"no-store\");\n setResponseHeader(event, \"x-frame-options\", \"DENY\");\n setResponseHeader(\n event,\n \"content-security-policy\",\n \"frame-ancestors 'none'\",\n );\n setResponseHeader(event, \"referrer-policy\", \"no-referrer\");\n const expired = approval.expiresAt <= Date.now();\n const active = approval.status === \"pending\" && !expired;\n const displayStatus = expired ? \"expired\" : approval.status;\n return `<!doctype html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>Review agent action</title><style>body{font:15px/1.5 ui-sans-serif,system-ui;background:#f7f7f5;color:#171717;margin:0}.card{max-width:680px;margin:8vh auto;background:white;border:1px solid #ddd;border-radius:14px;padding:28px;box-shadow:0 12px 36px #0001}h1{font-size:22px;margin:0 0 8px}p{color:#555}pre{white-space:pre-wrap;word-break:break-word;background:#f4f4f2;padding:16px;border-radius:9px;max-height:45vh;overflow:auto}button{background:#171717;color:white;border:0;border-radius:8px;padding:11px 16px;font-weight:650;cursor:pointer}button[disabled]{opacity:.5;cursor:default}#status{margin-left:10px;color:#555}</style></head><body><main class=\"card\"><h1>Review agent action</h1><p>This action is paused until you approve it. Approval can be used once.</p><h2>${esc(approval.tool)}</h2><pre>${esc(safeInput)}</pre><button id=\"approve\" ${active ? \"\" : \"disabled\"}>${active ? \"Approve and run\" : esc(displayStatus)}</button><span id=\"status\">${active ? \"\" : esc(approval.result ?? displayStatus)}</span><script>document.getElementById('approve').onclick=async function(){this.disabled=true;document.getElementById('status').textContent='Running…';try{const r=await fetch(location.href,{method:'POST',credentials:'include',headers:{'content-type':'application/json'}});const j=await r.json();document.getElementById('status').textContent=j.output||j.error||'Done';}catch(e){document.getElementById('status').textContent='Could not run the action.'}}</script></main></body></html>`;\n }\n\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n if (!isSameOriginRequest(event)) {\n setResponseStatus(event, 403);\n return { error: \"Cross-origin approval denied\" };\n }\n if (!config.executeApproval) {\n setResponseStatus(event, 501);\n return { error: \"Approval execution is not configured\" };\n }\n\n const approval = await claimA2AApproval(\n approvalId,\n session.email,\n session.orgId ?? null,\n );\n if (!approval) {\n const current = await getA2AApprovalForOwner(\n approvalId,\n session.email,\n session.orgId ?? null,\n );\n setResponseStatus(event, current ? 409 : 404);\n return {\n error: current\n ? `Approval is ${current.status} and cannot be run again`\n : \"Approval not found\",\n };\n }\n\n const { runWithRequestContext } =\n await import(\"../server/request-context.js\");\n let execution: { status: \"completed\" | \"failed\"; output: string };\n try {\n execution = await runWithRequestContext(\n { userEmail: session.email, orgId: session.orgId ?? undefined },\n () => config.executeApproval!(approval),\n );\n } catch (error) {\n execution = {\n status: \"failed\",\n output:\n error instanceof Error\n ? error.message\n : \"Approval execution failed\",\n };\n }\n await settleA2AApproval(approval.id, execution.status, execution.output);\n if (execution.status === \"failed\") setResponseStatus(event, 500);\n return execution;\n }),\n );\n\n // Async-mode processor route. MUST be mounted BEFORE the `/a2a` catch-all\n // below, since h3's `.use()` matches by prefix and `/a2a` would otherwise\n // swallow `/a2a/_process-task` and return a JSON-RPC \"Invalid token\" error\n // (the JSON-RPC handler doesn't know about taskId-only bodies).\n //\n // When `message/send` is called with `async: true`, the JSON-RPC handler\n // enqueues the task and self-fires a POST to this route on the same\n // deployment so the actual handler runs in a fresh function execution (its\n // own full timeout). Authenticated with an HMAC token bound to the task id\n // (5-minute lifetime, signed with A2A_SECRET — same scheme as the\n // integration webhook queue).\n getH3App(nitroApp).use(\n `${routePrefix}/a2a/_process-task`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n const body = (await readBody(event)) as { taskId?: unknown } | null;\n const taskId = body && typeof body.taskId === \"string\" ? body.taskId : \"\";\n if (!taskId) {\n setResponseStatus(event, 400);\n return { error: \"taskId required\" };\n }\n\n // When A2A_SECRET is set, require a valid HMAC token bound to this\n // taskId. In production, we REQUIRE A2A_SECRET to be set so unsigned\n // dispatches are never accepted (an attacker who fishes a taskId out\n // of logs / a share link could otherwise force-replay it). In\n // development, a missing secret is permitted so local templates work\n // out of the box, but we log a one-time warning so operators notice.\n if (hasConfiguredA2ASecret()) {\n const auth = getRequestHeader(event, \"authorization\");\n const tok = extractBearerToken(auth);\n if (!verifyInternalToken(taskId, tok ?? \"\")) {\n setResponseStatus(event, 401);\n return { error: \"Invalid or expired processor token\" };\n }\n } else if (isA2AProductionRuntime()) {\n setResponseStatus(event, 503);\n return {\n error:\n \"A2A processor not configured — set A2A_SECRET on this deployment to enable async A2A.\",\n };\n } else {\n warnA2AUnauthOnce();\n }\n\n try {\n await processA2ATaskFromQueue(taskId, config, event);\n return { ok: true };\n } catch (err: any) {\n console.error(\"[a2a] process-task failed:\", err);\n setResponseStatus(event, 500);\n return { error: err?.message ?? \"process-task failed\" };\n }\n }),\n );\n\n // JSON-RPC A2A endpoint (with optional auth)\n getH3App(nitroApp).use(\n `${routePrefix}/a2a`,\n defineEventHandler(async (event) => {\n if (getMethod(event) !== \"POST\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n // h3 prefix-matches mounts, so a request to `/a2a/_process-task`\n // reaches this handler too. The dedicated mount above runs first and\n // takes the request, but if that returns `undefined` (or h3 ever\n // changes ordering semantics) defensively bail here. event.path is\n // stripped to the remainder after the mount prefix.\n const sub = (event.path || \"/\").split(\"?\")[0].replace(/^\\//, \"\");\n if (sub.startsWith(\"_process-task\")) return;\n\n const authHeader = getRequestHeader(event, \"authorization\");\n const bearerToken = extractBearerToken(authHeader);\n let verifiedCallerEmail: string | null = null;\n let verifiedOrgDomain: string | null = null;\n let verifiedAudienceBound = false;\n let legacyApiKeyAuthenticated = false;\n let bearerTokenRejectedByJwt = false;\n\n // SECURITY: when neither A2A_SECRET nor an apiKeyEnv is configured,\n // there's no way to authenticate the caller. Default to \"auth required\"\n // in production — return 503 with a clear message instead of running\n // the agent loop unauthenticated. In development, log a one-time\n // warning but allow so local templates work out of the box.\n const hasA2ASecret = hasConfiguredA2ASecret();\n const hasApiKey = !!(config.apiKeyEnv && process.env[config.apiKeyEnv]);\n\n // Try JWT verification first (org-level or global A2A_SECRET-based identity)\n if (bearerToken) {\n const tokenPayload = await verifyA2AToken(bearerToken, event);\n verifiedCallerEmail = tokenPayload.email;\n verifiedOrgDomain = tokenPayload.orgDomain;\n if (verifiedCallerEmail) {\n try {\n verifiedAudienceBound =\n typeof jose.decodeJwt(bearerToken).aud !== \"undefined\";\n } catch {\n verifiedAudienceBound = false;\n }\n }\n bearerTokenRejectedByJwt = !verifiedCallerEmail;\n }\n\n // Fall back to legacy API key check (exact string match)\n if (!verifiedCallerEmail && config.apiKeyEnv) {\n const expectedKey = process.env[config.apiKeyEnv];\n if (expectedKey) {\n if (!bearerToken) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32001, message: \"Authentication required\" },\n };\n }\n if (bearerToken !== expectedKey) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: { code: -32001, message: \"Invalid API key\" },\n };\n }\n legacyApiKeyAuthenticated = true;\n }\n }\n\n if (!verifiedCallerEmail && !legacyApiKeyAuthenticated) {\n // Any supplied bearer token that failed JWT verification is an auth\n // failure after the legacy exact-match apiKeyEnv path has had a\n // chance to succeed. Do not let bad tokens fall through to tasks/get\n // and get reported as lookup misses.\n if (bearerTokenRejectedByJwt) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32001,\n message: \"Invalid or expired A2A token\",\n },\n };\n }\n\n if (!hasA2ASecret && !hasApiKey) {\n if (isA2AProductionRuntime()) {\n setResponseStatus(event, 503);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32001,\n message:\n \"A2A authentication not configured. Set A2A_SECRET (preferred) or configure apiKeyEnv to accept inbound A2A traffic.\",\n },\n };\n }\n warnA2AUnauthOnce();\n } else if (isA2AProductionRuntime()) {\n setResponseStatus(event, 401);\n return {\n jsonrpc: \"2.0\",\n id: null,\n error: {\n code: -32001,\n message: \"Authentication required\",\n },\n };\n }\n }\n\n // Store verified caller identity on the event context so the handler\n // can set request context from a trusted source instead of metadata\n if (verifiedCallerEmail) {\n event.context.__a2aVerifiedEmail = verifiedCallerEmail;\n }\n if (verifiedAudienceBound) {\n event.context.__a2aAudienceVerified = true;\n }\n if (verifiedOrgDomain) {\n event.context.__a2aOrgDomain = verifiedOrgDomain;\n }\n\n const body = await readBody(event);\n return handleJsonRpcH3(body, event, config);\n }),\n );\n}\n\nexport function filterPublicAgentCardSkills(config: A2AConfig) {\n return (config.skills ?? []).filter((skill) => {\n const id =\n (skill as { id?: string; name?: string }).id ??\n (skill as { name?: string }).name ??\n \"\";\n if (typeof id === \"string\") {\n if (id.startsWith(\"mcp__user_\") || id.startsWith(\"mcp__org_\")) {\n return false;\n }\n }\n\n if (skill.public === false || skill.requiresAuth || skill.isConsequential) {\n return false;\n }\n\n if (!config.publicSkillsOnly) return true;\n\n if (skill.publicAgent) {\n return (\n skill.publicAgent.expose === true &&\n skill.publicAgent.readOnly === true &&\n skill.publicAgent.requiresAuth !== true &&\n skill.publicAgent.isConsequential !== true\n );\n }\n\n return skill.public === true && skill.readOnly !== false;\n });\n}\n"]}
@@ -1,4 +1,6 @@
1
1
  import type { Task, Message, TaskState, Artifact } from "./types.js";
2
+ export declare const MAX_A2A_IDEMPOTENCY_KEY_CHARS = 128;
3
+ export declare const A2A_PERSONAL_OWNER_SCOPE = "__personal__";
2
4
  export interface A2AApprovalRecord {
3
5
  id: string;
4
6
  taskId: string;
@@ -26,7 +28,15 @@ export declare function getA2AApprovalForOwner(id: string, ownerEmail: string, o
26
28
  export declare function claimA2AApproval(id: string, ownerEmail: string, orgId?: string | null): Promise<A2AApprovalRecord | null>;
27
29
  export declare function settleA2AApproval(id: string, status: "completed" | "failed", resultText: string): Promise<void>;
28
30
  export declare function pauseProcessingA2ATask(id: string, message: Message): Promise<Task | null>;
29
- export declare function createTask(message: Message, contextId?: string, metadata?: Record<string, unknown>, ownerEmail?: string | null): Promise<Task>;
31
+ export declare function createTask(message: Message, contextId?: string, metadata?: Record<string, unknown>, ownerEmail?: string | null, ownerScope?: string | null): Promise<Task>;
32
+ export declare function createOrReuseTask(message: Message, contextId: string | undefined, metadata: Record<string, unknown> | undefined, ownerEmail: string | null, ownerScope: string | null, idempotencyKey: string | undefined): Promise<{
33
+ task: Task;
34
+ reused: boolean;
35
+ }>;
36
+ export interface A2ATaskOwnership {
37
+ ownerEmail: string | null;
38
+ ownerScope: string | null;
39
+ }
30
40
  /**
31
41
  * Fetch the verified owner email recorded against a task at creation time.
32
42
  * Returns null when the task has no owner (legacy rows or unauthenticated
@@ -36,6 +46,7 @@ export declare function createTask(message: Message, contextId?: string, metadat
36
46
  * verified caller's email must match `owner_email` to read or cancel.
37
47
  */
38
48
  export declare function getTaskOwner(id: string): Promise<string | null>;
49
+ export declare function getTaskOwnership(id: string): Promise<A2ATaskOwnership>;
39
50
  /**
40
51
  * Atomically claim a task for processing. Only succeeds when the task is in
41
52
  * state 'submitted' or 'working' — flipping it to 'processing' so concurrent
@@ -1 +1 @@
1
- {"version":3,"file":"task-store.d.ts","sourceRoot":"","sources":["../../src/a2a/task-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"task-store.d.ts","sourceRoot":"","sources":["../../src/a2a/task-store.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGrE,eAAO,MAAM,6BAA6B,MAAM,CAAC;AAEjD,eAAO,MAAM,wBAAwB,iBAAiB,CAAC;AAqHvD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC1D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAkCD,wBAAsB,iBAAiB,CAAC,KAAK,EAAE;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAmC7B;AAED,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACpB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAOnC;AAED,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GACpB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAwCnC;AAED,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,WAAW,GAAG,QAAQ,EAC9B,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CA+Cf;AAED,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAyBtB;AAqCD,wBAAsB,UAAU,CAC9B,OAAO,EAAE,OAAO,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,EAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GACzB,OAAO,CAAC,IAAI,CAAC,CAmCf;AAED,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC7C,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,OAAO,CAAC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC,CAmE1C;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAErE;AAED,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgB5E;AAED;;;;;;;;GAQG;AACH,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAwBtB;AAED,wBAAsB,uBAAuB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IACjE,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CAAC,CAgBR;AAED,wBAAsB,0BAA0B,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAa7E;AAED,wBAAsB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAazE;AAED,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,MAAM,EACV,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,OAAO,CAAC,CAiBlB;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,MAAM,EACV,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE,MAAM,EACd,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,OAAO,CAAC,CAoClB;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,MAAM,EACV,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC,CAsBlB;AAED,wBAAsB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAS9D;AAED,wBAAsB,UAAU,CAC9B,EAAE,EAAE,MAAM,EACV,MAAM,EAAE;IACN,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;CACxB,GACA,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CA4CtB;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,MAAM,EACV,MAAM,EAAE;IACN,KAAK,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;CACxB,GACA,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CA+CtB;AAED,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,wBAAsB,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAgBnE"}
@@ -1,7 +1,10 @@
1
1
  import crypto from "crypto";
2
2
  import { getDbExec, intType, isPostgres } from "../db/client.js";
3
- import { ensureTableExists, ensureColumnExists } from "../db/ddl-guard.js";
3
+ import { ensureTableExists, ensureColumnExists, ensureIndexExists, } from "../db/ddl-guard.js";
4
4
  let _initPromise;
5
+ export const MAX_A2A_IDEMPOTENCY_KEY_CHARS = 128;
6
+ const A2A_IDEMPOTENCY_INDEX = "idx_a2a_tasks_owner_scope_idempotency";
7
+ export const A2A_PERSONAL_OWNER_SCOPE = "__personal__";
5
8
  async function ensureTable() {
6
9
  if (!_initPromise) {
7
10
  _initPromise = (async () => {
@@ -16,10 +19,15 @@ async function ensureTable() {
16
19
  history TEXT NOT NULL DEFAULT '[]',
17
20
  artifacts TEXT NOT NULL DEFAULT '[]',
18
21
  metadata TEXT,
22
+ owner_email TEXT,
23
+ owner_scope TEXT NOT NULL DEFAULT '',
24
+ idempotency_key TEXT,
19
25
  created_at ${intType()} NOT NULL,
20
26
  updated_at ${intType()} NOT NULL
21
27
  )
22
28
  `;
29
+ const createIdempotencyIndexSql = `CREATE UNIQUE INDEX IF NOT EXISTS ${A2A_IDEMPOTENCY_INDEX} ` +
30
+ `ON a2a_tasks(owner_email, owner_scope, idempotency_key)`;
23
31
  const createApprovalsSql = `
24
32
  CREATE TABLE IF NOT EXISTS a2a_approvals (
25
33
  id TEXT PRIMARY KEY,
@@ -48,6 +56,9 @@ async function ensureTable() {
48
56
  // the legacy-token apiKeyEnv path; new rows are scoped from this point
49
57
  // forward.
50
58
  await ensureColumnExists("a2a_tasks", "owner_email", `ALTER TABLE a2a_tasks ADD COLUMN IF NOT EXISTS owner_email TEXT`);
59
+ await ensureColumnExists("a2a_tasks", "owner_scope", `ALTER TABLE a2a_tasks ADD COLUMN IF NOT EXISTS owner_scope TEXT NOT NULL DEFAULT ''`);
60
+ await ensureColumnExists("a2a_tasks", "idempotency_key", `ALTER TABLE a2a_tasks ADD COLUMN IF NOT EXISTS idempotency_key TEXT`);
61
+ await ensureIndexExists(A2A_IDEMPOTENCY_INDEX, createIdempotencyIndexSql);
51
62
  await ensureTableExists("a2a_approvals", createApprovalsSql);
52
63
  return;
53
64
  }
@@ -59,12 +70,25 @@ async function ensureTable() {
59
70
  // have NULL owner_email and remain accessible to legacy callers via
60
71
  // the legacy-token apiKeyEnv path; new rows are scoped from this point
61
72
  // forward.
73
+ try {
74
+ await client.execute(`ALTER TABLE a2a_tasks ADD COLUMN owner_scope TEXT NOT NULL DEFAULT ''`);
75
+ }
76
+ catch {
77
+ // Column already exists — expected on every restart after first run.
78
+ }
62
79
  try {
63
80
  await client.execute(`ALTER TABLE a2a_tasks ADD COLUMN owner_email TEXT`);
64
81
  }
65
82
  catch {
66
83
  // Column already exists — expected on every restart after first run.
67
84
  }
85
+ try {
86
+ await client.execute(`ALTER TABLE a2a_tasks ADD COLUMN idempotency_key TEXT`);
87
+ }
88
+ catch {
89
+ // Column already exists — expected on every restart after first run.
90
+ }
91
+ await client.execute(createIdempotencyIndexSql);
68
92
  await client.execute(createApprovalsSql);
69
93
  })().catch((err) => {
70
94
  // Retry init on the next call after a failed startup.
@@ -286,13 +310,14 @@ function taskFromRow(row) {
286
310
  artifacts: JSON.parse(row.artifacts),
287
311
  metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
288
312
  ownerEmail: row.owner_email ?? null,
313
+ ownerScope: row.owner_scope ?? null,
289
314
  };
290
315
  }
291
316
  function getAffectedRowCount(result) {
292
317
  const resultRecord = result;
293
318
  return (resultRecord?.rowsAffected ?? resultRecord?.rowCount ?? resultRecord?.count);
294
319
  }
295
- export async function createTask(message, contextId, metadata, ownerEmail) {
320
+ export async function createTask(message, contextId, metadata, ownerEmail, ownerScope) {
296
321
  await ensureTable();
297
322
  const client = getDbExec();
298
323
  const id = crypto.randomUUID();
@@ -307,7 +332,7 @@ export async function createTask(message, contextId, metadata, ownerEmail) {
307
332
  metadata,
308
333
  };
309
334
  await client.execute({
310
- sql: `INSERT INTO a2a_tasks (id, context_id, status_state, status_timestamp, history, artifacts, metadata, owner_email, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
335
+ sql: `INSERT INTO a2a_tasks (id, context_id, status_state, status_timestamp, history, artifacts, metadata, owner_email, owner_scope, idempotency_key, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
311
336
  args: [
312
337
  id,
313
338
  contextId ?? null,
@@ -317,12 +342,70 @@ export async function createTask(message, contextId, metadata, ownerEmail) {
317
342
  "[]",
318
343
  metadata ? JSON.stringify(metadata) : null,
319
344
  ownerEmail ?? null,
345
+ ownerScope ?? "",
346
+ null,
320
347
  now,
321
348
  now,
322
349
  ],
323
350
  });
324
351
  return task;
325
352
  }
353
+ export async function createOrReuseTask(message, contextId, metadata, ownerEmail, ownerScope, idempotencyKey) {
354
+ if (!ownerEmail || !idempotencyKey) {
355
+ return {
356
+ task: await createTask(message, contextId, metadata, ownerEmail, ownerScope),
357
+ reused: false,
358
+ };
359
+ }
360
+ if (idempotencyKey.length > MAX_A2A_IDEMPOTENCY_KEY_CHARS) {
361
+ throw new Error("A2A idempotency key is too long");
362
+ }
363
+ await ensureTable();
364
+ const client = getDbExec();
365
+ const normalizedOwner = ownerEmail.trim().toLowerCase();
366
+ const normalizedScope = ownerScope?.trim().toLowerCase() || A2A_PERSONAL_OWNER_SCOPE;
367
+ for (let attempt = 0; attempt < 2; attempt++) {
368
+ const id = crypto.randomUUID();
369
+ const now = Date.now();
370
+ const timestamp = new Date().toISOString();
371
+ await client.execute({
372
+ sql: `INSERT INTO a2a_tasks (id, context_id, status_state, status_timestamp, history, artifacts, metadata, owner_email, owner_scope, idempotency_key, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(owner_email, owner_scope, idempotency_key) DO NOTHING`,
373
+ args: [
374
+ id,
375
+ contextId ?? null,
376
+ "submitted",
377
+ timestamp,
378
+ JSON.stringify([message]),
379
+ "[]",
380
+ metadata ? JSON.stringify(metadata) : null,
381
+ normalizedOwner,
382
+ normalizedScope,
383
+ idempotencyKey,
384
+ now,
385
+ now,
386
+ ],
387
+ });
388
+ const { rows } = await client.execute({
389
+ sql: `SELECT * FROM a2a_tasks WHERE owner_email = ? AND owner_scope = ? AND idempotency_key = ?`,
390
+ args: [normalizedOwner, normalizedScope, idempotencyKey],
391
+ });
392
+ if (rows.length === 0) {
393
+ throw new Error("A2A idempotent task insert could not be verified");
394
+ }
395
+ const task = taskFromRow(rows[0]);
396
+ const reused = task.id !== id;
397
+ if (reused &&
398
+ (task.status.state === "failed" || task.status.state === "canceled")) {
399
+ await client.execute({
400
+ sql: `UPDATE a2a_tasks SET idempotency_key = NULL, updated_at = ? WHERE id = ? AND idempotency_key = ? AND status_state IN ('failed', 'canceled')`,
401
+ args: [Date.now(), task.id, idempotencyKey],
402
+ });
403
+ continue;
404
+ }
405
+ return { task, reused };
406
+ }
407
+ throw new Error("A2A terminal task idempotency key could not be released");
408
+ }
326
409
  /**
327
410
  * Fetch the verified owner email recorded against a task at creation time.
328
411
  * Returns null when the task has no owner (legacy rows or unauthenticated
@@ -332,16 +415,23 @@ export async function createTask(message, contextId, metadata, ownerEmail) {
332
415
  * verified caller's email must match `owner_email` to read or cancel.
333
416
  */
334
417
  export async function getTaskOwner(id) {
418
+ return (await getTaskOwnership(id)).ownerEmail;
419
+ }
420
+ export async function getTaskOwnership(id) {
335
421
  await ensureTable();
336
422
  const client = getDbExec();
337
423
  const { rows } = await client.execute({
338
- sql: `SELECT owner_email FROM a2a_tasks WHERE id = ?`,
424
+ sql: `SELECT owner_email, owner_scope FROM a2a_tasks WHERE id = ?`,
339
425
  args: [id],
340
426
  });
341
427
  if (rows.length === 0)
342
- return null;
428
+ return { ownerEmail: null, ownerScope: null };
343
429
  const ownerEmail = rows[0].owner_email;
344
- return typeof ownerEmail === "string" && ownerEmail ? ownerEmail : null;
430
+ const ownerScope = rows[0].owner_scope;
431
+ return {
432
+ ownerEmail: typeof ownerEmail === "string" && ownerEmail ? ownerEmail : null,
433
+ ownerScope: typeof ownerScope === "string" && ownerScope ? ownerScope : null,
434
+ };
345
435
  }
346
436
  /**
347
437
  * Atomically claim a task for processing. Only succeeds when the task is in