@canonry/canonry 7.72.1 → 7.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/assets/assets/{AgentSetupPage-D39M9CRK.js → AgentSetupPage-D7YVdPWO.js} +1 -1
  2. package/assets/assets/{AuditHistoryPanel-BS-iFyHX.js → AuditHistoryPanel-yrgfS5B_.js} +1 -1
  3. package/assets/assets/{BacklinksPage-BW2bEGF4.js → BacklinksPage-DJM6z03g.js} +1 -1
  4. package/assets/assets/{HistoryPage-Dh6o2iVd.js → HistoryPage-CNvAVJ1S.js} +1 -1
  5. package/assets/assets/{MeasurementPropertyPage-DL9cbtVz.js → MeasurementPropertyPage-BVVYhOxR.js} +1 -1
  6. package/assets/assets/{ProjectPage-DXh97uDN.js → ProjectPage-CPRD8kR9.js} +1 -1
  7. package/assets/assets/{RunsPage-BM4ETLsm.js → RunsPage-Ck33dcjz.js} +1 -1
  8. package/assets/assets/{SettingsPage-DpJTB2-Q.js → SettingsPage-CS_t4Dai.js} +1 -1
  9. package/assets/assets/{SiteHealthSection-CmlMQ17V.js → SiteHealthSection-BurKnHpn.js} +2 -2
  10. package/assets/assets/ToneBadge-Df8oiKsQ.js +60 -0
  11. package/assets/assets/{TrafficPage-ClH3Dxnm.js → TrafficPage-DAiY698E.js} +1 -1
  12. package/assets/assets/{TrafficSourceDetailPage-DE-NyNGz.js → TrafficSourceDetailPage-clJSX2rr.js} +1 -1
  13. package/assets/assets/{account-context-BwV6ox8O.js → account-context-DDEhuoP2.js} +1 -1
  14. package/assets/assets/{card-DhkoBNyY.js → card-DbR-lBY3.js} +1 -1
  15. package/assets/assets/{extract-error-message-dNDtiSBo.js → extract-error-message-7_Vm2DQF.js} +1 -1
  16. package/assets/assets/{format-helpers-Bt4tx-f3.js → format-helpers-vtahpXTQ.js} +1 -1
  17. package/assets/assets/{index-MbApCekj.js → index-BIhCeXvc.js} +4 -4
  18. package/assets/assets/{query-client-D-zMw63p.js → query-client-TlFXYJ9o.js} +1 -1
  19. package/assets/assets/{react-query-EdiRRB2q.js → react-query-C5Mv8xfD.js} +1 -1
  20. package/assets/assets/{react-sigma_core.esm.min-Bidr1Gxk.js → react-sigma_core.esm.min-DmggJ7YC.js} +1 -1
  21. package/assets/assets/{service-BUi8JgGI.js → service-CLFURPuM.js} +1 -1
  22. package/assets/index.html +7 -7
  23. package/dist/{ads-FFUUMS4J.js → ads-TX5622SS.js} +3 -3
  24. package/dist/{agent-LCD2VG7C.js → agent-AIOQL66U.js} +7 -7
  25. package/dist/{agent-ask-OBHTCYFR.js → agent-ask-A6GIJTBX.js} +3 -3
  26. package/dist/{agent-conversations-VMZ4NFIX.js → agent-conversations-LHWLKOPQ.js} +3 -3
  27. package/dist/{agent-memory-UPFJFNWC.js → agent-memory-F54BPEYN.js} +3 -3
  28. package/dist/{agent-providers-4GOWLBZK.js → agent-providers-L74KZOSG.js} +3 -3
  29. package/dist/{agent-transcript-RGXIVZUP.js → agent-transcript-IH65H755.js} +3 -3
  30. package/dist/{analytics-FBK4XV5P.js → analytics-YWCY2KSY.js} +3 -3
  31. package/dist/{apply-Y2DVE3YB.js → apply-BLUUYG2N.js} +3 -3
  32. package/dist/{backfill-7SGCPH6J.js → backfill-6WO5CH6Z.js} +9 -9
  33. package/dist/{backlinks-YWHFC7DZ.js → backlinks-NC7AUGTK.js} +3 -3
  34. package/dist/{bing-7BP3DWPK.js → bing-WQUEYHVC.js} +3 -3
  35. package/dist/{bootstrap-Z7QSKVPL.js → bootstrap-AXZV4BBC.js} +10 -10
  36. package/dist/{cdp-OL6RENO3.js → cdp-DUG5PMUD.js} +7 -7
  37. package/dist/{chunk-J523Y7X2.js → chunk-2Y6MSB4J.js} +1 -1
  38. package/dist/{chunk-YFITKHCV.js → chunk-3ANSG6YT.js} +345 -337
  39. package/dist/{chunk-GA2EHZTI.js → chunk-3WPTMLQI.js} +22 -6
  40. package/dist/{chunk-QDN3FL2A.js → chunk-3YIKSZHN.js} +2 -1
  41. package/dist/{chunk-H4HNXCDF.js → chunk-4B6DE7BB.js} +2 -2
  42. package/dist/{chunk-UWBJWKDQ.js → chunk-4JMTDLFV.js} +2 -2
  43. package/dist/{chunk-QKMGGM4B.js → chunk-5PA7SJ2M.js} +8 -271
  44. package/dist/{chunk-JO73L677.js → chunk-6ATKY252.js} +2 -2
  45. package/dist/{chunk-XR6ZVMYK.js → chunk-6W5AR4IW.js} +1 -1
  46. package/dist/{chunk-IZMT4WLZ.js → chunk-6YW24AUN.js} +2 -2
  47. package/dist/chunk-AZQNJX3T.js +269 -0
  48. package/dist/{chunk-TUVG7BIF.js → chunk-B6R223HQ.js} +8 -8
  49. package/dist/{chunk-6MYHGP46.js → chunk-DLVGMRM5.js} +1 -1
  50. package/dist/{chunk-P3UGNR2Y.js → chunk-ETVM3T7K.js} +5 -5
  51. package/dist/{chunk-IV6VZ63E.js → chunk-F5D4GPZQ.js} +18 -14
  52. package/dist/{chunk-WJ2JU32O.js → chunk-GNBATQS3.js} +23 -6
  53. package/dist/{chunk-TEDY3MHN.js → chunk-GUFKUPKZ.js} +3 -3
  54. package/dist/{chunk-BADJCT6U.js → chunk-GWDMWKM6.js} +1 -1
  55. package/dist/{chunk-PPM6Z7CM.js → chunk-HEL6DKDN.js} +1 -1
  56. package/dist/{chunk-DFCKSJQI.js → chunk-HGMTGC34.js} +4 -4
  57. package/dist/{chunk-GPTRCOKV.js → chunk-HIGBV77K.js} +259 -95
  58. package/dist/{chunk-NZZWJCKS.js → chunk-HJHFW455.js} +3 -3
  59. package/dist/{chunk-JE5QURTR.js → chunk-HKV4UWG5.js} +1 -1
  60. package/dist/{chunk-DRGCVTYH.js → chunk-JPM3VC6A.js} +1 -1
  61. package/dist/{chunk-TOX6HAQJ.js → chunk-JQNVNB63.js} +3 -3
  62. package/dist/{chunk-3AG3LPZX.js → chunk-MRSNLKSM.js} +1 -1
  63. package/dist/{chunk-O7WOCTBD.js → chunk-PAIYFNNY.js} +71 -3
  64. package/dist/{chunk-MJYO6UK2.js → chunk-PRSQ4R47.js} +2 -2
  65. package/dist/{chunk-JEBY6MS6.js → chunk-QS6RIP37.js} +1 -1
  66. package/dist/{chunk-4LTL5RNY.js → chunk-S77W2XSI.js} +4 -4
  67. package/dist/{chunk-YXAKL5HM.js → chunk-SF5JLMLG.js} +6791 -6777
  68. package/dist/{chunk-Q25JQANW.js → chunk-T5PWWDMJ.js} +17 -2
  69. package/dist/{chunk-ATT3ZCSS.js → chunk-WH2M2MQF.js} +38 -16
  70. package/dist/{chunk-7KOAP47B.js → chunk-WLWOGBLJ.js} +363 -248
  71. package/dist/{chunk-BZZDFIY2.js → chunk-XDQJOZKJ.js} +1 -1
  72. package/dist/{citations-RVSC67GE.js → citations-FUZ6DGP5.js} +3 -3
  73. package/dist/{cli-catalog-NEZE5QU5.js → cli-catalog-BXHG544D.js} +3 -3
  74. package/dist/{cli-commands-HGCYU4MQ.js → cli-commands-GMOR67F5.js} +7 -7
  75. package/dist/cli.js +13 -13
  76. package/dist/{competitor-BX3M3OYS.js → competitor-QDCH7PLT.js} +3 -3
  77. package/dist/{content-PKJMVMHJ.js → content-JX2CPIPR.js} +3 -3
  78. package/dist/{dashboard-SVHZBVM6.js → dashboard-OOWMLMKV.js} +6 -6
  79. package/dist/{demo-HYDPECCK.js → demo-GKSMSKOY.js} +1 -1
  80. package/dist/{demo-server-KEOO7WFO.js → demo-server-UQO4XKHN.js} +12 -11
  81. package/dist/{discover-JDP44ZHX.js → discover-YQSVQRUV.js} +3 -3
  82. package/dist/{discover-eval-6ORCVYYR.js → discover-eval-FN5RL6QI.js} +3 -3
  83. package/dist/{doctor-TVZRMBSS.js → doctor-YHJLAEJJ.js} +3 -3
  84. package/dist/{evidence-FNIAFBBG.js → evidence-KUPZMBIK.js} +3 -3
  85. package/dist/{export-cmd-HQNF2SSD.js → export-cmd-YSEPTUUF.js} +3 -3
  86. package/dist/{ga-PIO5OXMK.js → ga-WNS7Q7TF.js} +3 -3
  87. package/dist/{gbp-3R5FME43.js → gbp-5NYFK4TW.js} +3 -3
  88. package/dist/{google-BYZREX2O.js → google-T4CF4WCI.js} +4 -4
  89. package/dist/{google-marketing-SPQ2GW6X.js → google-marketing-IXPMUBXZ.js} +1 -1
  90. package/dist/{health-cmd-HH5RYMSV.js → health-cmd-2W37CF6J.js} +3 -3
  91. package/dist/{history-Q35NLLMJ.js → history-PA3O6ZHX.js} +3 -3
  92. package/dist/index.d.ts +248 -71
  93. package/dist/index.js +25 -24
  94. package/dist/{init-TV4ZKAAW.js → init-I3P7FINF.js} +12 -11
  95. package/dist/{insights-SH73B4PD.js → insights-O5PUVHTW.js} +3 -3
  96. package/dist/intelligence-service-EJQQNO65.js +16 -0
  97. package/dist/{journeys-SIV7HPW7.js → journeys-GU34O3HE.js} +3 -3
  98. package/dist/{keys-O656YWSW.js → keys-RXBFRNUS.js} +3 -3
  99. package/dist/{keyword-FZ2N4EW7.js → keyword-MASR36DK.js} +3 -3
  100. package/dist/{logs-2NPN7HBI.js → logs-OTA7MV4P.js} +3 -3
  101. package/dist/mcp-ZQYN2NET.js +19 -0
  102. package/dist/mcp.js +20 -14
  103. package/dist/{measurement-plan-JQKVSJRL.js → measurement-plan-ZGVO36TN.js} +5 -5
  104. package/dist/{notify-VTAYBHC6.js → notify-KS5CR3S2.js} +3 -3
  105. package/dist/{organic-evidence-HPXXEPOW.js → organic-evidence-CTH52AC5.js} +3 -3
  106. package/dist/{overview-FSBNDYZJ.js → overview-IRCIDE5H.js} +4 -4
  107. package/dist/{project-MAPPXURS.js → project-H5XPI5CT.js} +3 -3
  108. package/dist/{query-R6DLPIPJ.js → query-2R6EZG5T.js} +3 -3
  109. package/dist/{research-FXKOEUQB.js → research-OA3UQAV3.js} +3 -3
  110. package/dist/{results-export-X2PUM63S.js → results-export-XUXU3WMX.js} +3 -3
  111. package/dist/{run-6ENTG4IO.js → run-7IIOB6AS.js} +4 -4
  112. package/dist/{schedule-DMMVRT7P.js → schedule-DUTPZB5C.js} +3 -3
  113. package/dist/{search-FHI6APT7.js → search-TWUJD7KH.js} +3 -3
  114. package/dist/{serve-76BGQFPW.js → serve-BYHHULUU.js} +26 -25
  115. package/dist/{session-JBTIV7SS.js → session-M5XSTGPI.js} +13 -12
  116. package/dist/{settings-FMB4QED4.js → settings-GQXU5M3H.js} +3 -3
  117. package/dist/{skills-HBIMHSOI.js → skills-F6AXQHTO.js} +2 -2
  118. package/dist/{snapshot-RBA2EL7R.js → snapshot-QFKUO4QK.js} +3 -3
  119. package/dist/{src-BXXGJOQB.js → src-52USCS7O.js} +4 -2
  120. package/dist/{status-ATFDFAVG.js → status-42LPR7YH.js} +4 -4
  121. package/dist/{technical-aeo-JWQTGCTB.js → technical-aeo-SUILL4MY.js} +3 -3
  122. package/dist/{telemetry-6QFGJL2I.js → telemetry-RITB7YZH.js} +4 -4
  123. package/dist/{tools-4VRHKUBE.js → tools-DGWJOLNS.js} +11 -11
  124. package/dist/{traffic-5R7M4CK5.js → traffic-3YC3HUNT.js} +5 -5
  125. package/dist/{users-24TIUYJY.js → users-BST5DQ5R.js} +3 -3
  126. package/dist/{visibility-stats-YLQPPBJJ.js → visibility-stats-NCNP4AL2.js} +3 -3
  127. package/dist/{wordpress-7VDPHMUZ.js → wordpress-4HQDLQVE.js} +3 -3
  128. package/package.json +10 -6
  129. package/assets/assets/ToneBadge-CmvL5mFG.js +0 -60
  130. package/dist/intelligence-service-YNHDEY4M.js +0 -15
  131. package/dist/mcp-RHQY3DV6.js +0 -14
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  answerServiceAdapters,
3
3
  answerServiceDescriptors
4
- } from "./chunk-XR6ZVMYK.js";
4
+ } from "./chunk-6W5AR4IW.js";
5
5
  import {
6
6
  AeroLlmUsageFeatures,
7
7
  aeroTurnStatus,
@@ -18,7 +18,7 @@ import {
18
18
  isSystemMessage,
19
19
  loadAeroSystemPrompt,
20
20
  missingProviderMessage,
21
- readAeroViewEvidence,
21
+ readAeroViewEvidenceForTurn,
22
22
  resolveAeroModel,
23
23
  resolveAgentAllowViewers,
24
24
  resolveAgentEnabled,
@@ -27,14 +27,14 @@ import {
27
27
  resolveConfiguredAgentProvider,
28
28
  resolveSessionProviderAndModel,
29
29
  setAeroSystemPrompt
30
- } from "./chunk-WJ2JU32O.js";
30
+ } from "./chunk-GNBATQS3.js";
31
31
  import {
32
32
  AeroToolProfiles,
33
33
  AeroToolScopes,
34
34
  buildAeroStateTools,
35
35
  isAeroToolProfile,
36
36
  truncateToolResult
37
- } from "./chunk-P3UGNR2Y.js";
37
+ } from "./chunk-ETVM3T7K.js";
38
38
  import {
39
39
  getGoogleAuthConfig,
40
40
  getGoogleConnection,
@@ -53,7 +53,7 @@ import {
53
53
  removeCloudflareTrafficConnection,
54
54
  removeCloudflareTrafficConnectionBySourceId,
55
55
  upsertCloudflareTrafficConnection
56
- } from "./chunk-BZZDFIY2.js";
56
+ } from "./chunk-XDQJOZKJ.js";
57
57
  import {
58
58
  claudeAdapter,
59
59
  embedQueries,
@@ -64,7 +64,7 @@ import {
64
64
  openaiAdapter,
65
65
  openrouterAdapter,
66
66
  perplexityAdapter
67
- } from "./chunk-JO73L677.js";
67
+ } from "./chunk-6ATKY252.js";
68
68
  import {
69
69
  classifyUsageSurface,
70
70
  createApiUsageTelemetry,
@@ -76,7 +76,7 @@ import {
76
76
  startOutcomeTimer,
77
77
  trackFeatureCompleted,
78
78
  trackInstallState
79
- } from "./chunk-4LTL5RNY.js";
79
+ } from "./chunk-S77W2XSI.js";
80
80
  import {
81
81
  isLoopbackBindHost
82
82
  } from "./chunk-TSENU4GG.js";
@@ -84,7 +84,7 @@ import {
84
84
  isApiProviderRegistrable,
85
85
  isCdpProviderRegistrable,
86
86
  registeredProviderNames
87
- } from "./chunk-6MYHGP46.js";
87
+ } from "./chunk-DLVGMRM5.js";
88
88
  import {
89
89
  checkLatestVersionForServer,
90
90
  getOrCreateAnonymousId,
@@ -95,17 +95,17 @@ import {
95
95
  recordDashboardEvent,
96
96
  setTelemetryPreference,
97
97
  trackEvent
98
- } from "./chunk-MJYO6UK2.js";
98
+ } from "./chunk-PRSQ4R47.js";
99
99
  import {
100
100
  createCanonryMcpServer
101
- } from "./chunk-IV6VZ63E.js";
101
+ } from "./chunk-F5D4GPZQ.js";
102
102
  import {
103
103
  CANONRY_MCP_TIERS,
104
104
  CANONRY_MCP_TOOLKIT_NAMES
105
105
  } from "./chunk-NDTU7FGL.js";
106
106
  import {
107
107
  ApiClient
108
- } from "./chunk-ATT3ZCSS.js";
108
+ } from "./chunk-WH2M2MQF.js";
109
109
  import {
110
110
  AGENT_PROVIDERS,
111
111
  adapterSupportsBatch,
@@ -136,21 +136,21 @@ import {
136
136
  saveConfigPatch,
137
137
  sentimentInstallReadiness,
138
138
  updateSharedProviderExecutionGate
139
- } from "./chunk-JE5QURTR.js";
139
+ } from "./chunk-HKV4UWG5.js";
140
140
  import {
141
141
  getBundledSkillSnapshots
142
- } from "./chunk-PPM6Z7CM.js";
142
+ } from "./chunk-HEL6DKDN.js";
143
143
  import {
144
144
  computeFactorAverages,
145
145
  deleteSiteCrawlGraphLayout,
146
146
  persistSiteCrawlGraphLayout,
147
147
  prepareSiteCrawlGraphLayout,
148
148
  recordedSharePct
149
- } from "./chunk-IZMT4WLZ.js";
149
+ } from "./chunk-6YW24AUN.js";
150
150
  import {
151
151
  CanonryMcpToolNames,
152
152
  canonryMcpTools
153
- } from "./chunk-GA2EHZTI.js";
153
+ } from "./chunk-3WPTMLQI.js";
154
154
  import {
155
155
  PACKAGE_VERSION
156
156
  } from "./chunk-AOJU5LKX.js";
@@ -158,15 +158,17 @@ import {
158
158
  CliError
159
159
  } from "./chunk-HGMYEDAQ.js";
160
160
  import {
161
- IntelligenceService,
161
+ IntelligenceService
162
+ } from "./chunk-5PA7SJ2M.js";
163
+ import {
162
164
  addLogListener,
163
165
  createFastifyLogger,
164
166
  createLogger
165
- } from "./chunk-QKMGGM4B.js";
167
+ } from "./chunk-AZQNJX3T.js";
166
168
  import {
167
169
  computeCitedCompetitorDomains,
168
170
  determineCitationState
169
- } from "./chunk-DRGCVTYH.js";
171
+ } from "./chunk-JPM3VC6A.js";
170
172
  import {
171
173
  BingApiError,
172
174
  CC_CACHE_DIR,
@@ -179,6 +181,7 @@ import {
179
181
  GbpApiError,
180
182
  GoogleApiError,
181
183
  GoogleAuthError,
184
+ MCP_DELEGATED_KEY_MAX_AGE_MS,
182
185
  PLUGIN_DIR,
183
186
  SITE_REACHABILITY_CHECKS,
184
187
  SITE_REACHABILITY_CHECK_ID,
@@ -286,7 +289,7 @@ import {
286
289
  webhookResponseReason,
287
290
  webhookTargetRefusalReason,
288
291
  writeAuditLog
289
- } from "./chunk-7KOAP47B.js";
292
+ } from "./chunk-WLWOGBLJ.js";
290
293
  import {
291
294
  OperationalLogStore,
292
295
  SentimentIdempotencyConflict,
@@ -372,7 +375,7 @@ import {
372
375
  siteLivenessState,
373
376
  trafficSources,
374
377
  usageCounters
375
- } from "./chunk-O7WOCTBD.js";
378
+ } from "./chunk-PAIYFNNY.js";
376
379
  import {
377
380
  AGENT_MEMORY_VALUE_MAX_BYTES,
378
381
  AI_ENGINE_DOMAINS,
@@ -624,7 +627,7 @@ import {
624
627
  winnabilityClassLabel,
625
628
  withRetry,
626
629
  withSkippedProviders
627
- } from "./chunk-YXAKL5HM.js";
630
+ } from "./chunk-SF5JLMLG.js";
628
631
 
629
632
  // src/google-marketing-runtime.ts
630
633
  import crypto2 from "crypto";
@@ -3314,7 +3317,7 @@ import path5 from "path";
3314
3317
  import { isIP as isIP2 } from "net";
3315
3318
  import { fileURLToPath } from "url";
3316
3319
  import { setImmediate as yieldToEventLoop4 } from "timers/promises";
3317
- import { and as and26, eq as eq33, isNotNull as isNotNull5, isNull as isNull7, lte as lte3, max, ne as ne4, or as or4, sql as sql13 } from "drizzle-orm";
3320
+ import { and as and27, eq as eq33, isNotNull as isNotNull5, isNull as isNull8, lte as lte3, max, ne as ne4, or as or4, sql as sql13 } from "drizzle-orm";
3318
3321
 
3319
3322
  // src/seo-runtime.ts
3320
3323
  import { eq, inArray } from "drizzle-orm";
@@ -5807,7 +5810,7 @@ function nonBlank(value) {
5807
5810
  return trimmed ? trimmed : void 0;
5808
5811
  }
5809
5812
  function resolveBuildCommit(env = process.env) {
5810
- const embedded = true ? "f363ee51db531415324bfdb27933588afe17a5f3" : void 0;
5813
+ const embedded = true ? "a9c886130b3b0c74de10313ac5ebd1c0853664d0" : void 0;
5811
5814
  return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
5812
5815
  }
5813
5816
  function resolveInstanceIdentity(env = process.env) {
@@ -15636,8 +15639,7 @@ import { eq as eq27 } from "drizzle-orm";
15636
15639
 
15637
15640
  // src/agent/remote-mcp.ts
15638
15641
  import { Type } from "@earendil-works/pi-ai";
15639
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
15640
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
15642
+ import { Client, StreamableHTTPClientTransport } from "@modelcontextprotocol/client";
15641
15643
  var log24 = createLogger("RemoteMcp");
15642
15644
  var AERO_EXCLUDED_MCP_TOOLS = /* @__PURE__ */ new Set([]);
15643
15645
  async function connectStreamableHttp(server) {
@@ -15648,7 +15650,7 @@ async function connectStreamableHttp(server) {
15648
15650
  });
15649
15651
  const client = new Client(
15650
15652
  { name: "canonry-aero", version: "1.0.0" },
15651
- { capabilities: {} }
15653
+ { capabilities: {}, versionNegotiation: { mode: "auto" } }
15652
15654
  );
15653
15655
  await client.connect(transport);
15654
15656
  return client;
@@ -16381,7 +16383,7 @@ ${lines.join("\n")}
16381
16383
  this.assertTurnProviderUsable(projectId);
16382
16384
  await this.mergeExternalTools(agent);
16383
16385
  const view = { client: this.opts.client, projectName, basePath: this.opts.config.basePath, context: preferences?.context };
16384
- const evidence = preferences?.context ? await readAeroViewEvidence(view) : void 0;
16386
+ const evidence = preferences?.context ? await readAeroViewEvidenceForTurn(view, preferences?.signal) : void 0;
16385
16387
  preferences?.signal?.throwIfAborted();
16386
16388
  await this.maybeCompact(projectName, agent);
16387
16389
  preferences?.signal?.throwIfAborted();
@@ -16880,7 +16882,7 @@ var ViewerAeroSessions = class {
16880
16882
  const agent = this.sessions.get(key)?.agent ?? await this.createAgent(project, client, preferences.signal);
16881
16883
  agent.state.messages = trimViewerTranscript(agent.state.messages.filter((message) => message.role !== "system"));
16882
16884
  const view = { client, projectName: project.name, basePath: this.opts.config.basePath, context: preferences.context };
16883
- const evidence = preferences.context ? await readAeroViewEvidence(view) : void 0;
16885
+ const evidence = preferences.context ? await readAeroViewEvidenceForTurn(view, preferences.signal) : void 0;
16884
16886
  preferences.signal?.throwIfAborted();
16885
16887
  const shape = aeroProjectShape(this.opts.db, project.id);
16886
16888
  setAeroSystemPrompt(agent, loadAeroSystemPrompt(void 0, { extras: false }) + VIEWER_AERO_PROMPT + shape.prompt + aeroViewPrompt(preferences.context));
@@ -16969,12 +16971,15 @@ var ViewerAeroSessions = class {
16969
16971
  // src/mcp-http.ts
16970
16972
  import crypto25 from "crypto";
16971
16973
  import { isIP } from "net";
16972
- import { eq as eq29 } from "drizzle-orm";
16973
- import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
16974
- import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
16974
+ import { and as and24, eq as eq29, isNull as isNull6 } from "drizzle-orm";
16975
+ import { NodeStreamableHTTPServerTransport, toNodeHandler, toWebRequest } from "@modelcontextprotocol/node";
16976
+ import { McpServer, createMcpHandler, isInitializeRequest, isLegacyRequest } from "@modelcontextprotocol/server";
16975
16977
  var SESSION_IDLE_MS = 10 * 60 * 1e3;
16976
16978
  var SWEEP_INTERVAL_MS = 60 * 1e3;
16977
- function mintSessionKey(db, scopes, userId) {
16979
+ var MAX_CLEANUP_RETRIES_PER_SWEEP = 8;
16980
+ var MAX_PENDING_KEY_RETIREMENTS = 256;
16981
+ var MAX_CLEANUP_BACKOFF_MS = 10 * 60 * 1e3;
16982
+ function mintSessionKey(db, scopes, userId, oauthGrantId, createdAt) {
16978
16983
  const raw = `cnry_${crypto25.randomBytes(24).toString("hex")}`;
16979
16984
  const id = crypto25.randomUUID();
16980
16985
  db.insert(apiKeys).values({
@@ -16984,18 +16989,10 @@ function mintSessionKey(db, scopes, userId) {
16984
16989
  keyPrefix: raw.slice(0, 9),
16985
16990
  scopes: [...scopes],
16986
16991
  delegatedUserId: userId,
16987
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
16992
+ delegatedOAuthGrantId: oauthGrantId,
16993
+ createdAt: new Date(createdAt).toISOString()
16988
16994
  }).run();
16989
- return { id, raw };
16990
- }
16991
- function revokeSessionKey(db, id) {
16992
- try {
16993
- db.transaction((tx) => {
16994
- tx.delete(dashboardSessions).where(eq29(dashboardSessions.apiKeyId, id)).run();
16995
- tx.update(apiKeys).set({ revokedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq29(apiKeys.id, id)).run();
16996
- });
16997
- } catch {
16998
- }
16995
+ return { id, raw, expiresAt: createdAt + MCP_DELEGATED_KEY_MAX_AGE_MS };
16999
16996
  }
17000
16997
  function mcpTransportPaths() {
17001
16998
  const paths = ["/mcp", "/mcp/readonly"];
@@ -17050,18 +17047,95 @@ function mcpHttpHealth(app, apiPrefix, hosted) {
17050
17047
  }
17051
17048
  function registerMcpHttpRoutes(scope, opts) {
17052
17049
  const sessions = /* @__PURE__ */ new Map();
17050
+ const legacyServers = /* @__PURE__ */ new Set();
17051
+ const modernExchanges = /* @__PURE__ */ new Set();
17053
17052
  const now = opts.now ?? (() => Date.now());
17053
+ const pendingKeyRetirements = /* @__PURE__ */ new Map();
17054
+ let shuttingDown = false;
17055
+ function withoutLockWait(work) {
17056
+ const timeout = opts.db.$client.pragma("busy_timeout", { simple: true });
17057
+ try {
17058
+ opts.db.$client.pragma("busy_timeout = 0");
17059
+ return work();
17060
+ } finally {
17061
+ opts.db.$client.pragma(`busy_timeout = ${timeout}`);
17062
+ }
17063
+ }
17064
+ function attemptKeyRetirement(id, remove) {
17065
+ try {
17066
+ withoutLockWait(() => {
17067
+ opts.db.transaction((tx) => {
17068
+ tx.delete(dashboardSessions).where(eq29(dashboardSessions.apiKeyId, id)).run();
17069
+ tx.update(apiKeys).set({ revokedAt: new Date(now()).toISOString() }).where(and24(eq29(apiKeys.id, id), isNull6(apiKeys.revokedAt))).run();
17070
+ });
17071
+ if (remove) {
17072
+ try {
17073
+ opts.db.delete(apiKeys).where(eq29(apiKeys.id, id)).run();
17074
+ } catch (error) {
17075
+ scope.log.warn({ err: error, keyId: id }, "Retained revoked MCP request key after deletion failed");
17076
+ }
17077
+ }
17078
+ });
17079
+ return true;
17080
+ } catch (error) {
17081
+ scope.log.error({ err: error, keyId: id }, "Failed to retire MCP key; cleanup remains bounded by its expiry");
17082
+ return false;
17083
+ }
17084
+ }
17085
+ function retireSessionKey(key, remove = false) {
17086
+ const queued = pendingKeyRetirements.get(key.id);
17087
+ if (queued) {
17088
+ queued.remove ||= remove;
17089
+ return;
17090
+ }
17091
+ if (attemptKeyRetirement(key.id, remove)) return;
17092
+ if (pendingKeyRetirements.size >= MAX_PENDING_KEY_RETIREMENTS) {
17093
+ const oldest = pendingKeyRetirements.keys().next().value;
17094
+ if (oldest !== void 0) pendingKeyRetirements.delete(oldest);
17095
+ scope.log.warn("MCP cleanup queue is full; oldest credential remains bounded by its expiry");
17096
+ }
17097
+ pendingKeyRetirements.set(key.id, { remove, expiresAt: key.expiresAt, nextAttemptAt: now() + SWEEP_INTERVAL_MS, attempts: 1 });
17098
+ }
17099
+ function retryKeyRetirements() {
17100
+ let attempted = 0;
17101
+ for (const [id, queued] of pendingKeyRetirements) {
17102
+ if (queued.expiresAt <= now()) {
17103
+ pendingKeyRetirements.delete(id);
17104
+ continue;
17105
+ }
17106
+ if (queued.nextAttemptAt > now()) continue;
17107
+ if (attempted++ >= MAX_CLEANUP_RETRIES_PER_SWEEP) break;
17108
+ if (attemptKeyRetirement(id, queued.remove)) pendingKeyRetirements.delete(id);
17109
+ else {
17110
+ queued.nextAttemptAt = now() + Math.min(SWEEP_INTERVAL_MS * 2 ** queued.attempts, MAX_CLEANUP_BACKOFF_MS);
17111
+ queued.attempts++;
17112
+ }
17113
+ }
17114
+ }
17054
17115
  async function dropSession(id) {
17055
- const session = sessions.get(id);
17056
- if (!session) return;
17057
- sessions.delete(id);
17058
- await session.close().catch(() => {
17059
- });
17116
+ await sessions.get(id)?.close().catch((error) => scope.log.error({ err: error }, "Failed to close legacy MCP session"));
17060
17117
  }
17061
17118
  const sweep = setInterval(() => {
17062
- const cutoff = now() - SESSION_IDLE_MS;
17063
- for (const [id, session] of sessions) {
17064
- if (session.lastSeenAt < cutoff) void dropSession(id);
17119
+ try {
17120
+ retryKeyRetirements();
17121
+ withoutLockWait(() => {
17122
+ const cutoff = now() - SESSION_IDLE_MS;
17123
+ for (const session of legacyServers) {
17124
+ const key = session.sessionKeyId ? opts.db.select({ revokedAt: apiKeys.revokedAt }).from(apiKeys).where(eq29(apiKeys.id, session.sessionKeyId)).get() : void 0;
17125
+ if (session.lastSeenAt < cutoff || session.expiresAt !== void 0 && session.expiresAt <= now() || session.sessionKeyId && (!key || key.revokedAt)) {
17126
+ void session.close().catch((error) => scope.log.error({ err: error }, "Failed to close expired MCP session"));
17127
+ }
17128
+ }
17129
+ for (const exchange of modernExchanges) {
17130
+ if (!exchange.sessionKey) continue;
17131
+ const key = opts.db.select({ revokedAt: apiKeys.revokedAt }).from(apiKeys).where(eq29(apiKeys.id, exchange.sessionKey.id)).get();
17132
+ if (!key || key.revokedAt || exchange.sessionKey.expiresAt <= now()) {
17133
+ void exchange.close().catch((error) => scope.log.error({ err: error }, "Failed to close expired MCP request"));
17134
+ }
17135
+ }
17136
+ });
17137
+ } catch (error) {
17138
+ scope.log.error({ err: error }, "MCP lifecycle sweep failed; will retry on the next interval");
17065
17139
  }
17066
17140
  }, SWEEP_INTERVAL_MS);
17067
17141
  sweep.unref();
@@ -17075,9 +17149,15 @@ function registerMcpHttpRoutes(scope, opts) {
17075
17149
  return payload;
17076
17150
  });
17077
17151
  }
17078
- scope.addHook("onClose", async () => {
17152
+ scope.addHook("preClose", async () => {
17153
+ shuttingDown = true;
17079
17154
  clearInterval(sweep);
17080
- await Promise.all([...sessions.keys()].map((id) => dropSession(id)));
17155
+ await Promise.all([...legacyServers].map((session) => session.close().catch((error) => scope.log.error({ err: error }, "Failed to close MCP session during shutdown"))));
17156
+ await Promise.all([...modernExchanges].map((exchange) => exchange.close().catch((error) => scope.log.error({ err: error }, "Failed to close MCP request during shutdown"))));
17157
+ retryKeyRetirements();
17158
+ if (pendingKeyRetirements.size > 0) {
17159
+ scope.log.warn({ count: pendingKeyRetirements.size }, "MCP credential cleanup remains pending at shutdown; credentials remain bounded by expiry");
17160
+ }
17081
17161
  });
17082
17162
  function callerBearer(request) {
17083
17163
  const header = request.headers.authorization;
@@ -17088,53 +17168,74 @@ function registerMcpHttpRoutes(scope, opts) {
17088
17168
  if (trimmed.slice(0, prefix.length).toLowerCase() !== prefix) return null;
17089
17169
  return trimmed.slice(prefix.length).trim() || null;
17090
17170
  }
17091
- async function openSession(request, authorizationId, segment) {
17092
- const bearer = callerBearer(request);
17093
- if (!bearer) return null;
17171
+ function createAuthorizedServer(request, segment, bearer, signal, modern = false, needsApiCredential = true) {
17172
+ if (shuttingDown) throw new Error("MCP server is shutting down");
17094
17173
  const scopes = request.principal?.scopes ?? request.apiKey?.scopes ?? [];
17095
17174
  let sessionKey = null;
17096
- if (!request.apiKey && request.principal?.kind === "user") {
17097
- sessionKey = mintSessionKey(opts.db, scopes, request.principal.id);
17175
+ if (needsApiCredential && !request.apiKey && request.principal?.kind === "user") {
17176
+ if (!request.principal.oauthGrantId) throw forbidden("MCP OAuth credentials require an active authorization grant.");
17177
+ sessionKey = mintSessionKey(opts.db, segment.readOnly ? ["read"] : scopes, request.principal.id, request.principal.oauthGrantId, now());
17098
17178
  }
17099
17179
  const client = new ApiClient(opts.selfApiUrl, sessionKey?.raw ?? bearer, {
17100
17180
  skipProbe: true,
17181
+ storedOnly: segment.readOnly,
17182
+ signal,
17101
17183
  clientName: `canonry-mcp/${PACKAGE_VERSION}`,
17102
17184
  surface: "mcp-http",
17103
17185
  // Correlation only: this is never accepted as caller identity or authority.
17104
- actorSession: crypto25.randomUUID()
17186
+ ...modern ? {} : { actorSession: crypto25.randomUUID() }
17105
17187
  });
17106
17188
  let server;
17107
17189
  try {
17108
17190
  server = createCanonryMcpServer({
17109
- scope: segment.readOnly || isReadOnlyKey(scopes) ? "read-only" : "all",
17191
+ scope: segment.readOnly ? "stored-only" : isReadOnlyKey(scopes) ? "read-only" : "all",
17110
17192
  credentialScopes: scopes,
17111
17193
  operator: request.operatorAccess === true,
17194
+ connectionProfile: Boolean(opts.issuer && !request.principal?.projectId && (request.principal?.kind === "user" || request.principal?.delegatedUser) && scopes.some((scope2) => scope2 === "read" || scope2 === "*")),
17112
17195
  tiers: segment.tiers,
17113
17196
  clientFactory: () => client,
17114
17197
  updateAvailable: opts.getUpdateAvailable
17115
17198
  });
17199
+ server.server.registerCapabilities({ tools: { listChanged: false }, resources: { listChanged: false, subscribe: false } });
17116
17200
  } catch (error) {
17117
- if (sessionKey) revokeSessionKey(opts.db, sessionKey.id);
17201
+ if (sessionKey) retireSessionKey(sessionKey, modern);
17118
17202
  throw error;
17119
17203
  }
17120
- const transport = new StreamableHTTPServerTransport({
17204
+ return { server, sessionKey };
17205
+ }
17206
+ async function openSession(request, authorizationId, segment) {
17207
+ const bearer = callerBearer(request);
17208
+ if (!bearer) return null;
17209
+ const { server, sessionKey } = createAuthorizedServer(request, segment, bearer);
17210
+ const transport = new NodeStreamableHTTPServerTransport({
17121
17211
  sessionIdGenerator: () => crypto25.randomUUID(),
17122
17212
  onsessioninitialized: (id) => {
17123
- sessions.set(id, { transport, close, authorizationId, segmentId: segment.id, lastSeenAt: now() });
17213
+ if (!shuttingDown && !closing) sessions.set(id, session);
17124
17214
  }
17125
17215
  });
17126
- async function close() {
17127
- if (sessionKey) revokeSessionKey(opts.db, sessionKey.id);
17128
- try {
17129
- await transport.close();
17130
- } finally {
17131
- await server.close();
17132
- }
17216
+ let closing;
17217
+ const session = { transport, close, authorizationId, segmentId: segment.id, sessionKeyId: sessionKey?.id, expiresAt: sessionKey?.expiresAt, lastSeenAt: now() };
17218
+ legacyServers.add(session);
17219
+ function close() {
17220
+ if (closing) return closing;
17221
+ closing = Promise.resolve().then(async () => {
17222
+ if (sessionKey) retireSessionKey(sessionKey);
17223
+ const id = transport.sessionId;
17224
+ if (id) sessions.delete(id);
17225
+ try {
17226
+ await transport.close();
17227
+ } finally {
17228
+ try {
17229
+ await server.close();
17230
+ } finally {
17231
+ legacyServers.delete(session);
17232
+ }
17233
+ }
17234
+ });
17235
+ return closing;
17133
17236
  }
17134
17237
  transport.onclose = () => {
17135
- const id = transport.sessionId;
17136
- if (id) sessions.delete(id);
17137
- if (sessionKey) revokeSessionKey(opts.db, sessionKey.id);
17238
+ void close().catch((error) => scope.log.error({ err: error }, "Failed to close legacy MCP transport"));
17138
17239
  };
17139
17240
  try {
17140
17241
  await server.connect(transport);
@@ -17143,15 +17244,68 @@ function registerMcpHttpRoutes(scope, opts) {
17143
17244
  });
17144
17245
  throw error;
17145
17246
  }
17146
- return { transport, close, authorizationId, segmentId: segment.id, lastSeenAt: now() };
17247
+ return session;
17248
+ }
17249
+ async function handleModern(request, reply, segment, bearer) {
17250
+ const abort = new AbortController();
17251
+ let closing;
17252
+ const exchange = {
17253
+ close: () => {
17254
+ if (closing) return closing;
17255
+ abort.abort();
17256
+ if (exchange.sessionKey) retireSessionKey(exchange.sessionKey, true);
17257
+ modernExchanges.delete(exchange);
17258
+ closing = handler.close().catch((error) => {
17259
+ scope.log.error({ err: error }, "Failed to close MCP request transport");
17260
+ throw error;
17261
+ });
17262
+ return closing;
17263
+ }
17264
+ };
17265
+ const reportError = (error) => scope.log.error({ err: error }, "Modern MCP request failed");
17266
+ const handler = createMcpHandler(({ requestInfo }) => {
17267
+ if (shuttingDown) throw new Error("MCP server is shutting down");
17268
+ const body = request.body;
17269
+ const method = body && typeof body === "object" ? body.method : void 0;
17270
+ if (method === "subscriptions/listen") {
17271
+ return new McpServer({ name: "canonry", version: PACKAGE_VERSION });
17272
+ }
17273
+ const signal = requestInfo ? AbortSignal.any([abort.signal, requestInfo.signal]) : abort.signal;
17274
+ const opened = createAuthorizedServer(request, segment, bearer, signal, true, method === "tools/call");
17275
+ exchange.sessionKey = opened.sessionKey ?? void 0;
17276
+ return opened.server;
17277
+ }, { legacy: "reject", onerror: reportError });
17278
+ modernExchanges.add(exchange);
17279
+ try {
17280
+ await toNodeHandler(handler, { onerror: reportError })(request.raw, reply.raw, request.body);
17281
+ } finally {
17282
+ await exchange.close();
17283
+ }
17147
17284
  }
17148
17285
  async function handle(request, reply, segment) {
17286
+ if (shuttingDown) {
17287
+ await reply.status(503).send({ jsonrpc: "2.0", id: null, error: { code: -32e3, message: "MCP server is shutting down." } });
17288
+ return;
17289
+ }
17149
17290
  const principal = request.principal ?? request.apiKey;
17150
17291
  const bearer = callerBearer(request);
17151
17292
  if (!principal || !bearer) {
17152
17293
  await reply.status(401).send({ error: { code: "AUTH_REQUIRED", message: "Authentication required." } });
17153
17294
  return;
17154
17295
  }
17296
+ if (segment.readOnly && !request.apiKey && request.principal?.kind === "user" && !principal.scopes.some((scope2) => scope2 === "read" || scope2 === "*")) {
17297
+ throw forbidden('The hosted read-only MCP endpoint requires the "read" scope.');
17298
+ }
17299
+ const webRequest = await toWebRequest(request.raw, request.body);
17300
+ const legacy = await isLegacyRequest(webRequest, request.body);
17301
+ if (shuttingDown) {
17302
+ await reply.status(503).send({ jsonrpc: "2.0", id: null, error: { code: -32e3, message: "MCP server is shutting down." } });
17303
+ return;
17304
+ }
17305
+ if (!legacy) {
17306
+ await handleModern(request, reply, segment, bearer);
17307
+ return;
17308
+ }
17155
17309
  const authorizationId = hashApiKey(JSON.stringify({
17156
17310
  bearerHash: hashApiKey(bearer),
17157
17311
  kind: request.principal?.kind ?? "api-key",
@@ -17163,6 +17317,11 @@ function registerMcpHttpRoutes(scope, opts) {
17163
17317
  const sessionId = request.headers["mcp-session-id"];
17164
17318
  const existing = typeof sessionId === "string" ? sessions.get(sessionId) : void 0;
17165
17319
  if (existing) {
17320
+ if (existing.expiresAt !== void 0 && existing.expiresAt <= now() && typeof sessionId === "string") {
17321
+ await dropSession(sessionId);
17322
+ await reply.status(404).send({ error: { code: "NOT_FOUND", message: "Unknown MCP session." } });
17323
+ return;
17324
+ }
17166
17325
  if (existing.authorizationId !== authorizationId || existing.segmentId !== segment.id) {
17167
17326
  await reply.status(404).send({ error: { code: "NOT_FOUND", message: "Unknown MCP session." } });
17168
17327
  return;
@@ -17184,6 +17343,11 @@ function registerMcpHttpRoutes(scope, opts) {
17184
17343
  await reply.status(401).send({ error: { code: "AUTH_REQUIRED", message: "Authentication required." } });
17185
17344
  return;
17186
17345
  }
17346
+ if (shuttingDown) {
17347
+ await opened.close();
17348
+ await reply.status(503).send({ jsonrpc: "2.0", id: null, error: { code: -32e3, message: "MCP server is shutting down." } });
17349
+ return;
17350
+ }
17187
17351
  let handled = false;
17188
17352
  try {
17189
17353
  await opened.transport.handleRequest(request.raw, reply.raw, request.body);
@@ -18399,7 +18563,7 @@ function clipText(value, length) {
18399
18563
  }
18400
18564
 
18401
18565
  // src/research-runner.ts
18402
- import { and as and24, eq as eq31, inArray as inArray13, sql as sql11 } from "drizzle-orm";
18566
+ import { and as and25, eq as eq31, inArray as inArray13, sql as sql11 } from "drizzle-orm";
18403
18567
  var unfinishedResearchQueryStatuses = [ResearchQueryStatuses.queued, ResearchQueryStatuses.running];
18404
18568
  function finalResearchRunStatus(completed, failed, waiting) {
18405
18569
  if (waiting > 0) return ResearchRunStatuses["waiting-upstream"];
@@ -18407,13 +18571,13 @@ function finalResearchRunStatus(completed, failed, waiting) {
18407
18571
  return completed > 0 ? ResearchRunStatuses.partial : ResearchRunStatuses.failed;
18408
18572
  }
18409
18573
  async function executeResearchRun(db, registry, runId, projectId, options = {}) {
18410
- const run = db.select().from(researchRuns).where(and24(eq31(researchRuns.id, runId), eq31(researchRuns.projectId, projectId))).get();
18574
+ const run = db.select().from(researchRuns).where(and25(eq31(researchRuns.id, runId), eq31(researchRuns.projectId, projectId))).get();
18411
18575
  if (!run || run.status !== ResearchRunStatuses.queued) return;
18412
18576
  const project = db.select().from(projects).where(eq31(projects.id, projectId)).get();
18413
18577
  if (!project) return;
18414
18578
  const provider = registry.get(run.provider);
18415
18579
  const now = (/* @__PURE__ */ new Date()).toISOString();
18416
- const claim = db.update(researchRuns).set({ status: ResearchRunStatuses.running, startedAt: now }).where(and24(eq31(researchRuns.id, runId), eq31(researchRuns.status, ResearchRunStatuses.queued))).run();
18580
+ const claim = db.update(researchRuns).set({ status: ResearchRunStatuses.running, startedAt: now }).where(and25(eq31(researchRuns.id, runId), eq31(researchRuns.status, ResearchRunStatuses.queued))).run();
18417
18581
  if (claim.changes !== 1) return;
18418
18582
  const elapsed = startOutcomeTimer();
18419
18583
  const requested = currentOutcomeOrigin();
@@ -18458,7 +18622,7 @@ async function executeResearchRun(db, registry, runId, projectId, options = {})
18458
18622
  await mapWithConcurrency(rows, Math.max(1, provider.config.quotaPolicy.maxConcurrency), async (row) => {
18459
18623
  try {
18460
18624
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
18461
- db.update(researchRunQueries).set({ status: ResearchQueryStatuses.running, startedAt }).where(and24(eq31(researchRunQueries.id, row.id), eq31(researchRunQueries.status, ResearchQueryStatuses.queued))).run();
18625
+ db.update(researchRunQueries).set({ status: ResearchQueryStatuses.running, startedAt }).where(and25(eq31(researchRunQueries.id, row.id), eq31(researchRunQueries.status, ResearchQueryStatuses.queued))).run();
18462
18626
  const raw = await gate.run(async () => {
18463
18627
  dispatched++;
18464
18628
  return provider.adapter.executeTrackedQuery({ query: row.queryText, canonicalDomains: domains, competitorDomains, ...run.location ? { location: run.location } : {} }, config);
@@ -18489,7 +18653,7 @@ async function executeResearchRun(db, registry, runId, projectId, options = {})
18489
18653
  rawResponse: raw.rawResponse,
18490
18654
  answerEvidence: raw.evidence ?? null,
18491
18655
  finishedAt: (/* @__PURE__ */ new Date()).toISOString()
18492
- }).where(and24(eq31(researchRunQueries.id, row.id), eq31(researchRunQueries.status, ResearchQueryStatuses.running))).run();
18656
+ }).where(and25(eq31(researchRunQueries.id, row.id), eq31(researchRunQueries.status, ResearchQueryStatuses.running))).run();
18493
18657
  if (completed.changes === 1) incrementResearchProgress(db, runId, "completedQueries");
18494
18658
  } catch (error) {
18495
18659
  if (!(error instanceof IncompleteAnswerError && error.resumable)) queryFailure ??= error;
@@ -18544,7 +18708,7 @@ function incrementResearchProgress(db, runId, column) {
18544
18708
  }
18545
18709
  function markResearchQueryFailed(db, runId, queryId, error) {
18546
18710
  const message = describeError(error);
18547
- const unfinished = and24(eq31(researchRunQueries.id, queryId), inArray13(researchRunQueries.status, unfinishedResearchQueryStatuses));
18711
+ const unfinished = and25(eq31(researchRunQueries.id, queryId), inArray13(researchRunQueries.status, unfinishedResearchQueryStatuses));
18548
18712
  if (error instanceof IncompleteAnswerError && error.resumable) {
18549
18713
  db.update(researchRunQueries).set({
18550
18714
  status: ResearchQueryStatuses["waiting-upstream"],
@@ -18560,7 +18724,7 @@ function markResearchQueryFailed(db, runId, queryId, error) {
18560
18724
  if (failed.changes === 1) incrementResearchProgress(db, runId, "failedQueries");
18561
18725
  }
18562
18726
  function markUnfinishedResearchQueriesFailed(db, runId, error) {
18563
- db.update(researchRunQueries).set({ status: ResearchQueryStatuses.failed, error, finishedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(and24(eq31(researchRunQueries.researchRunId, runId), inArray13(researchRunQueries.status, unfinishedResearchQueryStatuses))).run();
18727
+ db.update(researchRunQueries).set({ status: ResearchQueryStatuses.failed, error, finishedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(and25(eq31(researchRunQueries.researchRunId, runId), inArray13(researchRunQueries.status, unfinishedResearchQueryStatuses))).run();
18564
18728
  }
18565
18729
  function finalizeResearchRun(db, runId, fatalError) {
18566
18730
  const rows = db.select({ status: researchRunQueries.status }).from(researchRunQueries).where(eq31(researchRunQueries.researchRunId, runId)).all();
@@ -18580,7 +18744,7 @@ function finalizeResearchRun(db, runId, fatalError) {
18580
18744
  }
18581
18745
 
18582
18746
  // src/google-marketing-sync.ts
18583
- import { and as and25, eq as eq32, isNull as isNull6, sql as sql12 } from "drizzle-orm";
18747
+ import { and as and26, eq as eq32, isNull as isNull7, sql as sql12 } from "drizzle-orm";
18584
18748
  var RUNTIME_FAILURE_REASONS = {
18585
18749
  INVALID_INPUT: OutcomeReasonCodes.VALIDATION,
18586
18750
  NOT_CONFIGURED: OutcomeReasonCodes.NOT_CONNECTED,
@@ -18617,7 +18781,7 @@ function assertSnapshotContext(metadata, expected) {
18617
18781
  }
18618
18782
  }
18619
18783
  function requireSyncRun(db, runId, projectId, kind) {
18620
- const run = db.select().from(runs).where(and25(
18784
+ const run = db.select().from(runs).where(and26(
18621
18785
  eq32(runs.id, runId),
18622
18786
  eq32(runs.projectId, projectId),
18623
18787
  eq32(runs.kind, kind)
@@ -18636,7 +18800,7 @@ function markFailed(db, runId, projectId, kind, expectedStatus, error) {
18636
18800
  status: RunStatuses.failed,
18637
18801
  error: serializeRunError({ message: safeErrorMessage(error) }),
18638
18802
  finishedAt: (/* @__PURE__ */ new Date()).toISOString()
18639
- }).where(and25(
18803
+ }).where(and26(
18640
18804
  eq32(runs.id, runId),
18641
18805
  eq32(runs.projectId, projectId),
18642
18806
  eq32(runs.kind, kind),
@@ -18644,7 +18808,7 @@ function markFailed(db, runId, projectId, kind, expectedStatus, error) {
18644
18808
  )).run();
18645
18809
  }
18646
18810
  function claimSyncRun(db, runId, projectId, kind, startedAt) {
18647
- const claim = db.update(runs).set({ status: RunStatuses.running, startedAt, error: null }).where(and25(
18811
+ const claim = db.update(runs).set({ status: RunStatuses.running, startedAt, error: null }).where(and26(
18648
18812
  eq32(runs.id, runId),
18649
18813
  eq32(runs.projectId, projectId),
18650
18814
  eq32(runs.kind, kind),
@@ -18712,7 +18876,7 @@ async function executeGoogleAdsMarketingSync(db, runtime, runId, projectId) {
18712
18876
  status: RunStatuses.completed,
18713
18877
  finishedAt,
18714
18878
  error: null
18715
- }).where(and25(
18879
+ }).where(and26(
18716
18880
  eq32(runs.id, runId),
18717
18881
  eq32(runs.projectId, projectId),
18718
18882
  eq32(runs.kind, RunKinds["google-ads-sync"]),
@@ -18736,11 +18900,11 @@ async function executeGoogleAdsMarketingSync(db, runtime, runId, projectId) {
18736
18900
  lastMetricsSnapshotAt: result.metrics?.metadata.capturedAt ?? connection.lastMetricsSnapshotAt,
18737
18901
  lastMetricsSnapshotId: result.metrics?.metadata.id ?? connection.lastMetricsSnapshotId,
18738
18902
  updatedAt: finishedAt
18739
- }).where(and25(
18903
+ }).where(and26(
18740
18904
  eq32(googleAdsConnections.id, connection.id),
18741
18905
  eq32(googleAdsConnections.projectId, projectId),
18742
18906
  eq32(googleAdsConnections.selectedCustomerId, connection.selectedCustomerId),
18743
- connection.selectedLoginCustomerId === null ? isNull6(googleAdsConnections.selectedLoginCustomerId) : eq32(googleAdsConnections.selectedLoginCustomerId, connection.selectedLoginCustomerId),
18907
+ connection.selectedLoginCustomerId === null ? isNull7(googleAdsConnections.selectedLoginCustomerId) : eq32(googleAdsConnections.selectedLoginCustomerId, connection.selectedLoginCustomerId),
18744
18908
  eq32(googleAdsConnections.selectionGeneration, connection.selectionGeneration)
18745
18909
  )).run();
18746
18910
  if (connectionClaim.changes !== 1) {
@@ -18821,7 +18985,7 @@ async function executeGtmMarketingSync(db, runtime, runId, projectId) {
18821
18985
  status: RunStatuses.completed,
18822
18986
  finishedAt,
18823
18987
  error: null
18824
- }).where(and25(
18988
+ }).where(and26(
18825
18989
  eq32(runs.id, runId),
18826
18990
  eq32(runs.projectId, projectId),
18827
18991
  eq32(runs.kind, RunKinds["gtm-sync"]),
@@ -18846,12 +19010,12 @@ async function executeGtmMarketingSync(db, runtime, runId, projectId) {
18846
19010
  lastSnapshotAt: snapshot.metadata.capturedAt,
18847
19011
  lastSnapshotId: snapshot.metadata.id,
18848
19012
  updatedAt: finishedAt
18849
- }).where(and25(
19013
+ }).where(and26(
18850
19014
  eq32(gtmConnections.id, connection.id),
18851
19015
  eq32(gtmConnections.projectId, projectId),
18852
19016
  eq32(gtmConnections.selectedAccountId, connection.selectedAccountId),
18853
19017
  eq32(gtmConnections.selectedContainerId, connection.selectedContainerId),
18854
- connection.selectedWorkspaceId === null ? isNull6(gtmConnections.selectedWorkspaceId) : eq32(gtmConnections.selectedWorkspaceId, connection.selectedWorkspaceId),
19018
+ connection.selectedWorkspaceId === null ? isNull7(gtmConnections.selectedWorkspaceId) : eq32(gtmConnections.selectedWorkspaceId, connection.selectedWorkspaceId),
18855
19019
  eq32(gtmConnections.selectionGeneration, connection.selectionGeneration)
18856
19020
  )).run();
18857
19021
  if (connectionClaim.changes !== 1) {
@@ -20260,13 +20424,13 @@ async function createServer(opts) {
20260
20424
  const currentPasswordFingerprint = () => hashSessionToken(opts.config.dashboardPasswordHash ?? "");
20261
20425
  opts.db.delete(dashboardSessions).where(or4(
20262
20426
  eq33(dashboardSessions.apiKeyHash, ""),
20263
- and26(
20427
+ and27(
20264
20428
  isNotNull5(dashboardSessions.passwordFingerprint),
20265
20429
  ne4(dashboardSessions.passwordFingerprint, currentPasswordFingerprint())
20266
20430
  )
20267
20431
  )).run();
20268
20432
  if (!opts.config.dashboardPasswordHash) {
20269
- const lastPasswordEventAt = (action) => opts.db.select({ at: max(auditLog.createdAt) }).from(auditLog).where(and26(eq33(auditLog.entityType, "dashboard-password"), eq33(auditLog.action, action))).get()?.at ?? null;
20433
+ const lastPasswordEventAt = (action) => opts.db.select({ at: max(auditLog.createdAt) }).from(auditLog).where(and27(eq33(auditLog.entityType, "dashboard-password"), eq33(auditLog.action, action))).get()?.at ?? null;
20270
20434
  const createdAt = lastPasswordEventAt("dashboard-password.created");
20271
20435
  const clearedAt = lastPasswordEventAt("dashboard-password.cleared");
20272
20436
  if (createdAt !== null && (clearedAt === null || clearedAt < createdAt)) {
@@ -20300,7 +20464,7 @@ async function createServer(opts) {
20300
20464
  currentApiKeyHash: apiKeys.keyHash,
20301
20465
  passwordFingerprint: dashboardSessions.passwordFingerprint,
20302
20466
  expiresAt: dashboardSessions.expiresAt
20303
- }).from(dashboardSessions).innerJoin(apiKeys, eq33(apiKeys.id, dashboardSessions.apiKeyId)).where(and26(eq33(dashboardSessions.tokenHash, tokenHash), isNull7(apiKeys.revokedAt))).get();
20467
+ }).from(dashboardSessions).innerJoin(apiKeys, eq33(apiKeys.id, dashboardSessions.apiKeyId)).where(and27(eq33(dashboardSessions.tokenHash, tokenHash), isNull8(apiKeys.revokedAt))).get();
20304
20468
  if (!session) return null;
20305
20469
  const expiresAt = Date.parse(session.expiresAt);
20306
20470
  if (!Number.isFinite(expiresAt) || expiresAt <= Date.now() || session.apiKeyHash !== session.currentApiKeyHash || session.passwordFingerprint !== null && session.passwordFingerprint !== currentPasswordFingerprint()) {
@@ -20579,7 +20743,7 @@ async function createServer(opts) {
20579
20743
  opts.db.update(projects).set({ answerFieldsRecompute: null }).where(eq33(projects.id, projectId)).run();
20580
20744
  if (recomputeDebts.get(projectId) === debt) recomputeDebts.delete(projectId);
20581
20745
  } else if (debt.latestFull === 0) {
20582
- opts.db.update(projects).set({ answerFieldsRecompute: "competitors" }).where(and26(eq33(projects.id, projectId), eq33(projects.answerFieldsRecompute, "full"))).run();
20746
+ opts.db.update(projects).set({ answerFieldsRecompute: "competitors" }).where(and27(eq33(projects.id, projectId), eq33(projects.answerFieldsRecompute, "full"))).run();
20583
20747
  }
20584
20748
  } catch (err) {
20585
20749
  app.log.error({ err, projectId }, "could not clear the owed answer field recompute");