@canonry/canonry 7.98.0 → 7.99.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 (134) hide show
  1. package/assets/agent-workspace/skills/aero/references/site-health.md +11 -1
  2. package/assets/assets/{AgentSetupPage-h1kJhy9q.js → AgentSetupPage-yOqSVJ-e.js} +1 -1
  3. package/assets/assets/{AuditHistoryPanel-CNUApNiJ.js → AuditHistoryPanel-CiTzFgbw.js} +1 -1
  4. package/assets/assets/{BacklinksPage-CpKmlAek.js → BacklinksPage-DmRdQsFQ.js} +1 -1
  5. package/assets/assets/{HistoryPage-DeN79d3c.js → HistoryPage-DNE76LNh.js} +1 -1
  6. package/assets/assets/{MeasurementPropertyPage-CcHnYn81.js → MeasurementPropertyPage-Cx64Fnmz.js} +1 -1
  7. package/assets/assets/{ProjectPage-Tmuqmust.js → ProjectPage-DNfgC82V.js} +1 -1
  8. package/assets/assets/{RunsPage-BD4k3MjX.js → RunsPage-BmPKBKKr.js} +1 -1
  9. package/assets/assets/{SettingsPage-BHy30JP5.js → SettingsPage-Dl0TNeVK.js} +1 -1
  10. package/assets/assets/{SiteHealthSection-SYdtuGjq.js → SiteHealthSection-DxQPaR--.js} +2 -2
  11. package/assets/assets/{ToneBadge-Cii5KNtg.js → ToneBadge-BhjTBHi-.js} +1 -1
  12. package/assets/assets/{TrafficPage-DuxtRqnc.js → TrafficPage-CJp0pS01.js} +1 -1
  13. package/assets/assets/{TrafficSourceDetailPage-DiX1bB02.js → TrafficSourceDetailPage-DKE8tSw5.js} +1 -1
  14. package/assets/assets/{account-context-CdEHcI5S.js → account-context-j3asaevn.js} +1 -1
  15. package/assets/assets/{agent-trust-copy-N6WacCSg.js → agent-trust-copy--U_DFYQE.js} +1 -1
  16. package/assets/assets/{card-B1O0SunG.js → card-CQAQ-c3g.js} +1 -1
  17. package/assets/assets/{format-helpers-V8Pyc7cR.js → format-helpers-BPugHeIX.js} +1 -1
  18. package/assets/assets/{index-BTz-B9hV.js → index-xlDLvgRC.js} +4 -4
  19. package/assets/assets/{query-client-C1ycmW1c.js → query-client-CwZpfiiD.js} +1 -1
  20. package/assets/assets/{react-query-DI7VfOND.js → react-query-CBpNFR4t.js} +1 -1
  21. package/assets/assets/{react-sigma_core.esm.min-f4uuOgrw.js → react-sigma_core.esm.min-BAq_-iP1.js} +1 -1
  22. package/assets/assets/{server-traffic-CkSCFMnL.js → server-traffic-jKXLZyeC.js} +1 -1
  23. package/assets/assets/{service-DSgXWhNq.js → service-DFumlmXt.js} +1 -1
  24. package/assets/index.html +7 -7
  25. package/dist/{ads-PQ4OP6OH.js → ads-EYDUTG4U.js} +3 -3
  26. package/dist/{agent-B6ZPL2HH.js → agent-KTK2IDB3.js} +7 -7
  27. package/dist/{agent-ask-ZUKNXRAX.js → agent-ask-KPZOH6RY.js} +3 -3
  28. package/dist/{agent-conversations-DJ7WU7PL.js → agent-conversations-BCWA4JJL.js} +3 -3
  29. package/dist/{agent-journeys-LGUI3SQG.js → agent-journeys-UBVLQ7JV.js} +3 -3
  30. package/dist/{agent-memory-PWZJ7G5Q.js → agent-memory-24SYEGEX.js} +3 -3
  31. package/dist/{agent-providers-TEERDNJT.js → agent-providers-E7EWFE5P.js} +3 -3
  32. package/dist/{agent-transcript-KDPOPK5Z.js → agent-transcript-QGJ45NW5.js} +3 -3
  33. package/dist/{analytics-NFW5RQRT.js → analytics-GHVG5CCT.js} +3 -3
  34. package/dist/{apply-EP4V4UF5.js → apply-7YLB2DPH.js} +3 -3
  35. package/dist/{backfill-6UTNNVFO.js → backfill-WNQ6O5WP.js} +10 -10
  36. package/dist/{backlinks-SG5GV5X5.js → backlinks-ZBZR4D27.js} +3 -3
  37. package/dist/{bing-Q4W24JNC.js → bing-4VBSKPSX.js} +3 -3
  38. package/dist/{bootstrap-WEMERVNZ.js → bootstrap-7ESCLP2G.js} +10 -10
  39. package/dist/{cdp-3XKBJGHO.js → cdp-WBL6FZTL.js} +7 -7
  40. package/dist/{chunk-ER5ZHAB2.js → chunk-2RW5D55K.js} +2 -2
  41. package/dist/{chunk-BLW327AU.js → chunk-3MFYM2IS.js} +1 -1
  42. package/dist/{chunk-RLKI2QF7.js → chunk-3MKJ4LP6.js} +6 -6
  43. package/dist/{chunk-3BA75QYU.js → chunk-3VPBRGPN.js} +1 -1
  44. package/dist/{chunk-X3UXMHWC.js → chunk-3WDQ5GPO.js} +1 -1
  45. package/dist/{chunk-ZBTUISPG.js → chunk-47X24IJG.js} +13 -1
  46. package/dist/{chunk-EJZ444VV.js → chunk-5ZOM5BJS.js} +1 -1
  47. package/dist/{chunk-3JWY65XO.js → chunk-74V5EPZH.js} +7 -7
  48. package/dist/{chunk-OL2L5ANJ.js → chunk-AJD252SX.js} +2 -2
  49. package/dist/{chunk-VMGZBH5L.js → chunk-AY7SDX6G.js} +3 -3
  50. package/dist/{chunk-2XCYEBQV.js → chunk-C55P75G4.js} +2 -2
  51. package/dist/{chunk-3GMBHGQ5.js → chunk-DLOWRO5R.js} +3 -3
  52. package/dist/{chunk-Q5SNOMRB.js → chunk-DMPSA7ZS.js} +4 -4
  53. package/dist/{chunk-KK3Z34AN.js → chunk-L53ZSQN5.js} +1 -1
  54. package/dist/{chunk-SAKH2RRF.js → chunk-LM7HTNUO.js} +5 -5
  55. package/dist/{chunk-FQ3L2TIX.js → chunk-O6RXNSNW.js} +1 -1
  56. package/dist/{chunk-RTH5JVC3.js → chunk-P764TJKQ.js} +1 -1
  57. package/dist/{chunk-J6MYB3F4.js → chunk-PT5HNVCM.js} +1 -1
  58. package/dist/{chunk-TNOYUE2L.js → chunk-RRXLJPBN.js} +5 -5
  59. package/dist/{chunk-2Q7JEC6N.js → chunk-SY3CWJR4.js} +2 -2
  60. package/dist/{chunk-QSL3FXE4.js → chunk-TVBOK4P2.js} +4 -4
  61. package/dist/{chunk-IAGC2MGP.js → chunk-UPHHKO3L.js} +357 -357
  62. package/dist/{chunk-UXXZXXNG.js → chunk-UY6SKAKW.js} +2 -2
  63. package/dist/{chunk-YJITDEZR.js → chunk-VADVPARO.js} +4 -4
  64. package/dist/{chunk-64KB6YTG.js → chunk-VOVT2H25.js} +3 -3
  65. package/dist/{chunk-64R66MWZ.js → chunk-WA6APXI6.js} +3 -3
  66. package/dist/{chunk-ZADRESLB.js → chunk-WXAF7AMC.js} +2 -2
  67. package/dist/{chunk-IX5AC3QB.js → chunk-XPIMVXAI.js} +388 -338
  68. package/dist/{chunk-RGFIRJ7F.js → chunk-XQP3XHLJ.js} +2 -2
  69. package/dist/{chunk-52M2JWCB.js → chunk-YACKJGY4.js} +1 -1
  70. package/dist/{chunk-ISIJ2NS4.js → chunk-YBWATBX4.js} +1 -1
  71. package/dist/{chunk-CN6MVUY3.js → chunk-YEUULP44.js} +1 -1
  72. package/dist/{chunk-WZSDGC45.js → chunk-YMHN4UIT.js} +1 -1
  73. package/dist/{chunk-O22WSFWL.js → chunk-ZGBLNKFN.js} +8 -5
  74. package/dist/{chunk-MSI4BGFN.js → chunk-ZN2TEBBX.js} +3 -3
  75. package/dist/{citations-5OSQ3ZYU.js → citations-N5MGNKJN.js} +3 -3
  76. package/dist/{cli-catalog-T5OAVKGS.js → cli-catalog-FFU7PHW7.js} +3 -3
  77. package/dist/{cli-commands-VATCVJKW.js → cli-commands-AMIDEUO2.js} +7 -7
  78. package/dist/cli.js +13 -13
  79. package/dist/{competitor-YIKTMTHY.js → competitor-GRA2GMZR.js} +3 -3
  80. package/dist/{content-DS2LKR7J.js → content-YVAPTIV4.js} +3 -3
  81. package/dist/{dashboard-HLVRRRI4.js → dashboard-33ACBR5A.js} +6 -6
  82. package/dist/{demo-A5DTVJGK.js → demo-AGXWBMR6.js} +1 -1
  83. package/dist/{demo-server-P2JGAI6C.js → demo-server-W4YAC7GT.js} +12 -12
  84. package/dist/{discover-VNZDO2MU.js → discover-BH33TO4Z.js} +3 -3
  85. package/dist/{discover-eval-ON77LUEN.js → discover-eval-3CEA6DEE.js} +3 -3
  86. package/dist/{doctor-7TNNTI7H.js → doctor-ZAYTD5PC.js} +3 -3
  87. package/dist/{evidence-E54CNGXS.js → evidence-247GL7UK.js} +3 -3
  88. package/dist/{export-cmd-XXZ6KLQQ.js → export-cmd-HLKWFI5Q.js} +3 -3
  89. package/dist/{ga-ZQB4EJI3.js → ga-BMING57Z.js} +3 -3
  90. package/dist/{gbp-ZQL6NQEK.js → gbp-MIB5CXSD.js} +3 -3
  91. package/dist/{google-7EIHQGSV.js → google-5JP6RYAW.js} +4 -4
  92. package/dist/{google-marketing-RSAO4PG7.js → google-marketing-25OBMPS6.js} +1 -1
  93. package/dist/{health-cmd-R7WPKGWX.js → health-cmd-D5XSEL7H.js} +3 -3
  94. package/dist/{history-2CSWSVCY.js → history-6MDRFPQ3.js} +3 -3
  95. package/dist/index.d.ts +7 -7
  96. package/dist/index.js +25 -25
  97. package/dist/{init-FXZRMXZ3.js → init-RDR75N2Y.js} +12 -12
  98. package/dist/{insights-EJUL3W6D.js → insights-QZVMBGVM.js} +3 -3
  99. package/dist/intelligence-service-KQE7RO5I.js +16 -0
  100. package/dist/{journeys-YUMBANFH.js → journeys-TABTZDFZ.js} +3 -3
  101. package/dist/{keys-KLOTGT4H.js → keys-SL5YF7NQ.js} +3 -3
  102. package/dist/{keyword-5NSJFEOI.js → keyword-OCDEXRSW.js} +3 -3
  103. package/dist/{logs-WW3RLCRG.js → logs-CSC7O364.js} +3 -3
  104. package/dist/{mcp-NTBEIEVX.js → mcp-P725OHAJ.js} +4 -4
  105. package/dist/mcp.js +9 -9
  106. package/dist/{measurement-plan-BLPAZEXS.js → measurement-plan-Z42GBJBO.js} +5 -5
  107. package/dist/{notify-KAGE6UEN.js → notify-E5JBES4I.js} +3 -3
  108. package/dist/{organic-evidence-HTYRXRML.js → organic-evidence-CUA3T64O.js} +3 -3
  109. package/dist/{overview-GSJ4GP2T.js → overview-UKQ52I72.js} +4 -4
  110. package/dist/{project-NYUWICVC.js → project-2ULM64TV.js} +3 -3
  111. package/dist/{query-3CRRDOHD.js → query-Y47IEFKJ.js} +3 -3
  112. package/dist/{research-ZULVD3TW.js → research-DPFQZ3TE.js} +3 -3
  113. package/dist/{results-export-STM7SQ4J.js → results-export-KBHOBQAH.js} +3 -3
  114. package/dist/{run-S4MFU4MK.js → run-4CYHVIIU.js} +4 -4
  115. package/dist/{schedule-6W3Q2FUL.js → schedule-GY4P3RON.js} +3 -3
  116. package/dist/{search-EKXXN7C4.js → search-AGVNZMJQ.js} +3 -3
  117. package/dist/{serve-TFBFPFAQ.js → serve-5LFKIXNL.js} +26 -26
  118. package/dist/{session-4B5V3AH6.js → session-YAYEDM3P.js} +13 -13
  119. package/dist/{settings-VRTDPFR3.js → settings-HUKMWRHY.js} +3 -3
  120. package/dist/{sitemaps-R7XFCH6E.js → sitemaps-APTY7U6H.js} +3 -3
  121. package/dist/{skills-44XYCTVD.js → skills-4BUONEIZ.js} +2 -2
  122. package/dist/{snapshot-ROAOJI4W.js → snapshot-BXCWSF5P.js} +3 -3
  123. package/dist/{src-ZJRIKEDB.js → src-R7XZUX3D.js} +2 -2
  124. package/dist/{status-EN3A2TX5.js → status-SB6HPBYJ.js} +4 -4
  125. package/dist/{technical-aeo-ZV466F65.js → technical-aeo-G7UEMWZD.js} +3 -3
  126. package/dist/{telemetry-EZHPNZ2A.js → telemetry-H4S4Y7YV.js} +4 -4
  127. package/dist/{tools-IH4M7AAG.js → tools-46XX6I4R.js} +11 -11
  128. package/dist/{traffic-VFLXWB3Z.js → traffic-I6WRJN3W.js} +5 -5
  129. package/dist/{trends-ZXJIX3Z3.js → trends-AQK3GLWF.js} +3 -3
  130. package/dist/{users-J2BYEWOE.js → users-SNTVY6OB.js} +3 -3
  131. package/dist/{visibility-stats-AJ7NY2BP.js → visibility-stats-44QAD2XS.js} +3 -3
  132. package/dist/{wordpress-U6MS35VE.js → wordpress-N7LTOW46.js} +3 -3
  133. package/package.json +2 -2
  134. package/dist/intelligence-service-TKK7O3Z5.js +0 -16
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  answerServiceAdapters,
3
3
  answerServiceDescriptors
4
- } from "./chunk-EJZ444VV.js";
4
+ } from "./chunk-5ZOM5BJS.js";
5
5
  import {
6
6
  AeroLlmUsageFeatures,
7
7
  aeroTurnStatus,
@@ -27,14 +27,14 @@ import {
27
27
  resolveConfiguredAgentProvider,
28
28
  resolveSessionProviderAndModel,
29
29
  setAeroSystemPrompt
30
- } from "./chunk-RLKI2QF7.js";
30
+ } from "./chunk-3MKJ4LP6.js";
31
31
  import {
32
32
  AeroToolProfiles,
33
33
  AeroToolScopes,
34
34
  buildAeroStateTools,
35
35
  isAeroToolProfile,
36
36
  truncateToolResult
37
- } from "./chunk-Q5SNOMRB.js";
37
+ } from "./chunk-DMPSA7ZS.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-J6MYB3F4.js";
56
+ } from "./chunk-PT5HNVCM.js";
57
57
  import {
58
58
  claudeAdapter,
59
59
  embedQueries,
@@ -65,7 +65,7 @@ import {
65
65
  openrouterAdapter,
66
66
  perplexityAdapter,
67
67
  startTrafficReclassification
68
- } from "./chunk-TNOYUE2L.js";
68
+ } from "./chunk-RRXLJPBN.js";
69
69
  import {
70
70
  classifyUsageSurface,
71
71
  createApiUsageTelemetry,
@@ -77,7 +77,7 @@ import {
77
77
  startOutcomeTimer,
78
78
  trackFeatureCompleted,
79
79
  trackInstallState
80
- } from "./chunk-YJITDEZR.js";
80
+ } from "./chunk-VADVPARO.js";
81
81
  import {
82
82
  isLoopbackBindHost
83
83
  } from "./chunk-TSENU4GG.js";
@@ -85,7 +85,7 @@ import {
85
85
  isApiProviderRegistrable,
86
86
  isCdpProviderRegistrable,
87
87
  registeredProviderNames
88
- } from "./chunk-FQ3L2TIX.js";
88
+ } from "./chunk-O6RXNSNW.js";
89
89
  import {
90
90
  checkLatestVersionForServer,
91
91
  getOrCreateAnonymousId,
@@ -97,17 +97,17 @@ import {
97
97
  recordDashboardEvent,
98
98
  setTelemetryPreference,
99
99
  trackEvent
100
- } from "./chunk-2XCYEBQV.js";
100
+ } from "./chunk-C55P75G4.js";
101
101
  import {
102
102
  createCanonryMcpServer
103
- } from "./chunk-64R66MWZ.js";
103
+ } from "./chunk-WA6APXI6.js";
104
104
  import {
105
105
  CANONRY_MCP_TIERS,
106
106
  CANONRY_MCP_TOOLKIT_NAMES
107
107
  } from "./chunk-MTW37GXF.js";
108
108
  import {
109
109
  ApiClient
110
- } from "./chunk-OL2L5ANJ.js";
110
+ } from "./chunk-AJD252SX.js";
111
111
  import {
112
112
  AGENT_PROVIDERS,
113
113
  adapterSupportsBatch,
@@ -139,21 +139,21 @@ import {
139
139
  saveConfigPatch,
140
140
  sentimentInstallReadiness,
141
141
  updateSharedProviderExecutionGate
142
- } from "./chunk-BLW327AU.js";
142
+ } from "./chunk-3MFYM2IS.js";
143
143
  import {
144
144
  getBundledSkillSnapshots
145
- } from "./chunk-RTH5JVC3.js";
145
+ } from "./chunk-P764TJKQ.js";
146
146
  import {
147
147
  computeFactorAverages,
148
148
  deleteSiteCrawlGraphLayout,
149
149
  persistSiteCrawlGraphLayout,
150
150
  prepareSiteCrawlGraphLayout,
151
151
  recordedSharePct
152
- } from "./chunk-2Q7JEC6N.js";
152
+ } from "./chunk-SY3CWJR4.js";
153
153
  import {
154
154
  CanonryMcpToolNames,
155
155
  canonryMcpTools
156
- } from "./chunk-3GMBHGQ5.js";
156
+ } from "./chunk-DLOWRO5R.js";
157
157
  import {
158
158
  PACKAGE_VERSION
159
159
  } from "./chunk-AOJU5LKX.js";
@@ -162,16 +162,16 @@ import {
162
162
  } from "./chunk-HGMYEDAQ.js";
163
163
  import {
164
164
  IntelligenceService
165
- } from "./chunk-SAKH2RRF.js";
165
+ } from "./chunk-LM7HTNUO.js";
166
166
  import {
167
167
  computeCitedCompetitorDomains,
168
168
  determineCitationState
169
- } from "./chunk-ISIJ2NS4.js";
169
+ } from "./chunk-YBWATBX4.js";
170
170
  import {
171
171
  addLogListener,
172
172
  createFastifyLogger,
173
173
  createLogger
174
- } from "./chunk-UXXZXXNG.js";
174
+ } from "./chunk-UY6SKAKW.js";
175
175
  import {
176
176
  BingApiError,
177
177
  CC_CACHE_DIR,
@@ -316,7 +316,7 @@ import {
316
316
  webhookResponseReason,
317
317
  webhookTargetRefusalReason,
318
318
  writeAuditLog
319
- } from "./chunk-O22WSFWL.js";
319
+ } from "./chunk-ZGBLNKFN.js";
320
320
  import {
321
321
  OperationalLogStore,
322
322
  SentimentIdempotencyConflict,
@@ -414,7 +414,7 @@ import {
414
414
  unrecognizedAgentEventsHourly,
415
415
  unrecognizedAgentNotifyState,
416
416
  usageCounters
417
- } from "./chunk-KK3Z34AN.js";
417
+ } from "./chunk-L53ZSQN5.js";
418
418
  import {
419
419
  AGENT_MEMORY_VALUE_MAX_BYTES,
420
420
  AI_ENGINE_DOMAINS,
@@ -629,6 +629,7 @@ import {
629
629
  parseMeasurementRunManifestV1,
630
630
  parseOriginList,
631
631
  parseRunError,
632
+ parseStoredMeasurementPlanAnyVersion,
632
633
  percentOf,
633
634
  providerConnectionName,
634
635
  providerError,
@@ -674,7 +675,7 @@ import {
674
675
  winnabilityClassLabel,
675
676
  withRetry,
676
677
  withSkippedProviders
677
- } from "./chunk-ZBTUISPG.js";
678
+ } from "./chunk-47X24IJG.js";
678
679
 
679
680
  // src/google-marketing-runtime.ts
680
681
  import crypto2 from "crypto";
@@ -3364,7 +3365,7 @@ import path5 from "path";
3364
3365
  import { isIP as isIP2 } from "net";
3365
3366
  import { fileURLToPath } from "url";
3366
3367
  import { setImmediate as yieldToEventLoop4 } from "timers/promises";
3367
- import { and as and30, eq as eq36, isNotNull as isNotNull5, isNull as isNull8, lte as lte3, max, ne as ne4, or as or4, sql as sql15 } from "drizzle-orm";
3368
+ import { and as and31, eq as eq37, isNotNull as isNotNull5, isNull as isNull8, lte as lte3, max, ne as ne4, or as or4, sql as sql15 } from "drizzle-orm";
3368
3369
 
3369
3370
  // src/seo-runtime.ts
3370
3371
  import { eq, inArray } from "drizzle-orm";
@@ -6002,7 +6003,7 @@ function nonBlank(value) {
6002
6003
  return trimmed ? trimmed : void 0;
6003
6004
  }
6004
6005
  function resolveBuildCommit(env = process.env) {
6005
- const embedded = true ? "161453e7b8d6e3b33614392ce97134fc484106ec" : void 0;
6006
+ const embedded = true ? "74e5d2930f44211335b0da42dd2200f8ac58ae90" : void 0;
6006
6007
  return nonBlank(embedded) ?? nonBlank(env.CANONRY_COMMIT);
6007
6008
  }
6008
6009
  function resolveInstanceIdentity(env = process.env) {
@@ -12234,7 +12235,7 @@ function buildDiscoveryInsightTitle(input) {
12234
12235
 
12235
12236
  // src/execute-site-audit.ts
12236
12237
  import crypto20 from "crypto";
12237
- import { and as and15, eq as eq19, ne as ne2, sql as sql7 } from "drizzle-orm";
12238
+ import { and as and16, eq as eq20, ne as ne2, sql as sql7 } from "drizzle-orm";
12238
12239
  import { runSiteCrawl } from "@canonry/agent-readiness";
12239
12240
 
12240
12241
  // src/site-audit-root.ts
@@ -12545,6 +12546,45 @@ function buildSiteCrawlIssueEvidence(siteIssues, pages) {
12545
12546
  return { schemaVersion: "1.0", groupIdentityVersion: GROUP_IDENTITY_VERSION, siteIssues: groups };
12546
12547
  }
12547
12548
 
12549
+ // src/site-audit-entity-registry.ts
12550
+ import { and as and15, eq as eq19 } from "drizzle-orm";
12551
+ function entityMatcher(matcher) {
12552
+ switch (matcher.kind) {
12553
+ case "prefix":
12554
+ return { host: matcher.host, pathPrefix: matcher.pathPrefix };
12555
+ case "host":
12556
+ return { host: matcher.host, pathPrefix: "/" };
12557
+ case "exact": {
12558
+ try {
12559
+ const url = new URL(matcher.url);
12560
+ return { host: url.hostname, pathPrefix: url.pathname };
12561
+ } catch {
12562
+ return null;
12563
+ }
12564
+ }
12565
+ }
12566
+ }
12567
+ function planEntityRegistry(plan) {
12568
+ if (plan.targets.length === 0) return null;
12569
+ return {
12570
+ entities: plan.targets.map((target) => ({
12571
+ key: target.stableKey,
12572
+ names: [.../* @__PURE__ */ new Set([target.label, ...target.aliases, ...target.identityAliases ?? []])],
12573
+ urlMatchers: target.urlMatchers.map(entityMatcher).filter((matcher) => matcher !== null)
12574
+ }))
12575
+ };
12576
+ }
12577
+ function activePlanEntityRegistry(db, projectId) {
12578
+ const pointer = db.select({ versionId: measurementPlans.activeVersionId }).from(measurementPlans).where(eq19(measurementPlans.projectId, projectId)).get();
12579
+ if (!pointer) return null;
12580
+ const version = db.select({ revision: measurementPlanVersions.revision, canonicalJson: measurementPlanVersions.canonicalJson }).from(measurementPlanVersions).where(and15(eq19(measurementPlanVersions.projectId, projectId), eq19(measurementPlanVersions.id, pointer.versionId))).get();
12581
+ if (!version) return null;
12582
+ const plan = parseStoredMeasurementPlanAnyVersion(version.canonicalJson);
12583
+ if (plan.schemaVersion !== MEASUREMENT_PLAN_V2_SCHEMA_VERSION) return null;
12584
+ const registry = planEntityRegistry(plan);
12585
+ return registry ? { planRevision: version.revision, registry } : null;
12586
+ }
12587
+
12548
12588
  // src/execute-site-audit.ts
12549
12589
  var log15 = createLogger("SiteAudit");
12550
12590
  var SiteAuditCancelledError = class extends Error {
@@ -12698,7 +12738,7 @@ function trackSiteAuditOutcome(db, input) {
12698
12738
  );
12699
12739
  const pagesAudited = input.crawl?.pagesAudited ?? 0;
12700
12740
  if (pagesAudited === 0 || input.trigger === RunTriggers.probe) return;
12701
- const prior = db.select({ id: siteAuditSnapshots.id }).from(siteAuditSnapshots).where(and15(eq19(siteAuditSnapshots.projectId, input.projectId), ne2(siteAuditSnapshots.runId, input.runId))).limit(1).get();
12741
+ const prior = db.select({ id: siteAuditSnapshots.id }).from(siteAuditSnapshots).where(and16(eq20(siteAuditSnapshots.projectId, input.projectId), ne2(siteAuditSnapshots.runId, input.runId))).limit(1).get();
12702
12742
  if (prior) return;
12703
12743
  trackEvent("activation.completed", {
12704
12744
  flowVersion: ONBOARDING_FLOW_VERSION,
@@ -12712,12 +12752,12 @@ function trackSiteAuditOutcome(db, input) {
12712
12752
  }
12713
12753
  async function executeSiteAudit(db, runId, projectId, opts = {}) {
12714
12754
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
12715
- const claim = db.update(runs).set({ status: "running", startedAt }).where(and15(eq19(runs.id, runId), eq19(runs.projectId, projectId), eq19(runs.status, "queued"))).run();
12755
+ const claim = db.update(runs).set({ status: "running", startedAt }).where(and16(eq20(runs.id, runId), eq20(runs.projectId, projectId), eq20(runs.status, "queued"))).run();
12716
12756
  if (claim.changes === 0) return;
12717
12757
  const startTime = Date.now();
12718
- const trigger = db.select({ trigger: runs.trigger }).from(runs).where(eq19(runs.id, runId)).get()?.trigger ?? null;
12758
+ const trigger = db.select({ trigger: runs.trigger }).from(runs).where(eq20(runs.id, runId)).get()?.trigger ?? null;
12719
12759
  let canonicalDomain = null;
12720
- const attemptNumber = (db.select({ value: sql7`coalesce(max(${siteCrawlAttempts.attemptNumber}), 0)` }).from(siteCrawlAttempts).where(eq19(siteCrawlAttempts.runId, runId)).get()?.value ?? 0) + 1;
12760
+ const attemptNumber = (db.select({ value: sql7`coalesce(max(${siteCrawlAttempts.attemptNumber}), 0)` }).from(siteCrawlAttempts).where(eq20(siteCrawlAttempts.runId, runId)).get()?.value ?? 0) + 1;
12721
12761
  const attemptId = crypto20.randomUUID();
12722
12762
  db.insert(siteCrawlAttempts).values({
12723
12763
  id: attemptId,
@@ -12752,22 +12792,22 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
12752
12792
  const nodeKey = nodeKeyByUrl.get(url);
12753
12793
  if (!nodeKey) continue;
12754
12794
  const scope = [
12755
- eq19(siteCrawlEdges.projectId, projectId),
12756
- eq19(siteCrawlEdges.runId, runId),
12757
- eq19(siteCrawlEdges.attemptId, attemptId)
12795
+ eq20(siteCrawlEdges.projectId, projectId),
12796
+ eq20(siteCrawlEdges.runId, runId),
12797
+ eq20(siteCrawlEdges.attemptId, attemptId)
12758
12798
  ];
12759
- tx.update(siteCrawlEdges).set({ sourceNodeKey: nodeKey, updatedAt: now }).where(and15(
12799
+ tx.update(siteCrawlEdges).set({ sourceNodeKey: nodeKey, updatedAt: now }).where(and16(
12760
12800
  ...scope,
12761
- eq19(siteCrawlEdges.sourceUrl, url)
12801
+ eq20(siteCrawlEdges.sourceUrl, url)
12762
12802
  )).run();
12763
- tx.update(siteCrawlEdges).set({ targetNodeKey: nodeKey, updatedAt: now }).where(and15(
12803
+ tx.update(siteCrawlEdges).set({ targetNodeKey: nodeKey, updatedAt: now }).where(and16(
12764
12804
  ...scope,
12765
- eq19(siteCrawlEdges.targetUrl, url)
12805
+ eq20(siteCrawlEdges.targetUrl, url)
12766
12806
  )).run();
12767
12807
  const pageScope = [
12768
- eq19(siteCrawlPages.projectId, projectId),
12769
- eq19(siteCrawlPages.runId, runId),
12770
- eq19(siteCrawlPages.attemptId, attemptId)
12808
+ eq20(siteCrawlPages.projectId, projectId),
12809
+ eq20(siteCrawlPages.runId, runId),
12810
+ eq20(siteCrawlPages.attemptId, attemptId)
12771
12811
  ];
12772
12812
  const canonicalTargets = tx.select({
12773
12813
  id: siteCrawlPages.id,
@@ -12775,13 +12815,13 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
12775
12815
  fetchState: siteCrawlPages.fetchState,
12776
12816
  indexabilityState: siteCrawlPages.indexabilityState,
12777
12817
  indexabilityReasons: siteCrawlPages.indexabilityReasons
12778
- }).from(siteCrawlPages).where(and15(...pageScope, eq19(siteCrawlPages.canonicalUrl, url))).all();
12818
+ }).from(siteCrawlPages).where(and16(...pageScope, eq20(siteCrawlPages.canonicalUrl, url))).all();
12779
12819
  for (const target of canonicalTargets) {
12780
12820
  tx.update(siteCrawlPages).set({
12781
12821
  canonicalNodeKey: nodeKey,
12782
12822
  healthState: deriveSiteHealthState({ ...target, canonicalNodeKey: nodeKey }),
12783
12823
  updatedAt: now
12784
- }).where(eq19(siteCrawlPages.id, target.id)).run();
12824
+ }).where(eq20(siteCrawlPages.id, target.id)).run();
12785
12825
  }
12786
12826
  }
12787
12827
  };
@@ -12940,20 +12980,20 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
12940
12980
  linkScoreRaw: metrics.linkScoreRaw,
12941
12981
  linkScoreNormalized: metrics.linkScore,
12942
12982
  updatedAt: now
12943
- }).where(and15(
12944
- eq19(siteCrawlPages.projectId, projectId),
12945
- eq19(siteCrawlPages.runId, runId),
12946
- eq19(siteCrawlPages.attemptId, attemptId),
12947
- eq19(siteCrawlPages.nodeKey, key)
12983
+ }).where(and16(
12984
+ eq20(siteCrawlPages.projectId, projectId),
12985
+ eq20(siteCrawlPages.runId, runId),
12986
+ eq20(siteCrawlPages.attemptId, attemptId),
12987
+ eq20(siteCrawlPages.nodeKey, key)
12948
12988
  )).run();
12949
12989
  };
12950
12990
  const persistEvent = async (event) => {
12951
12991
  const now = (/* @__PURE__ */ new Date()).toISOString();
12952
12992
  db.transaction((tx) => {
12953
- const receipt = tx.select({ checksum: siteCrawlEventReceipts.checksum }).from(siteCrawlEventReceipts).where(and15(
12954
- eq19(siteCrawlEventReceipts.attemptId, attemptId),
12955
- eq19(siteCrawlEventReceipts.sequence, event.sequence),
12956
- eq19(siteCrawlEventReceipts.batchId, event.batchId)
12993
+ const receipt = tx.select({ checksum: siteCrawlEventReceipts.checksum }).from(siteCrawlEventReceipts).where(and16(
12994
+ eq20(siteCrawlEventReceipts.attemptId, attemptId),
12995
+ eq20(siteCrawlEventReceipts.sequence, event.sequence),
12996
+ eq20(siteCrawlEventReceipts.batchId, event.batchId)
12957
12997
  )).get();
12958
12998
  if (receipt) {
12959
12999
  if (receipt.checksum !== event.checksum) {
@@ -12988,18 +13028,18 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
12988
13028
  urlVersionsSkipped: event.type === "summary" ? event.summary.urlVersions?.skipped ?? 0 : sql7`${siteCrawlAttempts.urlVersionsSkipped}`,
12989
13029
  edgesDiscovered: progress.edgesObserved,
12990
13030
  updatedAt: now
12991
- }).where(eq19(siteCrawlAttempts.id, attemptId)).run();
13031
+ }).where(eq20(siteCrawlAttempts.id, attemptId)).run();
12992
13032
  } else {
12993
13033
  tx.update(siteCrawlAttempts).set({
12994
13034
  lastEventSequence: event.sequence,
12995
13035
  lastEventChecksum: event.checksum,
12996
13036
  updatedAt: now
12997
- }).where(eq19(siteCrawlAttempts.id, attemptId)).run();
13037
+ }).where(eq20(siteCrawlAttempts.id, attemptId)).run();
12998
13038
  }
12999
13039
  });
13000
13040
  };
13001
13041
  try {
13002
- const project = db.select().from(projects).where(eq19(projects.id, projectId)).get();
13042
+ const project = db.select().from(projects).where(eq20(projects.id, projectId)).get();
13003
13043
  if (!project) throw new Error(`Project not found: ${projectId}`);
13004
13044
  canonicalDomain = project.canonicalDomain;
13005
13045
  const homepageUrl = toHomepageUrl(project.canonicalDomain);
@@ -13011,6 +13051,12 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
13011
13051
  });
13012
13052
  const crawlRootUrl = resolvedRoot.effectiveUrl;
13013
13053
  if (opts.sitemapUrl) await assertSiteAuditUrlAllowed(opts.sitemapUrl, "sitemapUrl");
13054
+ let entities = null;
13055
+ try {
13056
+ entities = activePlanEntityRegistry(db, projectId);
13057
+ } catch (error) {
13058
+ log15.warn("entity-registry.unavailable", { runId, projectId, error: describeError(error) });
13059
+ }
13014
13060
  log15.info("start", {
13015
13061
  runId,
13016
13062
  projectId,
@@ -13019,7 +13065,8 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
13019
13065
  redirects: resolvedRoot.redirects.length,
13020
13066
  maxPages,
13021
13067
  maxEdges,
13022
- maxDepth: opts.maxDepth ?? null
13068
+ maxDepth: opts.maxDepth ?? null,
13069
+ entityPlanRevision: entities?.planRevision ?? null
13023
13070
  });
13024
13071
  const report = await runSiteCrawl(crawlRootUrl, {
13025
13072
  mode: "summary",
@@ -13031,6 +13078,7 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
13031
13078
  includeGeo: opts.includeGeo ?? false,
13032
13079
  includeAgentSkills: opts.includeAgentSkills ?? true,
13033
13080
  skipUrlVersionsAfter: SITE_AUDIT_SKIP_URL_VERSIONS_AFTER,
13081
+ ...entities ? { entityRegistry: entities.registry } : {},
13034
13082
  signal: opts.signal,
13035
13083
  onEvent: persistEvent
13036
13084
  });
@@ -13103,7 +13151,7 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
13103
13151
  }
13104
13152
  }
13105
13153
  const published = db.transaction((tx) => {
13106
- const claim2 = tx.update(runs).set({ status: terminalStatus, finishedAt }).where(and15(eq19(runs.id, runId), eq19(runs.status, "running"))).run();
13154
+ const claim2 = tx.update(runs).set({ status: terminalStatus, finishedAt }).where(and16(eq20(runs.id, runId), eq20(runs.status, "running"))).run();
13107
13155
  if (claim2.changes === 0) return false;
13108
13156
  if (aggregateScore !== null) {
13109
13157
  tx.insert(siteAuditSnapshots).values({
@@ -13159,7 +13207,9 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
13159
13207
  maxDepth: opts.maxDepth ?? null,
13160
13208
  checkDeadLinks: opts.checkDeadLinks ?? false,
13161
13209
  includeGeo: opts.includeGeo ?? false,
13162
- includeAgentSkills: opts.includeAgentSkills ?? true
13210
+ includeAgentSkills: opts.includeAgentSkills ?? true,
13211
+ // The plan revision whose Properties pages were checked against; null when none were.
13212
+ entityPlanRevision: entities?.planRevision ?? null
13163
13213
  },
13164
13214
  pageBudget: maxPages,
13165
13215
  edgeBudget: maxEdges ?? null,
@@ -13213,7 +13263,7 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
13213
13263
  edgesDiscovered: crawlSummary.edgesObserved,
13214
13264
  finishedAt,
13215
13265
  updatedAt: finishedAt
13216
- }).where(eq19(siteCrawlAttempts.id, attemptId)).run();
13266
+ }).where(eq20(siteCrawlAttempts.id, attemptId)).run();
13217
13267
  return true;
13218
13268
  });
13219
13269
  if (!published) {
@@ -13226,7 +13276,7 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
13226
13276
  error: describeError(cleanupError)
13227
13277
  });
13228
13278
  }
13229
- const current = db.select({ status: runs.status }).from(runs).where(eq19(runs.id, runId)).get();
13279
+ const current = db.select({ status: runs.status }).from(runs).where(eq20(runs.id, runId)).get();
13230
13280
  if (current?.status === "cancelled") throw new SiteAuditCancelledError(`Site audit cancelled before publication: ${runId}`);
13231
13281
  throw new Error(`Site audit run was no longer running before publication: ${runId}`);
13232
13282
  }
@@ -13274,12 +13324,12 @@ async function executeSiteAudit(db, runId, projectId, opts = {}) {
13274
13324
  error: message,
13275
13325
  finishedAt,
13276
13326
  updatedAt: finishedAt
13277
- }).where(eq19(siteCrawlAttempts.id, attemptId)).run();
13327
+ }).where(eq20(siteCrawlAttempts.id, attemptId)).run();
13278
13328
  tx.update(runs).set({
13279
13329
  status: cancelled ? "cancelled" : "failed",
13280
13330
  error: message,
13281
13331
  finishedAt
13282
- }).where(and15(eq19(runs.id, runId), eq19(runs.status, "running"))).run();
13332
+ }).where(and16(eq20(runs.id, runId), eq20(runs.status, "running"))).run();
13283
13333
  });
13284
13334
  log15.error("failed", { runId, projectId, cancelled, error: message });
13285
13335
  trackSiteAuditOutcome(db, {
@@ -13477,7 +13527,7 @@ function derivedRouteAdapter(adapter, route) {
13477
13527
  }
13478
13528
 
13479
13529
  // src/install-state-telemetry.ts
13480
- import { and as and16, count as count4, eq as eq20, gte as gte2, inArray as inArray8, isNotNull as isNotNull2, isNull as isNull2, ne as ne3, sql as sql8 } from "drizzle-orm";
13530
+ import { and as and17, count as count4, eq as eq21, gte as gte2, inArray as inArray8, isNotNull as isNotNull2, isNull as isNull2, ne as ne3, sql as sql8 } from "drizzle-orm";
13481
13531
  var log17 = createLogger("InstallStateTelemetry");
13482
13532
  var INSTALL_STATE_FIRST_DELAY_MS = 5 * 6e4;
13483
13533
  var INSTALL_STATE_INTERVAL_MS = 24 * 60 * 6e4;
@@ -13502,8 +13552,8 @@ function buildInstallState(sources, now, startedAt) {
13502
13552
  const total = (query) => whole(query.get()?.value);
13503
13553
  const googleByType = new Map(db.select({ type: googleConnections.connectionType, value: count4() }).from(googleConnections).groupBy(googleConnections.connectionType).all().map((row) => [row.type, whole(row.value)]));
13504
13554
  const gaServiceAccounts = total(db.select({ value: count4() }).from(gaConnections));
13505
- const trafficByType = db.select({ type: trafficSources.sourceType, value: count4() }).from(trafficSources).where(and16(isNull2(trafficSources.archivedAt), ne3(trafficSources.status, TrafficSourceStatuses.archived))).groupBy(trafficSources.sourceType).all();
13506
- const webhookSources = db.select({ config: notifications.config }).from(notifications).where(eq20(notifications.enabled, true)).all().map((row) => row.config.source);
13555
+ const trafficByType = db.select({ type: trafficSources.sourceType, value: count4() }).from(trafficSources).where(and17(isNull2(trafficSources.archivedAt), ne3(trafficSources.status, TrafficSourceStatuses.archived))).groupBy(trafficSources.sourceType).all();
13556
+ const webhookSources = db.select({ config: notifications.config }).from(notifications).where(eq21(notifications.enabled, true)).all().map((row) => row.config.source);
13507
13557
  const agentWebhooks = webhookSources.filter((source) => source === AGENT_WEBHOOK_SOURCE).length;
13508
13558
  const webhooks = webhookSources.length - agentWebhooks;
13509
13559
  const bing = total(db.select({ value: count4() }).from(bingConnections));
@@ -13517,7 +13567,7 @@ function buildInstallState(sources, now, startedAt) {
13517
13567
  queries: total(db.select({ value: count4() }).from(queries)),
13518
13568
  competitors: total(db.select({ value: count4() }).from(competitors)),
13519
13569
  locations: total(db.select({ value: sql8`coalesce(sum(json_array_length(${projects.locations})), 0)` }).from(projects)),
13520
- schedules: total(db.select({ value: count4() }).from(schedules).where(eq20(schedules.enabled, true))),
13570
+ schedules: total(db.select({ value: count4() }).from(schedules).where(eq21(schedules.enabled, true))),
13521
13571
  webhooks,
13522
13572
  agentWebhooks,
13523
13573
  trafficSources: trafficByType.reduce((sum, row) => sum + whole(row.value), 0),
@@ -13561,14 +13611,14 @@ function buildInstallState(sources, now, startedAt) {
13561
13611
  costMicros: sql8`coalesce(sum(${usagePath("estimatedCostMicros")}), 0)`
13562
13612
  }).from(querySnapshots).where(gte2(querySnapshots.createdAt, since)).groupBy(sql8`+${querySnapshots.provider}`).all();
13563
13613
  for (const row of answers) addCalls(row.provider, whole(row.answers));
13564
- for (const row of db.select({ provider: researchRuns.provider, answered: sql8`coalesce(sum(${researchRuns.completedQueries}), 0)` }).from(researchRuns).where(and16(inArray8(researchRuns.projectId, projectIds), gte2(researchRuns.createdAt, since))).groupBy(researchRuns.provider).all()) {
13614
+ for (const row of db.select({ provider: researchRuns.provider, answered: sql8`coalesce(sum(${researchRuns.completedQueries}), 0)` }).from(researchRuns).where(and17(inArray8(researchRuns.projectId, projectIds), gte2(researchRuns.createdAt, since))).groupBy(researchRuns.provider).all()) {
13565
13615
  addCalls(row.provider, whole(row.answered));
13566
13616
  }
13567
13617
  for (const session of db.select({
13568
13618
  seedProviders: discoverySessions.seedProviders,
13569
13619
  seedCountRaw: discoverySessions.seedCountRaw,
13570
13620
  probeCount: discoverySessions.probeCount
13571
- }).from(discoverySessions).where(and16(inArray8(discoverySessions.projectId, projectIds), gte2(discoverySessions.createdAt, since))).all()) {
13621
+ }).from(discoverySessions).where(and17(inArray8(discoverySessions.projectId, projectIds), gte2(discoverySessions.createdAt, since))).all()) {
13572
13622
  if (session.seedCountRaw !== null) {
13573
13623
  for (const provider of session.seedProviders?.length ? session.seedProviders : [ProviderNames.gemini]) addCalls(provider, 1);
13574
13624
  }
@@ -13577,15 +13627,15 @@ function buildInstallState(sources, now, startedAt) {
13577
13627
  const answered = answers.reduce((sum, row) => sum + whole(row.answers), 0);
13578
13628
  const measured = answers.reduce((sum, row) => sum + whole(row.measured), 0);
13579
13629
  const usage24h = {
13580
- sweeps: total(db.select({ value: count4() }).from(runs).where(and16(
13630
+ sweeps: total(db.select({ value: count4() }).from(runs).where(and17(
13581
13631
  inArray8(runs.projectId, projectIds),
13582
- eq20(runs.kind, RunKinds["answer-visibility"]),
13632
+ eq21(runs.kind, RunKinds["answer-visibility"]),
13583
13633
  gte2(runs.createdAt, since),
13584
13634
  ne3(runs.trigger, RunTriggers.probe)
13585
13635
  ))),
13586
- audits: total(db.select({ value: count4() }).from(runs).where(and16(
13636
+ audits: total(db.select({ value: count4() }).from(runs).where(and17(
13587
13637
  inArray8(runs.projectId, projectIds),
13588
- eq20(runs.kind, RunKinds["site-audit"]),
13638
+ eq21(runs.kind, RunKinds["site-audit"]),
13589
13639
  gte2(runs.createdAt, since)
13590
13640
  ))),
13591
13641
  providerCalls: [...providerCalls.values()].reduce((sum, calls) => sum + calls, 0)
@@ -13602,14 +13652,14 @@ function buildInstallState(sources, now, startedAt) {
13602
13652
  inputTokens: sql8`coalesce(sum(${llmUsageEvents.inputTokens}), 0)`,
13603
13653
  outputTokens: sql8`coalesce(sum(${llmUsageEvents.outputTokens}), 0)`,
13604
13654
  costMillicents: sql8`coalesce(sum(${llmUsageEvents.costMillicents}), 0)`
13605
- }).from(llmUsageEvents).where(and16(eq20(llmUsageEvents.feature, AeroLlmUsageFeatures.turn), gte2(llmUsageEvents.createdAt, since))).get();
13655
+ }).from(llmUsageEvents).where(and17(eq21(llmUsageEvents.feature, AeroLlmUsageFeatures.turn), gte2(llmUsageEvents.createdAt, since))).get();
13606
13656
  const aeroCalls = whole(aero?.calls);
13607
13657
  usage24h.aeroModelCalls = aeroCalls;
13608
13658
  usage24h.aeroInputTokens = whole(aero?.inputTokens);
13609
13659
  usage24h.aeroOutputTokens = whole(aero?.outputTokens);
13610
13660
  const aeroMillicents = whole(aero?.costMillicents);
13611
13661
  if (aeroCalls === 0 || aeroMillicents > 0) usage24h.aeroCostMicros = aeroMillicents * 10;
13612
- usage24h.webhookDeliveries = total(db.select({ value: count4() }).from(auditLog).where(and16(gte2(auditLog.createdAt, since), eq20(auditLog.action, WEBHOOK_DELIVERED_ACTION))));
13662
+ usage24h.webhookDeliveries = total(db.select({ value: count4() }).from(auditLog).where(and17(gte2(auditLog.createdAt, since), eq21(auditLog.action, WEBHOOK_DELIVERED_ACTION))));
13613
13663
  const providerCalls24h = Object.fromEntries(PROVIDER_NAMES.flatMap((name) => providerCalls.has(name) ? [[name, providerCalls.get(name)]] : []));
13614
13664
  return {
13615
13665
  providers: registeredProviderNames(config).filter((name) => KNOWN_PROVIDERS2.has(name)),
@@ -13739,7 +13789,7 @@ function configuredProviderEntries(config, apiAdapters, cdpAdapter) {
13739
13789
 
13740
13790
  // src/provider-reload-batch-guard.ts
13741
13791
  import { isDeepStrictEqual } from "util";
13742
- import { and as and17, inArray as inArray9 } from "drizzle-orm";
13792
+ import { and as and18, inArray as inArray9 } from "drizzle-orm";
13743
13793
  function pendingBatchIdentity(provider) {
13744
13794
  const { quotaPolicy: _quotaPolicy, ...identity } = resolveRegistration(provider.adapter, provider.config).config;
13745
13795
  return identity;
@@ -13753,7 +13803,7 @@ function assertProviderReloadKeepsPendingBatches(db, previous, next, executing =
13753
13803
  const changed = previous.filter(changedRegistration).map((provider) => provider.adapter.name);
13754
13804
  const active = executing.filter((snapshot) => changedRegistration(snapshot.registration));
13755
13805
  if (changed.length === 0 && active.length === 0) return;
13756
- const pending = changed.length === 0 ? [] : db.select({ id: providerBatches.id, provider: providerBatches.provider, runId: providerBatches.runId }).from(providerBatches).where(and17(
13806
+ const pending = changed.length === 0 ? [] : db.select({ id: providerBatches.id, provider: providerBatches.provider, runId: providerBatches.runId }).from(providerBatches).where(and18(
13757
13807
  inArray9(providerBatches.provider, changed),
13758
13808
  inArray9(providerBatches.status, [ProviderBatchStatuses.submitting, ProviderBatchStatuses.submitted, ProviderBatchStatuses.ended])
13759
13809
  )).all();
@@ -13835,7 +13885,7 @@ function createProviderModelCatalog(registry) {
13835
13885
  // src/scheduler.ts
13836
13886
  import crypto21 from "crypto";
13837
13887
  import cron from "node-cron";
13838
- import { and as and18, eq as eq21, inArray as inArray10, notExists, sql as sql9 } from "drizzle-orm";
13888
+ import { and as and19, eq as eq22, inArray as inArray10, notExists, sql as sql9 } from "drizzle-orm";
13839
13889
  var log18 = createLogger("Scheduler");
13840
13890
  var SLOT_FIRED = { status: OutcomeStatuses.succeeded };
13841
13891
  var slotSkipped = (reasonCode) => ({ status: OutcomeStatuses.skipped, reasonCode });
@@ -13914,9 +13964,9 @@ var Scheduler = class {
13914
13964
  */
13915
13965
  ensureHealthSchedules() {
13916
13966
  const projectsWithoutHealth = this.db.select({ id: projects.id }).from(projects).where(notExists(
13917
- this.db.select({ one: sql9`1` }).from(schedules).where(and18(
13918
- eq21(schedules.projectId, projects.id),
13919
- eq21(schedules.kind, SchedulableRunKinds.doctor)
13967
+ this.db.select({ one: sql9`1` }).from(schedules).where(and19(
13968
+ eq22(schedules.projectId, projects.id),
13969
+ eq22(schedules.kind, SchedulableRunKinds.doctor)
13920
13970
  ))
13921
13971
  )).all();
13922
13972
  if (projectsWithoutHealth.length === 0) return;
@@ -13959,7 +14009,7 @@ var Scheduler = class {
13959
14009
  start() {
13960
14010
  this.ensureHealthSchedules();
13961
14011
  this.ensureQueryBaskets();
13962
- const allSchedules = this.db.select().from(schedules).where(eq21(schedules.enabled, true)).all();
14012
+ const allSchedules = this.db.select().from(schedules).where(eq22(schedules.enabled, true)).all();
13963
14013
  for (const schedule of allSchedules) {
13964
14014
  const missedRunAt = schedule.nextRunAt;
13965
14015
  const recurrence = scheduleRecurrence(schedule);
@@ -13993,7 +14043,7 @@ var Scheduler = class {
13993
14043
  this.stopTask(key, existing, "Stopped");
13994
14044
  this.tasks.delete(key);
13995
14045
  }
13996
- const schedule = this.db.select().from(schedules).where(and18(eq21(schedules.projectId, projectId), eq21(schedules.kind, kind))).get();
14046
+ const schedule = this.db.select().from(schedules).where(and19(eq22(schedules.projectId, projectId), eq22(schedules.kind, kind))).get();
13997
14047
  if (schedule && schedule.enabled) {
13998
14048
  this.registerCronTask(schedule);
13999
14049
  }
@@ -14026,12 +14076,12 @@ var Scheduler = class {
14026
14076
  /** Runtime timing writes must not restore a version already issued to a settings caller. */
14027
14077
  updateScheduleTiming(scheduleId, timing) {
14028
14078
  this.db.transaction((tx) => {
14029
- const current = tx.select({ updatedAt: schedules.updatedAt }).from(schedules).where(eq21(schedules.id, scheduleId)).get();
14079
+ const current = tx.select({ updatedAt: schedules.updatedAt }).from(schedules).where(eq22(schedules.id, scheduleId)).get();
14030
14080
  if (!current) return;
14031
14081
  tx.update(schedules).set({
14032
14082
  ...timing,
14033
14083
  updatedAt: nextScheduleUpdatedAt(current.updatedAt)
14034
- }).where(eq21(schedules.id, scheduleId)).run();
14084
+ }).where(eq22(schedules.id, scheduleId)).run();
14035
14085
  });
14036
14086
  }
14037
14087
  registerCronTask(schedule, options = {}) {
@@ -14107,7 +14157,7 @@ var Scheduler = class {
14107
14157
  };
14108
14158
  const tick = () => {
14109
14159
  if (stopped) return;
14110
- const current = this.db.select().from(schedules).where(eq21(schedules.id, scheduleId)).get();
14160
+ const current = this.db.select().from(schedules).where(eq22(schedules.id, scheduleId)).get();
14111
14161
  if (!current || !current.enabled || !scheduleRecurrence(current)) {
14112
14162
  this.remove(projectId, kind);
14113
14163
  return;
@@ -14125,7 +14175,7 @@ var Scheduler = class {
14125
14175
  this.triggerRun(scheduleId, projectId, kind);
14126
14176
  }
14127
14177
  }
14128
- arm(this.db.select({ nextRunAt: schedules.nextRunAt }).from(schedules).where(eq21(schedules.id, scheduleId)).get()?.nextRunAt);
14178
+ arm(this.db.select({ nextRunAt: schedules.nextRunAt }).from(schedules).where(eq22(schedules.id, scheduleId)).get()?.nextRunAt);
14129
14179
  };
14130
14180
  this.tasks.set(key, task);
14131
14181
  let registeredNextRunAt = schedule.nextRunAt;
@@ -14140,7 +14190,7 @@ var Scheduler = class {
14140
14190
  /** Atomically advance a due callback-only calendar occurrence before dispatch. */
14141
14191
  claimCalendarOccurrence(schedule, dueAt, now) {
14142
14192
  return this.db.transaction((tx) => {
14143
- const current = tx.select().from(schedules).where(eq21(schedules.id, schedule.id)).get();
14193
+ const current = tx.select().from(schedules).where(eq22(schedules.id, schedule.id)).get();
14144
14194
  if (!current || !current.enabled || current.updatedAt !== schedule.updatedAt || current.nextRunAt !== dueAt) return false;
14145
14195
  const recurrence = scheduleRecurrence(current);
14146
14196
  if (!recurrence) return false;
@@ -14149,11 +14199,11 @@ var Scheduler = class {
14149
14199
  const result = tx.update(schedules).set({
14150
14200
  nextRunAt,
14151
14201
  updatedAt: nextScheduleUpdatedAt(current.updatedAt)
14152
- }).where(and18(
14153
- eq21(schedules.id, current.id),
14154
- eq21(schedules.enabled, true),
14155
- eq21(schedules.nextRunAt, dueAt),
14156
- eq21(schedules.updatedAt, schedule.updatedAt)
14202
+ }).where(and19(
14203
+ eq22(schedules.id, current.id),
14204
+ eq22(schedules.enabled, true),
14205
+ eq22(schedules.nextRunAt, dueAt),
14206
+ eq22(schedules.updatedAt, schedule.updatedAt)
14157
14207
  )).run();
14158
14208
  return result.changes === 1;
14159
14209
  });
@@ -14175,7 +14225,7 @@ var Scheduler = class {
14175
14225
  fireSlot(scheduleId, projectId, kind, claimedOccurrence) {
14176
14226
  try {
14177
14227
  const now = (/* @__PURE__ */ new Date()).toISOString();
14178
- const currentSchedule = this.db.select().from(schedules).where(eq21(schedules.id, scheduleId)).get();
14228
+ const currentSchedule = this.db.select().from(schedules).where(eq22(schedules.id, scheduleId)).get();
14179
14229
  if (!currentSchedule || !currentSchedule.enabled) {
14180
14230
  log18.warn("schedule.stale", { scheduleId, projectId, kind, msg: "schedule no longer exists or is disabled" });
14181
14231
  this.remove(projectId, kind);
@@ -14191,7 +14241,7 @@ var Scheduler = class {
14191
14241
  timezone: currentSchedule.timezone,
14192
14242
  recurrence
14193
14243
  });
14194
- const project = this.db.select().from(projects).where(eq21(projects.id, projectId)).get();
14244
+ const project = this.db.select().from(projects).where(eq22(projects.id, projectId)).get();
14195
14245
  if (!project) {
14196
14246
  log18.error("project.not-found", { projectId, kind, msg: "skipping scheduled run" });
14197
14247
  this.remove(projectId, kind);
@@ -14242,9 +14292,9 @@ var Scheduler = class {
14242
14292
  log18.warn("ads-sync.no-callback", { scheduleId, projectId, msg: "host did not register onAdsSyncRequested" });
14243
14293
  return slotFailed(OutcomeReasonCodes.UNSUPPORTED);
14244
14294
  }
14245
- const activeAdsRun = this.db.select({ id: runs.id }).from(runs).where(and18(
14246
- eq21(runs.projectId, projectId),
14247
- eq21(runs.kind, RunKinds["ads-sync"]),
14295
+ const activeAdsRun = this.db.select({ id: runs.id }).from(runs).where(and19(
14296
+ eq22(runs.projectId, projectId),
14297
+ eq22(runs.kind, RunKinds["ads-sync"]),
14248
14298
  inArray10(runs.status, [RunStatuses.queued, RunStatuses.running])
14249
14299
  )).get();
14250
14300
  if (activeAdsRun) {
@@ -14274,9 +14324,9 @@ var Scheduler = class {
14274
14324
  log18.warn("seo-sync.no-callback", { scheduleId, projectId, msg: "host did not register onSeoSyncRequested" });
14275
14325
  return slotFailed(OutcomeReasonCodes.UNSUPPORTED);
14276
14326
  }
14277
- const activeSeoRun = this.db.select({ id: runs.id }).from(runs).where(and18(
14278
- eq21(runs.projectId, projectId),
14279
- eq21(runs.kind, RunKinds["seo-sync"]),
14327
+ const activeSeoRun = this.db.select({ id: runs.id }).from(runs).where(and19(
14328
+ eq22(runs.projectId, projectId),
14329
+ eq22(runs.kind, RunKinds["seo-sync"]),
14280
14330
  inArray10(runs.status, [RunStatuses.queued, RunStatuses.running])
14281
14331
  )).get();
14282
14332
  if (activeSeoRun) {
@@ -14336,9 +14386,9 @@ var Scheduler = class {
14336
14386
  log18.warn("site-audit.no-callback", { scheduleId, projectId, msg: "host did not register onSiteAuditRequested" });
14337
14387
  return slotFailed(OutcomeReasonCodes.UNSUPPORTED);
14338
14388
  }
14339
- const active = this.db.select({ id: runs.id }).from(runs).where(and18(
14340
- eq21(runs.projectId, projectId),
14341
- eq21(runs.kind, RunKinds["site-audit"]),
14389
+ const active = this.db.select({ id: runs.id }).from(runs).where(and19(
14390
+ eq22(runs.projectId, projectId),
14391
+ eq22(runs.kind, RunKinds["site-audit"]),
14342
14392
  inArray10(runs.status, [RunStatuses.queued, RunStatuses.running])
14343
14393
  )).get();
14344
14394
  if (active) {
@@ -14554,7 +14604,7 @@ function startSiteLivenessLoop(deps, intervalMs = SITE_LIVENESS_INTERVAL_MS) {
14554
14604
 
14555
14605
  // src/review-webhook-delivery.ts
14556
14606
  import { createHash as createHash7 } from "crypto";
14557
- import { and as and19, asc as asc4, eq as eq22, isNull as isNull3, lte as lte2, or } from "drizzle-orm";
14607
+ import { and as and20, asc as asc4, eq as eq23, isNull as isNull3, lte as lte2, or } from "drizzle-orm";
14558
14608
  var log20 = createLogger("ReviewDelivery");
14559
14609
  var hash = (value) => createHash7("sha256").update(JSON.stringify(value)).digest("hex");
14560
14610
  var REVIEW_DELIVERY_MAX_ATTEMPTS = 10;
@@ -14582,20 +14632,20 @@ function reviewEventId(projectId, review) {
14582
14632
  function reviewEventRefusal(db, projectId, payload, notification, targetDigest, now) {
14583
14633
  if (!notification?.enabled || !notification.config.events.includes("review.negative")) return "destination_disabled";
14584
14634
  if (targetDigest !== void 0 && hash(notification.config.url) !== targetDigest) return "destination_changed";
14585
- const project = db.select().from(projects).where(eq22(projects.id, projectId)).get();
14635
+ const project = db.select().from(projects).where(eq23(projects.id, projectId)).get();
14586
14636
  if (!project || project.name !== payload.project.name || project.canonicalDomain !== payload.project.canonicalDomain) return "project_changed";
14587
14637
  const review = payload.reviews[0];
14588
- const location = db.select().from(gbpLocations).where(and19(
14589
- eq22(gbpLocations.projectId, projectId),
14590
- eq22(gbpLocations.locationName, review.location.name),
14591
- eq22(gbpLocations.selected, true)
14638
+ const location = db.select().from(gbpLocations).where(and20(
14639
+ eq23(gbpLocations.projectId, projectId),
14640
+ eq23(gbpLocations.locationName, review.location.name),
14641
+ eq23(gbpLocations.selected, true)
14592
14642
  )).get();
14593
14643
  if (!location || review.origin === "gbp" && !review.reviewName.startsWith(`${location.accountName}/${location.locationName}/reviews/`)) return "location_removed_or_deselected";
14594
- const current = db.select().from(gbpReviews).where(and19(
14595
- eq22(gbpReviews.projectId, projectId),
14596
- eq22(gbpReviews.origin, review.origin),
14597
- eq22(gbpReviews.reviewName, review.reviewName),
14598
- eq22(gbpReviews.locationName, review.location.name)
14644
+ const current = db.select().from(gbpReviews).where(and20(
14645
+ eq23(gbpReviews.projectId, projectId),
14646
+ eq23(gbpReviews.origin, review.origin),
14647
+ eq23(gbpReviews.reviewName, review.reviewName),
14648
+ eq23(gbpReviews.locationName, review.location.name)
14599
14649
  )).get();
14600
14650
  if (!current) return "review_removed";
14601
14651
  if (!isWithinAlertWindow(review.updateTime, now) || !isWithinAlertWindow(current.updateTime, now)) return "review_expired";
@@ -14603,10 +14653,10 @@ function reviewEventRefusal(db, projectId, payload, notification, targetDigest,
14603
14653
  if (!isNegativeReviewRating(current.starRating, threshold) || !isNegativeReviewRating(review.starRating, threshold)) return "review_no_longer_negative";
14604
14654
  if (["baseline", "skipped", "suppressed", "stale", "none"].includes(current.alertState)) return "review_suppressed";
14605
14655
  if (review.origin === "places") {
14606
- const v4HasWorked = db.select({ id: gbpReviewRatings.id }).from(gbpReviewRatings).where(and19(
14607
- eq22(gbpReviewRatings.projectId, projectId),
14608
- eq22(gbpReviewRatings.locationName, review.location.name),
14609
- eq22(gbpReviewRatings.origin, "gbp")
14656
+ const v4HasWorked = db.select({ id: gbpReviewRatings.id }).from(gbpReviewRatings).where(and20(
14657
+ eq23(gbpReviewRatings.projectId, projectId),
14658
+ eq23(gbpReviewRatings.locationName, review.location.name),
14659
+ eq23(gbpReviewRatings.origin, "gbp")
14610
14660
  )).get() !== void 0;
14611
14661
  if (businessProfileReviewsCover(location.reviewsAccess, v4HasWorked)) return "review_origin_superseded";
14612
14662
  }
@@ -14614,9 +14664,9 @@ function reviewEventRefusal(db, projectId, payload, notification, targetDigest,
14614
14664
  }
14615
14665
  function cancelReviewDelivery(db, id, reason) {
14616
14666
  db.transaction((tx) => {
14617
- const canceled = tx.update(reviewWebhookDeliveries).set({ state: ReviewDeliveryStates.Canceled, retryAt: null }).where(and19(
14618
- eq22(reviewWebhookDeliveries.id, id),
14619
- eq22(reviewWebhookDeliveries.state, ReviewDeliveryStates.Pending)
14667
+ const canceled = tx.update(reviewWebhookDeliveries).set({ state: ReviewDeliveryStates.Canceled, retryAt: null }).where(and20(
14668
+ eq23(reviewWebhookDeliveries.id, id),
14669
+ eq23(reviewWebhookDeliveries.state, ReviewDeliveryStates.Pending)
14620
14670
  )).returning({ projectId: reviewWebhookDeliveries.projectId, eventId: reviewWebhookDeliveries.eventId, notificationId: reviewWebhookDeliveries.notificationId, targetDigest: reviewWebhookDeliveries.targetDigest }).get();
14621
14671
  if (canceled) writeAuditLog(tx, {
14622
14672
  projectId: canceled.projectId,
@@ -14632,10 +14682,10 @@ function deferReviewDelivery(db, saved, now) {
14632
14682
  if (saved.state !== ReviewDeliveryStates.Pending && saved.state !== ReviewDeliveryStates.Attempting) return;
14633
14683
  const waited = now - Date.parse(saved.createdAt);
14634
14684
  const delay = Math.min(Math.max(RETRY_BASE_MS, Number.isFinite(waited) ? waited / 4 : RETRY_BASE_MS), RETRY_MAX_MS);
14635
- db.update(reviewWebhookDeliveries).set({ retryAt: new Date(now + delay).toISOString() }).where(and19(
14636
- eq22(reviewWebhookDeliveries.id, saved.id),
14637
- eq22(reviewWebhookDeliveries.state, saved.state),
14638
- eq22(reviewWebhookDeliveries.attempts, saved.attempts)
14685
+ db.update(reviewWebhookDeliveries).set({ retryAt: new Date(now + delay).toISOString() }).where(and20(
14686
+ eq23(reviewWebhookDeliveries.id, saved.id),
14687
+ eq23(reviewWebhookDeliveries.state, saved.state),
14688
+ eq23(reviewWebhookDeliveries.attempts, saved.attempts)
14639
14689
  )).run();
14640
14690
  }
14641
14691
  function auditUndelivered(db, saved, outcome) {
@@ -14652,8 +14702,8 @@ function dueReviewDeliveryProjects(db, now) {
14652
14702
  const at = new Date(now).toISOString();
14653
14703
  const staleAttempt = new Date(now - 6e4).toISOString();
14654
14704
  return db.selectDistinct({ projectId: reviewWebhookDeliveries.projectId }).from(reviewWebhookDeliveries).where(or(
14655
- and19(eq22(reviewWebhookDeliveries.state, ReviewDeliveryStates.Pending), or(isNull3(reviewWebhookDeliveries.retryAt), lte2(reviewWebhookDeliveries.retryAt, at))),
14656
- and19(eq22(reviewWebhookDeliveries.state, ReviewDeliveryStates.Attempting), lte2(reviewWebhookDeliveries.attemptedAt, staleAttempt))
14705
+ and20(eq23(reviewWebhookDeliveries.state, ReviewDeliveryStates.Pending), or(isNull3(reviewWebhookDeliveries.retryAt), lte2(reviewWebhookDeliveries.retryAt, at))),
14706
+ and20(eq23(reviewWebhookDeliveries.state, ReviewDeliveryStates.Attempting), lte2(reviewWebhookDeliveries.attemptedAt, staleAttempt))
14657
14707
  )).all().map((row) => row.projectId);
14658
14708
  }
14659
14709
  function startReviewDeliveryLoop(drain, intervalMs = REVIEW_DELIVERY_INTERVAL_MS) {
@@ -14674,12 +14724,12 @@ async function drainReviewDeliveries(options) {
14674
14724
  const now = (options.now ?? Date.now)();
14675
14725
  const at = new Date(now).toISOString();
14676
14726
  const staleAttempt = new Date(now - 6e4).toISOString();
14677
- const ready = options.db.select().from(reviewWebhookDeliveries).where(and19(
14678
- eq22(reviewWebhookDeliveries.projectId, options.projectId),
14727
+ const ready = options.db.select().from(reviewWebhookDeliveries).where(and20(
14728
+ eq23(reviewWebhookDeliveries.projectId, options.projectId),
14679
14729
  or(isNull3(reviewWebhookDeliveries.retryAt), lte2(reviewWebhookDeliveries.retryAt, at)),
14680
14730
  or(
14681
- eq22(reviewWebhookDeliveries.state, ReviewDeliveryStates.Pending),
14682
- and19(eq22(reviewWebhookDeliveries.state, ReviewDeliveryStates.Attempting), lte2(reviewWebhookDeliveries.attemptedAt, staleAttempt))
14731
+ eq23(reviewWebhookDeliveries.state, ReviewDeliveryStates.Pending),
14732
+ and20(eq23(reviewWebhookDeliveries.state, ReviewDeliveryStates.Attempting), lte2(reviewWebhookDeliveries.attemptedAt, staleAttempt))
14683
14733
  )
14684
14734
  )).orderBy(asc4(reviewWebhookDeliveries.retryAt), asc4(reviewWebhookDeliveries.attemptedAt), asc4(reviewWebhookDeliveries.createdAt), asc4(reviewWebhookDeliveries.id)).limit(100).all();
14685
14735
  let delivered = 0;
@@ -14703,15 +14753,15 @@ async function deliverReviewEvent(options) {
14703
14753
  if (!payload.eventId || !/^evt_[a-f0-9]{64}$/u.test(payload.eventId) || payload.reviews.length !== 1)
14704
14754
  return false;
14705
14755
  const notification = db.select().from(notifications).where(
14706
- and19(
14707
- eq22(notifications.id, notificationId),
14708
- eq22(notifications.projectId, projectId)
14756
+ and20(
14757
+ eq23(notifications.id, notificationId),
14758
+ eq23(notifications.projectId, projectId)
14709
14759
  )
14710
14760
  ).get();
14711
14761
  const id = hash([projectId, notificationId, payload.eventId]);
14712
14762
  const now = options.now ?? Date.now;
14713
14763
  const at = new Date(now()).toISOString();
14714
- let saved = db.select().from(reviewWebhookDeliveries).where(eq22(reviewWebhookDeliveries.id, id)).get();
14764
+ let saved = db.select().from(reviewWebhookDeliveries).where(eq23(reviewWebhookDeliveries.id, id)).get();
14715
14765
  const event = saved?.payload ?? payload;
14716
14766
  const refusal = reviewEventRefusal(db, projectId, event, notification, saved?.targetDigest, new Date(now()));
14717
14767
  if (refusal) {
@@ -14730,7 +14780,7 @@ async function deliverReviewEvent(options) {
14730
14780
  payload,
14731
14781
  createdAt: at
14732
14782
  }).onConflictDoNothing().run();
14733
- saved = db.select().from(reviewWebhookDeliveries).where(eq22(reviewWebhookDeliveries.id, id)).get();
14783
+ saved = db.select().from(reviewWebhookDeliveries).where(eq23(reviewWebhookDeliveries.id, id)).get();
14734
14784
  if (!saved || saved.targetDigest !== targetDigest) return false;
14735
14785
  if (saved.state === ReviewDeliveryStates.Sent) return true;
14736
14786
  if (saved.state === ReviewDeliveryStates.Uncertain || saved.state === ReviewDeliveryStates.Canceled) return false;
@@ -14745,17 +14795,17 @@ async function deliverReviewEvent(options) {
14745
14795
  return false;
14746
14796
  const state2 = destination.signed ? ReviewDeliveryStates.Pending : ReviewDeliveryStates.Uncertain;
14747
14797
  const moved = db.update(reviewWebhookDeliveries).set({ state: state2 }).where(
14748
- and19(
14749
- eq22(reviewWebhookDeliveries.id, id),
14750
- eq22(reviewWebhookDeliveries.state, ReviewDeliveryStates.Attempting),
14751
- eq22(reviewWebhookDeliveries.attempts, saved.attempts),
14752
- eq22(reviewWebhookDeliveries.attemptedAt, saved.attemptedAt)
14798
+ and20(
14799
+ eq23(reviewWebhookDeliveries.id, id),
14800
+ eq23(reviewWebhookDeliveries.state, ReviewDeliveryStates.Attempting),
14801
+ eq23(reviewWebhookDeliveries.attempts, saved.attempts),
14802
+ eq23(reviewWebhookDeliveries.attemptedAt, saved.attemptedAt)
14753
14803
  )
14754
14804
  ).returning({ id: reviewWebhookDeliveries.id }).get();
14755
14805
  if (moved && state2 === ReviewDeliveryStates.Uncertain) {
14756
14806
  auditUndelivered(db, saved, { state: state2, reason: "interrupted_attempt", attempts: saved.attempts });
14757
14807
  }
14758
- saved = db.select().from(reviewWebhookDeliveries).where(eq22(reviewWebhookDeliveries.id, id)).get();
14808
+ saved = db.select().from(reviewWebhookDeliveries).where(eq23(reviewWebhookDeliveries.id, id)).get();
14759
14809
  if (!saved || saved.state !== ReviewDeliveryStates.Pending) return false;
14760
14810
  }
14761
14811
  if (saved.retryAt && Date.parse(saved.retryAt) > now()) return false;
@@ -14777,9 +14827,9 @@ async function deliverReviewEvent(options) {
14777
14827
  return false;
14778
14828
  }
14779
14829
  const latest = db.select().from(notifications).where(
14780
- and19(
14781
- eq22(notifications.id, notificationId),
14782
- eq22(notifications.projectId, projectId)
14830
+ and20(
14831
+ eq23(notifications.id, notificationId),
14832
+ eq23(notifications.projectId, projectId)
14783
14833
  )
14784
14834
  ).get();
14785
14835
  const latestRefusal = reviewEventRefusal(db, projectId, saved.payload, latest, targetDigest, new Date(now()));
@@ -14792,10 +14842,10 @@ async function deliverReviewEvent(options) {
14792
14842
  attempts: saved.attempts + 1,
14793
14843
  attemptedAt: new Date(now()).toISOString()
14794
14844
  }).where(
14795
- and19(
14796
- eq22(reviewWebhookDeliveries.id, id),
14797
- eq22(reviewWebhookDeliveries.state, ReviewDeliveryStates.Pending),
14798
- eq22(reviewWebhookDeliveries.attempts, saved.attempts)
14845
+ and20(
14846
+ eq23(reviewWebhookDeliveries.id, id),
14847
+ eq23(reviewWebhookDeliveries.state, ReviewDeliveryStates.Pending),
14848
+ eq23(reviewWebhookDeliveries.attempts, saved.attempts)
14799
14849
  )
14800
14850
  ).returning({ id: reviewWebhookDeliveries.id }).get();
14801
14851
  if (!claimed) return false;
@@ -14822,10 +14872,10 @@ async function deliverReviewEvent(options) {
14822
14872
  deliveredAt: sent ? new Date(now()).toISOString() : null,
14823
14873
  retryAt: state === ReviewDeliveryStates.Pending ? new Date(now() + retryDelayMs(attempts, result.retryAfterSeconds)).toISOString() : null
14824
14874
  }).where(
14825
- and19(
14826
- eq22(reviewWebhookDeliveries.id, id),
14827
- eq22(reviewWebhookDeliveries.state, ReviewDeliveryStates.Attempting),
14828
- eq22(reviewWebhookDeliveries.attempts, attempts)
14875
+ and20(
14876
+ eq23(reviewWebhookDeliveries.id, id),
14877
+ eq23(reviewWebhookDeliveries.state, ReviewDeliveryStates.Attempting),
14878
+ eq23(reviewWebhookDeliveries.attempts, attempts)
14829
14879
  )
14830
14880
  ).run();
14831
14881
  if (state === ReviewDeliveryStates.Uncertain || state === ReviewDeliveryStates.Failed) {
@@ -14837,7 +14887,7 @@ async function deliverReviewEvent(options) {
14837
14887
  }
14838
14888
 
14839
14889
  // src/unrecognized-agent-alerts.ts
14840
- import { and as and20, desc as desc8, eq as eq23, gte as gte3, sql as sql10 } from "drizzle-orm";
14890
+ import { and as and21, desc as desc8, eq as eq24, gte as gte3, sql as sql10 } from "drizzle-orm";
14841
14891
  var log21 = createLogger("UnrecognizedAgentAlerts");
14842
14892
  var UNRECOGNIZED_AGENT_ALERT_WINDOW_MS = 7 * 864e5;
14843
14893
  var UNRECOGNIZED_AGENT_ALERT_MIN_HITS = 3;
@@ -14853,13 +14903,13 @@ function projectsWithRecentUnrecognizedAgents(db, now) {
14853
14903
  return db.selectDistinct({ projectId: unrecognizedAgentEventsHourly.projectId }).from(unrecognizedAgentEventsHourly).where(gte3(unrecognizedAgentEventsHourly.tsHour, since)).all().map((row) => row.projectId);
14854
14904
  }
14855
14905
  function undecidedUnrecognizedAgents(db, projectId, now) {
14856
- const decided = new Set(db.select({ agentName: unrecognizedAgentNotifyState.agentName }).from(unrecognizedAgentNotifyState).where(eq23(unrecognizedAgentNotifyState.projectId, projectId)).all().map((row) => row.agentName));
14906
+ const decided = new Set(db.select({ agentName: unrecognizedAgentNotifyState.agentName }).from(unrecognizedAgentNotifyState).where(eq24(unrecognizedAgentNotifyState.projectId, projectId)).all().map((row) => row.agentName));
14857
14907
  const totals = db.select({
14858
14908
  name: unrecognizedAgentEventsHourly.agentName,
14859
14909
  hits: sql10`SUM(${unrecognizedAgentEventsHourly.hits})`,
14860
14910
  firstSeenAt: sql10`MIN(${unrecognizedAgentEventsHourly.tsHour})`,
14861
14911
  lastSeenAt: sql10`MAX(${unrecognizedAgentEventsHourly.tsHour})`
14862
- }).from(unrecognizedAgentEventsHourly).where(eq23(unrecognizedAgentEventsHourly.projectId, projectId)).groupBy(unrecognizedAgentEventsHourly.agentName).all();
14912
+ }).from(unrecognizedAgentEventsHourly).where(eq24(unrecognizedAgentEventsHourly.projectId, projectId)).groupBy(unrecognizedAgentEventsHourly.agentName).all();
14863
14913
  const windowStart = new Date(now - UNRECOGNIZED_AGENT_ALERT_WINDOW_MS).toISOString();
14864
14914
  const recordingStart = totals.reduce((earliest, total) => earliest === null || total.firstSeenAt < earliest ? total.firstSeenAt : earliest, null);
14865
14915
  const baselineEnd = recordingStart === null ? null : new Date(Date.parse(recordingStart) + UNRECOGNIZED_AGENT_ALERT_WINDOW_MS).toISOString();
@@ -14877,7 +14927,7 @@ function undecidedUnrecognizedAgents(db, projectId, now) {
14877
14927
  continue;
14878
14928
  }
14879
14929
  if (Number(total.hits) < UNRECOGNIZED_AGENT_ALERT_MIN_HITS) continue;
14880
- const latest = db.select({ sampledUserAgent: unrecognizedAgentEventsHourly.sampledUserAgent, sampledPath: unrecognizedAgentEventsHourly.sampledPath }).from(unrecognizedAgentEventsHourly).where(and20(eq23(unrecognizedAgentEventsHourly.projectId, projectId), eq23(unrecognizedAgentEventsHourly.agentName, total.name))).orderBy(desc8(unrecognizedAgentEventsHourly.tsHour)).limit(1).get();
14930
+ const latest = db.select({ sampledUserAgent: unrecognizedAgentEventsHourly.sampledUserAgent, sampledPath: unrecognizedAgentEventsHourly.sampledPath }).from(unrecognizedAgentEventsHourly).where(and21(eq24(unrecognizedAgentEventsHourly.projectId, projectId), eq24(unrecognizedAgentEventsHourly.agentName, total.name))).orderBy(desc8(unrecognizedAgentEventsHourly.tsHour)).limit(1).get();
14881
14931
  due.push({
14882
14932
  name: total.name,
14883
14933
  hits: Number(total.hits),
@@ -14912,7 +14962,7 @@ function startUnrecognizedAgentAlertLoop(dispatch, intervalMs = UNRECOGNIZED_AGE
14912
14962
  }
14913
14963
 
14914
14964
  // src/provider-batch-poller.ts
14915
- import { and as and21, eq as eq24, inArray as inArray11, isNotNull as isNotNull3, isNull as isNull4, notExists as notExists2, sql as sql11 } from "drizzle-orm";
14965
+ import { and as and22, eq as eq25, inArray as inArray11, isNotNull as isNotNull3, isNull as isNull4, notExists as notExists2, sql as sql11 } from "drizzle-orm";
14916
14966
  var log22 = createLogger("ProviderBatchPoller");
14917
14967
  var PROVIDER_BATCH_POLL_INITIAL_MS = 3e4;
14918
14968
  var PROVIDER_BATCH_POLL_MAX_MS = 10 * 6e4;
@@ -14955,7 +15005,7 @@ var ProviderBatchPoller = class {
14955
15005
  * outstanding (ingested or cancelled), so its run may now finalize.
14956
15006
  */
14957
15007
  async advance(row) {
14958
- const runStatus = this.deps.db.select({ status: runs.status }).from(runs).where(eq24(runs.id, row.runId)).get()?.status;
15008
+ const runStatus = this.deps.db.select({ status: runs.status }).from(runs).where(eq25(runs.id, row.runId)).get()?.status;
14959
15009
  if (runStatus !== RunStatuses.running) {
14960
15010
  await this.deps.runner.abandonProviderBatches([row.id], "Cancelled because its run is no longer running.");
14961
15011
  this.schedule.delete(row.id);
@@ -14972,7 +15022,7 @@ var ProviderBatchPoller = class {
14972
15022
  status = poll.status;
14973
15023
  if (poll.status === "ended") {
14974
15024
  const endedAt = poll.endedAt ?? new Date(this.now()).toISOString();
14975
- const ended = this.deps.db.update(providerBatches).set({ status: ProviderBatchStatuses.ended, endedAt, resultsExpireAt: poll.resultsExpireAt ?? null, updatedAt: endedAt }).where(and21(eq24(providerBatches.id, row.id), eq24(providerBatches.status, ProviderBatchStatuses.submitted))).run().changes === 1;
15025
+ const ended = this.deps.db.update(providerBatches).set({ status: ProviderBatchStatuses.ended, endedAt, resultsExpireAt: poll.resultsExpireAt ?? null, updatedAt: endedAt }).where(and22(eq25(providerBatches.id, row.id), eq25(providerBatches.status, ProviderBatchStatuses.submitted))).run().changes === 1;
14976
15026
  this.schedule.delete(row.id);
14977
15027
  return ended ? this.ingest({ ...row, status: ProviderBatchStatuses.ended, resultsExpireAt: poll.resultsExpireAt ?? null }) : false;
14978
15028
  }
@@ -14996,9 +15046,9 @@ var ProviderBatchPoller = class {
14996
15046
  const at = new Date(now).toISOString();
14997
15047
  if (row.cancelRequestedAt === null) {
14998
15048
  if (now < Date.parse(row.deadlineAt)) return false;
14999
- const claimed = this.deps.db.update(providerBatches).set({ cancelRequestedAt: at, updatedAt: at }).where(and21(
15000
- eq24(providerBatches.id, row.id),
15001
- eq24(providerBatches.status, ProviderBatchStatuses.submitted),
15049
+ const claimed = this.deps.db.update(providerBatches).set({ cancelRequestedAt: at, updatedAt: at }).where(and22(
15050
+ eq25(providerBatches.id, row.id),
15051
+ eq25(providerBatches.status, ProviderBatchStatuses.submitted),
15002
15052
  isNull4(providerBatches.cancelRequestedAt)
15003
15053
  )).run().changes === 1;
15004
15054
  if (!claimed) return false;
@@ -15017,7 +15067,7 @@ var ProviderBatchPoller = class {
15017
15067
  status: ProviderBatchStatuses.cancelled,
15018
15068
  error: `The provider batch did not end within an hour of being cancelled at its deadline; its ${row.requestCount} answer(s) were not recorded.`,
15019
15069
  updatedAt: at
15020
- }).where(and21(eq24(providerBatches.id, row.id), eq24(providerBatches.status, ProviderBatchStatuses.submitted))).run().changes === 1;
15070
+ }).where(and22(eq25(providerBatches.id, row.id), eq25(providerBatches.status, ProviderBatchStatuses.submitted))).run().changes === 1;
15021
15071
  this.schedule.delete(row.id);
15022
15072
  if (gaveUp) log22.warn("batch.abandoned-after-deadline", { batchId: row.id, runId: row.runId, provider: row.provider });
15023
15073
  return gaveUp;
@@ -15057,10 +15107,10 @@ var ProviderBatchPoller = class {
15057
15107
  /** Runs the sweep handed off whose batches have all settled. */
15058
15108
  finalizableRuns() {
15059
15109
  const holding = [ProviderBatchStatuses.submitting, ...OUTSTANDING_PROVIDER_BATCH_STATUSES];
15060
- return this.deps.db.select({ id: runs.id, projectId: runs.projectId }).from(runs).where(and21(
15061
- eq24(runs.status, RunStatuses.running),
15110
+ return this.deps.db.select({ id: runs.id, projectId: runs.projectId }).from(runs).where(and22(
15111
+ eq25(runs.status, RunStatuses.running),
15062
15112
  isNotNull3(runs.pendingProviderErrors),
15063
- notExists2(this.deps.db.select({ one: sql11`1` }).from(providerBatches).where(and21(eq24(providerBatches.runId, runs.id), inArray11(providerBatches.status, holding))))
15113
+ notExists2(this.deps.db.select({ one: sql11`1` }).from(providerBatches).where(and22(eq25(providerBatches.runId, runs.id), inArray11(providerBatches.status, holding))))
15064
15114
  )).all();
15065
15115
  }
15066
15116
  };
@@ -15140,12 +15190,12 @@ async function refreshAllIntegrations(client, projectName, now = /* @__PURE__ */
15140
15190
  }
15141
15191
 
15142
15192
  // src/notifier.ts
15143
- import { eq as eq26, desc as desc10, and as and23, inArray as inArray12, or as or2, isNull as isNull5 } from "drizzle-orm";
15193
+ import { eq as eq27, desc as desc10, and as and24, inArray as inArray12, or as or2, isNull as isNull5 } from "drizzle-orm";
15144
15194
  import crypto23 from "crypto";
15145
15195
 
15146
15196
  // src/site-health-alerts.ts
15147
15197
  import crypto22 from "crypto";
15148
- import { and as and22, asc as asc5, desc as desc9, eq as eq25, gt as gt3 } from "drizzle-orm";
15198
+ import { and as and23, asc as asc5, desc as desc9, eq as eq26, gt as gt3 } from "drizzle-orm";
15149
15199
  var ISSUE_TITLES = {
15150
15200
  "missing-h1": "Missing H1",
15151
15201
  "multiple-h1": "Multiple H1 tags",
@@ -15158,18 +15208,18 @@ function siteHealthProblemKey(code, url) {
15158
15208
  return `${code}|${crypto22.createHash("sha256").update(url).digest("hex").slice(0, 16)}`;
15159
15209
  }
15160
15210
  function readSiteHealthScan(db, projectId, runId) {
15161
- const snapshot = db.select().from(siteCrawlSnapshots).where(and22(eq25(siteCrawlSnapshots.projectId, projectId), eq25(siteCrawlSnapshots.runId, runId))).orderBy(desc9(siteCrawlSnapshots.updatedAt)).limit(1).get();
15211
+ const snapshot = db.select().from(siteCrawlSnapshots).where(and23(eq26(siteCrawlSnapshots.projectId, projectId), eq26(siteCrawlSnapshots.runId, runId))).orderBy(desc9(siteCrawlSnapshots.updatedAt)).limit(1).get();
15162
15212
  if (!snapshot?.detailsAvailable || !snapshot.attemptId) return null;
15163
- const scope = and22(
15164
- eq25(siteCrawlPages.projectId, projectId),
15165
- eq25(siteCrawlPages.runId, runId),
15166
- eq25(siteCrawlPages.attemptId, snapshot.attemptId)
15213
+ const scope = and23(
15214
+ eq26(siteCrawlPages.projectId, projectId),
15215
+ eq26(siteCrawlPages.runId, runId),
15216
+ eq26(siteCrawlPages.attemptId, snapshot.attemptId)
15167
15217
  );
15168
15218
  const pagesByCode = /* @__PURE__ */ new Map();
15169
15219
  const keys = /* @__PURE__ */ new Set();
15170
15220
  let after;
15171
15221
  for (; ; ) {
15172
- const pages = db.select({ nodeKey: siteCrawlPages.nodeKey, url: siteCrawlPages.url, auditFields: siteCrawlPages.auditFields }).from(siteCrawlPages).where(after === void 0 ? scope : and22(scope, gt3(siteCrawlPages.nodeKey, after))).orderBy(asc5(siteCrawlPages.nodeKey)).limit(PAGE_BATCH).all();
15222
+ const pages = db.select({ nodeKey: siteCrawlPages.nodeKey, url: siteCrawlPages.url, auditFields: siteCrawlPages.auditFields }).from(siteCrawlPages).where(after === void 0 ? scope : and23(scope, gt3(siteCrawlPages.nodeKey, after))).orderBy(asc5(siteCrawlPages.nodeKey)).limit(PAGE_BATCH).all();
15173
15223
  for (const page of pages) {
15174
15224
  const defects = page.auditFields.criticalDefects;
15175
15225
  for (const defect of Array.isArray(defects) ? defects : []) {
@@ -15211,7 +15261,7 @@ function settledSiteHealthKeys(scan, reported) {
15211
15261
  return [...scan.complete ? scan.keys : /* @__PURE__ */ new Set([...reported, ...scan.keys])].sort(compareText);
15212
15262
  }
15213
15263
  function readSiteHealthNotifyState(db, projectId) {
15214
- return db.select().from(siteHealthNotifyState).where(eq25(siteHealthNotifyState.projectId, projectId)).get() ?? null;
15264
+ return db.select().from(siteHealthNotifyState).where(eq26(siteHealthNotifyState.projectId, projectId)).get() ?? null;
15215
15265
  }
15216
15266
  function writeSiteHealthNotifyState(db, input) {
15217
15267
  const values = { reportedKeys: input.reportedKeys, runId: input.runId, updatedAt: input.updatedAt, notifiedAt: input.notifiedAt };
@@ -15340,18 +15390,18 @@ var Notifier = class {
15340
15390
  /** Called after a run completes (success, partial, or failed). */
15341
15391
  async onRunCompleted(runId, projectId, opts) {
15342
15392
  log24.info("run.completed", { runId, projectId, origin: opts?.origin ?? "sweep" });
15343
- const notifs = this.db.select().from(notifications).where(eq26(notifications.projectId, projectId)).all().filter((n) => n.enabled);
15393
+ const notifs = this.db.select().from(notifications).where(eq27(notifications.projectId, projectId)).all().filter((n) => n.enabled);
15344
15394
  if (notifs.length === 0) {
15345
15395
  log24.info("notifications.none-enabled", { projectId });
15346
15396
  return;
15347
15397
  }
15348
15398
  log24.info("notifications.found", { projectId, count: notifs.length });
15349
- const run = this.db.select().from(runs).where(eq26(runs.id, runId)).get();
15399
+ const run = this.db.select().from(runs).where(eq27(runs.id, runId)).get();
15350
15400
  if (!run) {
15351
15401
  log24.error("run.not-found", { runId, msg: "skipping notification dispatch" });
15352
15402
  return;
15353
15403
  }
15354
- const project = this.db.select().from(projects).where(eq26(projects.id, projectId)).get();
15404
+ const project = this.db.select().from(projects).where(eq27(projects.id, projectId)).get();
15355
15405
  if (!project) {
15356
15406
  log24.error("project.not-found", { projectId, msg: "skipping notification dispatch" });
15357
15407
  return;
@@ -15430,7 +15480,7 @@ var Notifier = class {
15430
15480
  * than inferred from the absence of a webhook.
15431
15481
  */
15432
15482
  async onHealthChecked(projectId, report) {
15433
- const project = this.db.select().from(projects).where(eq26(projects.id, projectId)).get();
15483
+ const project = this.db.select().from(projects).where(eq27(projects.id, projectId)).get();
15434
15484
  if (!project) {
15435
15485
  log24.error("project.not-found", { projectId, msg: "skipping health notification" });
15436
15486
  return null;
@@ -15463,7 +15513,7 @@ var Notifier = class {
15463
15513
  const status = noSignal ? "warn" : worst ? worst.status : "ok";
15464
15514
  const code = noSignal ? HEALTH_NO_SIGNAL_CODE : worst?.code ?? "health.ok";
15465
15515
  const summary = noSignal ? `No health check produced a result (${healthChecks.length} skipped) \u2014 health is unknown, not confirmed.` : worst?.summary ?? `All ${graded.length} health check(s) passing.`;
15466
- const previous = this.db.select().from(doctorHealthState).where(eq26(doctorHealthState.projectId, projectId)).get();
15516
+ const previous = this.db.select().from(doctorHealthState).where(eq27(doctorHealthState.projectId, projectId)).get();
15467
15517
  const previousStatus = previous?.status ?? null;
15468
15518
  const failingSignature = failing.map((c) => `${c.status}:${c.code}`).join(",");
15469
15519
  const failingNow = failing.map((c) => ({ id: c.id, code: c.code, rank: rank(c.status) }));
@@ -15533,7 +15583,7 @@ var Notifier = class {
15533
15583
  const urgentById = new Map(urgentItems.map((item) => [item.id, item]));
15534
15584
  const generalEvent = event;
15535
15585
  const urgentRecord = previous?.urgentNotified ?? null;
15536
- const enabled = generalEvent || urgentItems.length > 0 || urgentRecord ? this.db.select().from(notifications).where(eq26(notifications.projectId, projectId)).all().filter((n) => n.enabled) : [];
15586
+ const enabled = generalEvent || urgentItems.length > 0 || urgentRecord ? this.db.select().from(notifications).where(eq27(notifications.projectId, projectId)).all().filter((n) => n.enabled) : [];
15537
15587
  const listedEvents = (notif) => notif.config.events;
15538
15588
  const hasUrl = (notif) => Boolean(notif.config.url);
15539
15589
  const urgentSubscribers = enabled.filter((n) => hasUrl(n) && (listedEvents(n) ?? []).some((e) => URGENT_HEALTH_EVENTS.has(e)));
@@ -15581,7 +15631,7 @@ var Notifier = class {
15581
15631
  if (previous === void 0) {
15582
15632
  this.db.insert(doctorHealthState).values({ ...observation, notifiedAt: null }).run();
15583
15633
  } else {
15584
- this.db.update(doctorHealthState).set(observation).where(eq26(doctorHealthState.projectId, projectId)).run();
15634
+ this.db.update(doctorHealthState).set(observation).where(eq27(doctorHealthState.projectId, projectId)).run();
15585
15635
  }
15586
15636
  for (const group of urgentGroups) {
15587
15637
  const { urgentEvent, urgentTold, urgentNew, urgentCleared, urgentNotifs, urgentSettled } = group;
@@ -15625,7 +15675,7 @@ var Notifier = class {
15625
15675
  }
15626
15676
  if (accepted > 0) {
15627
15677
  recordUrgentReceipts(urgentReceipts, group.subscribers, formatUrgentBreaches(urgentSettled) || null);
15628
- this.db.update(doctorHealthState).set({ urgentNotified: doctorUrgentSummary(urgentReceipts), urgentReceipts }).where(eq26(doctorHealthState.projectId, projectId)).run();
15678
+ this.db.update(doctorHealthState).set({ urgentNotified: doctorUrgentSummary(urgentReceipts), urgentReceipts }).where(eq27(doctorHealthState.projectId, projectId)).run();
15629
15679
  }
15630
15680
  if (urgentNotifs.length > 0) {
15631
15681
  log24.info("health.urgent-notified", {
@@ -15669,7 +15719,7 @@ var Notifier = class {
15669
15719
  if (await this.sendWebhook(config.url, payload, notif.id, projectId, notif.webhookSecret ?? null)) delivered += 1;
15670
15720
  }
15671
15721
  if (delivered > 0) {
15672
- this.db.update(doctorHealthState).set({ notifiedAt: now, notifiedSignature: formatBreaches(failingNow), pendingSignature: null }).where(eq26(doctorHealthState.projectId, projectId)).run();
15722
+ this.db.update(doctorHealthState).set({ notifiedAt: now, notifiedSignature: formatBreaches(failingNow), pendingSignature: null }).where(eq27(doctorHealthState.projectId, projectId)).run();
15673
15723
  }
15674
15724
  log24.info("health.notified", {
15675
15725
  projectId,
@@ -15699,12 +15749,12 @@ var Notifier = class {
15699
15749
  async onSiteLivenessChecked(projectId, result) {
15700
15750
  const { check, checkedAt } = result;
15701
15751
  if (check.status !== "ok" && check.status !== "fail") return null;
15702
- const project = this.db.select().from(projects).where(eq26(projects.id, projectId)).get();
15752
+ const project = this.db.select().from(projects).where(eq27(projects.id, projectId)).get();
15703
15753
  if (!project) {
15704
15754
  log24.error("project.not-found", { projectId, msg: "skipping site liveness notification" });
15705
15755
  return null;
15706
15756
  }
15707
- const previous = this.db.select().from(siteLivenessState).where(eq26(siteLivenessState.projectId, projectId)).get();
15757
+ const previous = this.db.select().from(siteLivenessState).where(eq27(siteLivenessState.projectId, projectId)).get();
15708
15758
  const sincePrevious = previous ? Date.parse(checkedAt) - Date.parse(previous.checkedAt) : Number.NaN;
15709
15759
  const countsAsRepeat = Number.isFinite(sincePrevious) && sincePrevious >= SITE_LIVENESS_MIN_PASS_GAP_MS && sincePrevious <= SITE_LIVENESS_MAX_PASS_GAP_MS;
15710
15760
  const failures = check.status === "fail" ? countsAsRepeat ? (previous?.consecutiveFailures ?? 0) + 1 : 1 : 0;
@@ -15714,7 +15764,7 @@ var Notifier = class {
15714
15764
  if (check.status === "ok" && outagePaged) event = "health.recovered";
15715
15765
  const confirmed = check.status === "fail" && failures >= SITE_LIVENESS_FAILURES_TO_PAGE;
15716
15766
  const urgentRecord = previous?.urgentNotifiedAt ?? null;
15717
- const enabled = event !== null || confirmed || urgentRecord !== null ? this.db.select().from(notifications).where(eq26(notifications.projectId, projectId)).all().filter((n) => n.enabled) : [];
15767
+ const enabled = event !== null || confirmed || urgentRecord !== null ? this.db.select().from(notifications).where(eq27(notifications.projectId, projectId)).all().filter((n) => n.enabled) : [];
15718
15768
  const listedEvents = (notif) => notif.config.events;
15719
15769
  const hasUrl = (notif) => Boolean(notif.config.url);
15720
15770
  const scoped = enabled.filter((n) => hasUrl(n) && (listedEvents(n) ?? []).some((e) => URGENT_HEALTH_EVENTS.has(e)));
@@ -15747,7 +15797,7 @@ var Notifier = class {
15747
15797
  if (previous === void 0) {
15748
15798
  this.db.insert(siteLivenessState).values(observation).run();
15749
15799
  } else {
15750
- this.db.update(siteLivenessState).set(observation).where(eq26(siteLivenessState.projectId, projectId)).run();
15800
+ this.db.update(siteLivenessState).set(observation).where(eq27(siteLivenessState.projectId, projectId)).run();
15751
15801
  }
15752
15802
  if (!event && urgentGroups.every((group) => group.urgentEvent === null)) return null;
15753
15803
  const payloadFor = (name) => {
@@ -15783,7 +15833,7 @@ var Notifier = class {
15783
15833
  }
15784
15834
  }
15785
15835
  if (event === "health.degraded" && delivered > 0) {
15786
- this.db.update(siteLivenessState).set({ notifiedAt: checkedAt }).where(eq26(siteLivenessState.projectId, projectId)).run();
15836
+ this.db.update(siteLivenessState).set({ notifiedAt: checkedAt }).where(eq27(siteLivenessState.projectId, projectId)).run();
15787
15837
  }
15788
15838
  log24.info("site-liveness.notified", { projectId, event, code: check.code, subscribers: notifs.length, delivered });
15789
15839
  }
@@ -15797,7 +15847,7 @@ var Notifier = class {
15797
15847
  }
15798
15848
  if (accepted > 0) {
15799
15849
  recordUrgentReceipts(urgentReceipts, group.subscribers, group.settled);
15800
- this.db.update(siteLivenessState).set({ urgentNotifiedAt: siteUrgentSummary(urgentReceipts), urgentReceipts }).where(eq26(siteLivenessState.projectId, projectId)).run();
15850
+ this.db.update(siteLivenessState).set({ urgentNotifiedAt: siteUrgentSummary(urgentReceipts), urgentReceipts }).where(eq27(siteLivenessState.projectId, projectId)).run();
15801
15851
  }
15802
15852
  if (urgentNotifs.length > 0 || generalIds.size > 0) {
15803
15853
  log24.info("site-liveness.urgent-notified", { projectId, event: urgentEvent, code: check.code, subscribers: urgentNotifs.length + generalIds.size, delivered: accepted });
@@ -15823,7 +15873,7 @@ var Notifier = class {
15823
15873
  */
15824
15874
  isNewInsightNews(projectId, insight) {
15825
15875
  const key = insightNotifyKey(projectId, insight);
15826
- const previous = this.db.select().from(insightNotifyState).where(eq26(insightNotifyState.key, key)).get();
15876
+ const previous = this.db.select().from(insightNotifyState).where(eq27(insightNotifyState.key, key)).get();
15827
15877
  if (!previous) return true;
15828
15878
  if (severityRank(insight.severity) > severityRank(previous.severity)) return true;
15829
15879
  const magnitude = insightMagnitude(insight);
@@ -15845,9 +15895,9 @@ var Notifier = class {
15845
15895
  magnitude: insightMagnitude(insight),
15846
15896
  notifiedAt: (/* @__PURE__ */ new Date()).toISOString()
15847
15897
  };
15848
- const existing = this.db.select().from(insightNotifyState).where(eq26(insightNotifyState.key, key)).get();
15898
+ const existing = this.db.select().from(insightNotifyState).where(eq27(insightNotifyState.key, key)).get();
15849
15899
  if (existing) {
15850
- this.db.update(insightNotifyState).set(row).where(eq26(insightNotifyState.key, key)).run();
15900
+ this.db.update(insightNotifyState).set(row).where(eq27(insightNotifyState.key, key)).run();
15851
15901
  } else {
15852
15902
  this.db.insert(insightNotifyState).values(row).run();
15853
15903
  }
@@ -15861,11 +15911,11 @@ var Notifier = class {
15861
15911
  if (criticalInsights.length > 0) insightEvents.push("insight.critical");
15862
15912
  if (highInsights.length > 0) insightEvents.push("insight.high");
15863
15913
  if (insightEvents.length === 0) return;
15864
- const notifs = this.db.select().from(notifications).where(eq26(notifications.projectId, projectId)).all().filter((n) => n.enabled);
15914
+ const notifs = this.db.select().from(notifications).where(eq27(notifications.projectId, projectId)).all().filter((n) => n.enabled);
15865
15915
  if (notifs.length === 0) return;
15866
- const run = this.db.select().from(runs).where(eq26(runs.id, runId)).get();
15916
+ const run = this.db.select().from(runs).where(eq27(runs.id, runId)).get();
15867
15917
  if (!run) return;
15868
- const project = this.db.select().from(projects).where(eq26(projects.id, projectId)).get();
15918
+ const project = this.db.select().from(projects).where(eq27(projects.id, projectId)).get();
15869
15919
  if (!project) return;
15870
15920
  for (const notif of notifs) {
15871
15921
  const config = notif.config;
@@ -15946,9 +15996,9 @@ var Notifier = class {
15946
15996
  return delivered;
15947
15997
  }
15948
15998
  async dispatchQueuedReviewAlerts(projectId) {
15949
- const pendingReviews = this.db.select().from(gbpReviews).where(and23(eq26(gbpReviews.projectId, projectId), eq26(gbpReviews.alertState, "pending"))).all();
15950
- const pendingRatings = this.db.select().from(gbpReviewRatings).where(and23(eq26(gbpReviewRatings.projectId, projectId), eq26(gbpReviewRatings.alertState, "pending"))).all();
15951
- const project = this.db.select().from(projects).where(eq26(projects.id, projectId)).get();
15999
+ const pendingReviews = this.db.select().from(gbpReviews).where(and24(eq27(gbpReviews.projectId, projectId), eq27(gbpReviews.alertState, "pending"))).all();
16000
+ const pendingRatings = this.db.select().from(gbpReviewRatings).where(and24(eq27(gbpReviewRatings.projectId, projectId), eq27(gbpReviewRatings.alertState, "pending"))).all();
16001
+ const project = this.db.select().from(projects).where(eq27(projects.id, projectId)).get();
15952
16002
  if (!project) return { reviews: 0, ratingDrops: 0, delivered: 0 };
15953
16003
  const chatSendsLeft = /* @__PURE__ */ new Map();
15954
16004
  const now = /* @__PURE__ */ new Date();
@@ -15960,10 +16010,10 @@ var Notifier = class {
15960
16010
  displayName: gbpLocations.displayName,
15961
16011
  mapsUri: gbpLocations.mapsUri,
15962
16012
  reviewsAccess: gbpLocations.reviewsAccess
15963
- }).from(gbpLocations).where(eq26(gbpLocations.projectId, projectId)).all().map((loc) => [loc.locationName, loc])
16013
+ }).from(gbpLocations).where(eq27(gbpLocations.projectId, projectId)).all().map((loc) => [loc.locationName, loc])
15964
16014
  );
15965
16015
  const v4HasWorked = new Set(
15966
- this.db.select({ locationName: gbpReviewRatings.locationName }).from(gbpReviewRatings).where(and23(eq26(gbpReviewRatings.projectId, projectId), eq26(gbpReviewRatings.origin, "gbp"))).all().map((row) => row.locationName)
16016
+ this.db.select({ locationName: gbpReviewRatings.locationName }).from(gbpReviewRatings).where(and24(eq27(gbpReviewRatings.projectId, projectId), eq27(gbpReviewRatings.origin, "gbp"))).all().map((row) => row.locationName)
15967
16017
  );
15968
16018
  const coveredByBusinessProfile = (locationName) => businessProfileReviewsCover(locations.get(locationName)?.reviewsAccess ?? null, v4HasWorked.has(locationName));
15969
16019
  const locationRef = (locationName) => {
@@ -15992,7 +16042,7 @@ var Notifier = class {
15992
16042
  else if (row.rating === null || row.previousRating === null) setRatingState([row.id], "none");
15993
16043
  else ratingsToSend.push(row);
15994
16044
  }
15995
- const enabled = this.db.select().from(notifications).where(eq26(notifications.projectId, projectId)).all().filter((n) => n.enabled && n.config.url);
16045
+ const enabled = this.db.select().from(notifications).where(eq27(notifications.projectId, projectId)).all().filter((n) => n.enabled && n.config.url);
15996
16046
  const subscribedTo = (event) => enabled.filter((n) => (n.config.events ?? []).includes(event));
15997
16047
  const projectRef = { name: project.name, canonicalDomain: project.canonicalDomain };
15998
16048
  const dashboardUrl = `${this.serverUrl}/projects/${project.name}`;
@@ -16046,13 +16096,13 @@ var Notifier = class {
16046
16096
  if (!sent) all = false;
16047
16097
  }
16048
16098
  if (all) {
16049
- this.db.update(gbpReviews).set({ alertState: "sent", alertStateAt: nowIso }).where(and23(
16050
- eq26(gbpReviews.id, review.id),
16051
- eq26(gbpReviews.alertState, "pending"),
16052
- eq26(gbpReviews.updateTime, review.updateTime),
16053
- review.alertStateAt === null ? isNull5(gbpReviews.alertStateAt) : eq26(gbpReviews.alertStateAt, review.alertStateAt),
16054
- review.comment === null ? isNull5(gbpReviews.comment) : eq26(gbpReviews.comment, review.comment),
16055
- review.starRating === null ? isNull5(gbpReviews.starRating) : eq26(gbpReviews.starRating, review.starRating)
16099
+ this.db.update(gbpReviews).set({ alertState: "sent", alertStateAt: nowIso }).where(and24(
16100
+ eq27(gbpReviews.id, review.id),
16101
+ eq27(gbpReviews.alertState, "pending"),
16102
+ eq27(gbpReviews.updateTime, review.updateTime),
16103
+ review.alertStateAt === null ? isNull5(gbpReviews.alertStateAt) : eq27(gbpReviews.alertStateAt, review.alertStateAt),
16104
+ review.comment === null ? isNull5(gbpReviews.comment) : eq27(gbpReviews.comment, review.comment),
16105
+ review.starRating === null ? isNull5(gbpReviews.starRating) : eq27(gbpReviews.starRating, review.starRating)
16056
16106
  )).run();
16057
16107
  }
16058
16108
  }
@@ -16093,7 +16143,7 @@ var Notifier = class {
16093
16143
  return { reviews: reviewsToSend.length, ratingDrops: ratingsToSend.length, delivered };
16094
16144
  }
16095
16145
  computeTransitions(runId, projectId) {
16096
- const thisRun = this.db.select().from(runs).where(eq26(runs.id, runId)).get();
16146
+ const thisRun = this.db.select().from(runs).where(eq27(runs.id, runId)).get();
16097
16147
  if (!thisRun) return [];
16098
16148
  const completeness = measurementRunCompleteness(this.db, runId);
16099
16149
  if (completeness.planned && !completeness.complete) {
@@ -16104,10 +16154,10 @@ var Notifier = class {
16104
16154
  });
16105
16155
  return [];
16106
16156
  }
16107
- const groupSiblings = this.db.select().from(runs).where(and23(
16108
- eq26(runs.projectId, projectId),
16109
- eq26(runs.kind, thisRun.kind),
16110
- eq26(runs.createdAt, thisRun.createdAt),
16157
+ const groupSiblings = this.db.select().from(runs).where(and24(
16158
+ eq27(runs.projectId, projectId),
16159
+ eq27(runs.kind, thisRun.kind),
16160
+ eq27(runs.createdAt, thisRun.createdAt),
16111
16161
  notProbeRun()
16112
16162
  )).all();
16113
16163
  const stillPending = groupSiblings.some((r) => r.status === "queued" || r.status === "running");
@@ -16124,17 +16174,17 @@ var Notifier = class {
16124
16174
  return candidate.id > best.id ? candidate : best;
16125
16175
  });
16126
16176
  if (winner.id !== runId) return [];
16127
- const projectLocations = this.db.select({ locations: projects.locations }).from(projects).where(eq26(projects.id, projectId)).get();
16177
+ const projectLocations = this.db.select({ locations: projects.locations }).from(projects).where(eq27(projects.id, projectId)).get();
16128
16178
  const locationCount = Math.max(
16129
16179
  1,
16130
16180
  (projectLocations?.locations ?? []).length
16131
16181
  );
16132
16182
  const RECENT_FETCH_LIMIT = Math.max(8, locationCount * 4);
16133
16183
  const recentRuns = this.db.select().from(runs).where(
16134
- and23(
16135
- eq26(runs.projectId, projectId),
16136
- eq26(runs.kind, thisRun.kind),
16137
- or2(eq26(runs.status, "completed"), eq26(runs.status, "partial")),
16184
+ and24(
16185
+ eq27(runs.projectId, projectId),
16186
+ eq27(runs.kind, thisRun.kind),
16187
+ or2(eq27(runs.status, "completed"), eq27(runs.status, "partial")),
16138
16188
  notProbeRun()
16139
16189
  )
16140
16190
  ).orderBy(desc10(runs.createdAt), desc10(runs.id)).limit(RECENT_FETCH_LIMIT).all();
@@ -16152,7 +16202,7 @@ var Notifier = class {
16152
16202
  provider: querySnapshots.provider,
16153
16203
  location: querySnapshots.location,
16154
16204
  citationState: querySnapshots.citationState
16155
- }).from(querySnapshots).leftJoin(queries, eq26(querySnapshots.queryId, queries.id)).where(inArray12(querySnapshots.runId, currentRunIds)).all();
16205
+ }).from(querySnapshots).leftJoin(queries, eq27(querySnapshots.queryId, queries.id)).where(inArray12(querySnapshots.runId, currentRunIds)).all();
16156
16206
  const previousSnapshots = this.db.select({
16157
16207
  queryId: querySnapshots.queryId,
16158
16208
  provider: querySnapshots.provider,
@@ -16203,12 +16253,12 @@ var Notifier = class {
16203
16253
  recordUnrecognizedAgentDecisions(this.db, projectId, baseline, UnrecognizedAgentNotifyStates.baseline, now);
16204
16254
  if (due.length === 0) continue;
16205
16255
  const names = due.map((agent) => agent.name);
16206
- const subscribed = this.db.select().from(notifications).where(eq26(notifications.projectId, projectId)).all().filter((n) => n.enabled && n.config.url && n.config.events.includes("traffic.agent.discovered"));
16256
+ const subscribed = this.db.select().from(notifications).where(eq27(notifications.projectId, projectId)).all().filter((n) => n.enabled && n.config.url && n.config.events.includes("traffic.agent.discovered"));
16207
16257
  if (subscribed.length === 0) {
16208
16258
  recordUnrecognizedAgentDecisions(this.db, projectId, names, UnrecognizedAgentNotifyStates.skipped, now);
16209
16259
  continue;
16210
16260
  }
16211
- const project = this.db.select().from(projects).where(eq26(projects.id, projectId)).get();
16261
+ const project = this.db.select().from(projects).where(eq27(projects.id, projectId)).get();
16212
16262
  if (!project) continue;
16213
16263
  const payload = {
16214
16264
  source: "canonry",
@@ -16247,12 +16297,12 @@ var Notifier = class {
16247
16297
  * observable in tests.
16248
16298
  */
16249
16299
  async onSiteAuditCompleted(runId, projectId) {
16250
- const run = this.db.select().from(runs).where(eq26(runs.id, runId)).get();
16300
+ const run = this.db.select().from(runs).where(eq27(runs.id, runId)).get();
16251
16301
  if (!run || run.kind !== RunKinds["site-audit"]) return null;
16252
16302
  if (run.status !== RunStatuses.completed && run.status !== RunStatuses.partial) return null;
16253
- const subscribed = this.db.select().from(notifications).where(eq26(notifications.projectId, projectId)).all().filter((n) => n.enabled && n.config.url && n.config.events.includes("site-health.issue.new"));
16303
+ const subscribed = this.db.select().from(notifications).where(eq27(notifications.projectId, projectId)).all().filter((n) => n.enabled && n.config.url && n.config.events.includes("site-health.issue.new"));
16254
16304
  if (subscribed.length === 0) return null;
16255
- const project = this.db.select().from(projects).where(eq26(projects.id, projectId)).get();
16305
+ const project = this.db.select().from(projects).where(eq27(projects.id, projectId)).get();
16256
16306
  if (!project) return null;
16257
16307
  const scan = readSiteHealthScan(this.db, projectId, runId);
16258
16308
  if (!scan) return null;
@@ -16378,7 +16428,7 @@ var Notifier = class {
16378
16428
  };
16379
16429
 
16380
16430
  // src/run-coordinator.ts
16381
- import { eq as eq27 } from "drizzle-orm";
16431
+ import { eq as eq28 } from "drizzle-orm";
16382
16432
  var log25 = createLogger("RunCoordinator");
16383
16433
  function reportInsightsGenerated(runTrigger, outcome) {
16384
16434
  trackFeatureCompleted({
@@ -16412,7 +16462,7 @@ var RunCoordinator = class {
16412
16462
  */
16413
16463
  onAnswersRecorded;
16414
16464
  async onRunCompleted(runId, projectId, opts) {
16415
- const runRow = this.db.select().from(runs).where(eq27(runs.id, runId)).get();
16465
+ const runRow = this.db.select().from(runs).where(eq28(runs.id, runId)).get();
16416
16466
  const kind = runRow?.kind ?? RunKinds["answer-visibility"];
16417
16467
  if (runRow?.trigger === RunTriggers.probe) {
16418
16468
  log25.info("probe.skip-side-effects", { runId, projectId, kind });
@@ -16539,7 +16589,7 @@ var RunCoordinator = class {
16539
16589
  * so the Aero queue is never starved of a follow-up.
16540
16590
  */
16541
16591
  buildDiscoveryAeroContext(runId, projectId, status, error) {
16542
- const session = this.db.select().from(discoverySessions).where(eq27(discoverySessions.runId, runId)).get();
16592
+ const session = this.db.select().from(discoverySessions).where(eq28(discoverySessions.runId, runId)).get();
16543
16593
  const competitorMap = session ? session.competitorMap : [];
16544
16594
  return {
16545
16595
  kind: RunKinds["aeo-discover-probe"],
@@ -16582,7 +16632,7 @@ function analysisResultFromInsights(insights2) {
16582
16632
 
16583
16633
  // src/agent/session-registry.ts
16584
16634
  import crypto25 from "crypto";
16585
- import { eq as eq30 } from "drizzle-orm";
16635
+ import { eq as eq31 } from "drizzle-orm";
16586
16636
 
16587
16637
  // src/agent/remote-mcp.ts
16588
16638
  import { Type } from "@earendil-works/pi-ai";
@@ -16687,7 +16737,7 @@ async function loadExternalMcpTools(servers, opts = {}) {
16687
16737
 
16688
16738
  // src/agent/memory-store.ts
16689
16739
  import crypto24 from "crypto";
16690
- import { and as and24, desc as desc11, eq as eq28, like, sql as sql12, or as or3 } from "drizzle-orm";
16740
+ import { and as and25, desc as desc11, eq as eq29, like, sql as sql12, or as or3 } from "drizzle-orm";
16691
16741
  var COMPACTION_KEY_PREFIX = "compaction:";
16692
16742
  var COMPACTION_NOTES_PER_SESSION = 3;
16693
16743
  function rowToDto(row) {
@@ -16701,7 +16751,7 @@ function rowToDto(row) {
16701
16751
  };
16702
16752
  }
16703
16753
  function listMemoryEntries(db, projectId, opts = {}) {
16704
- const query = db.select().from(agentMemory).where(eq28(agentMemory.projectId, projectId)).orderBy(desc11(agentMemory.updatedAt));
16754
+ const query = db.select().from(agentMemory).where(eq29(agentMemory.projectId, projectId)).orderBy(desc11(agentMemory.updatedAt));
16705
16755
  const rows = opts.limit === void 0 ? query.all() : query.limit(opts.limit).all();
16706
16756
  return rows.map(rowToDto);
16707
16757
  }
@@ -16732,20 +16782,20 @@ function upsertMemoryEntry(db, args) {
16732
16782
  updatedAt: now
16733
16783
  }
16734
16784
  }).run();
16735
- const row = db.select().from(agentMemory).where(and24(eq28(agentMemory.projectId, args.projectId), eq28(agentMemory.key, args.key))).get();
16785
+ const row = db.select().from(agentMemory).where(and25(eq29(agentMemory.projectId, args.projectId), eq29(agentMemory.key, args.key))).get();
16736
16786
  if (!row) throw new Error("memory upsert produced no row");
16737
16787
  return rowToDto(row);
16738
16788
  }
16739
16789
  function deleteMemoryEntry(db, projectId, key) {
16740
- const result = db.delete(agentMemory).where(and24(eq28(agentMemory.projectId, projectId), eq28(agentMemory.key, key))).run();
16790
+ const result = db.delete(agentMemory).where(and25(eq29(agentMemory.projectId, projectId), eq29(agentMemory.key, key))).run();
16741
16791
  const changes = result.changes ?? 0;
16742
16792
  return changes > 0;
16743
16793
  }
16744
16794
  function loadRecentForHydrate(db, projectId, limit, sessionId) {
16745
16795
  if (sessionId === void 0) return listMemoryEntries(db, projectId, { limit });
16746
16796
  const sessionPrefix = `compaction:${sessionId ?? ""}:`;
16747
- return db.select().from(agentMemory).where(and24(
16748
- eq28(agentMemory.projectId, projectId),
16797
+ return db.select().from(agentMemory).where(and25(
16798
+ eq29(agentMemory.projectId, projectId),
16749
16799
  or3(sql12`substr(${agentMemory.key}, 1, ${COMPACTION_KEY_PREFIX.length}) <> ${COMPACTION_KEY_PREFIX}`, sessionId ? sql12`substr(${agentMemory.key}, 1, ${sessionPrefix.length}) = ${sessionPrefix}` : void 0)
16750
16800
  )).orderBy(desc11(agentMemory.updatedAt)).limit(limit).all().map(rowToDto);
16751
16801
  }
@@ -16771,8 +16821,8 @@ function writeCompactionNote(db, args) {
16771
16821
  }).run();
16772
16822
  const sessionPrefix = `${COMPACTION_KEY_PREFIX}${args.sessionId}:`;
16773
16823
  const existing = tx.select({ id: agentMemory.id, updatedAt: agentMemory.updatedAt }).from(agentMemory).where(
16774
- and24(
16775
- eq28(agentMemory.projectId, args.projectId),
16824
+ and25(
16825
+ eq29(agentMemory.projectId, args.projectId),
16776
16826
  like(agentMemory.key, `${sessionPrefix}%`)
16777
16827
  )
16778
16828
  ).orderBy(desc11(agentMemory.updatedAt)).all();
@@ -16780,7 +16830,7 @@ function writeCompactionNote(db, args) {
16780
16830
  if (stale.length > 0) {
16781
16831
  tx.delete(agentMemory).where(sql12`${agentMemory.id} IN (${sql12.join(stale.map((s) => sql12`${s}`), sql12`, `)})`).run();
16782
16832
  }
16783
- const row = tx.select().from(agentMemory).where(and24(eq28(agentMemory.projectId, args.projectId), eq28(agentMemory.key, key))).get();
16833
+ const row = tx.select().from(agentMemory).where(and25(eq29(agentMemory.projectId, args.projectId), eq29(agentMemory.key, key))).get();
16784
16834
  if (row) inserted = rowToDto(row);
16785
16835
  });
16786
16836
  if (!inserted) throw new Error("compaction note write produced no row");
@@ -16854,7 +16904,7 @@ function trackAeroTurn(agent, turn) {
16854
16904
  }
16855
16905
 
16856
16906
  // src/agent/project-shape.ts
16857
- import { and as and25, count as count5, eq as eq29 } from "drizzle-orm";
16907
+ import { and as and26, count as count5, eq as eq30 } from "drizzle-orm";
16858
16908
  var ADVANCED_TOOLS = [
16859
16909
  "canonry_measurement_portfolio_summary",
16860
16910
  "canonry_measurement_overview",
@@ -16881,10 +16931,10 @@ var ADVANCED_ROUTES = [
16881
16931
  ];
16882
16932
  function aeroProjectShape(db, projectId) {
16883
16933
  try {
16884
- const pointer = db.select().from(measurementPlans).where(eq29(measurementPlans.projectId, projectId)).get();
16885
- const version = pointer ? db.select().from(measurementPlanVersions).where(and25(
16886
- eq29(measurementPlanVersions.projectId, projectId),
16887
- eq29(measurementPlanVersions.id, pointer.activeVersionId)
16934
+ const pointer = db.select().from(measurementPlans).where(eq30(measurementPlans.projectId, projectId)).get();
16935
+ const version = pointer ? db.select().from(measurementPlanVersions).where(and26(
16936
+ eq30(measurementPlanVersions.projectId, projectId),
16937
+ eq30(measurementPlanVersions.id, pointer.activeVersionId)
16888
16938
  )).get() : void 0;
16889
16939
  if (version) {
16890
16940
  const plan = JSON.parse(version.canonicalJson);
@@ -16911,7 +16961,7 @@ canonry_visibility_report describes the whole project, not one Property. canonry
16911
16961
  pinned: ADVANCED_TOOLS
16912
16962
  };
16913
16963
  }
16914
- const tracked = db.select({ total: count5() }).from(queries).where(eq29(queries.projectId, projectId)).get()?.total ?? 0;
16964
+ const tracked = db.select({ total: count5() }).from(queries).where(eq30(queries.projectId, projectId)).get()?.total ?? 0;
16915
16965
  return {
16916
16966
  prompt: `
16917
16967
 
@@ -17170,7 +17220,7 @@ var SessionRegistry = class {
17170
17220
  modelProvider: effectiveProvider,
17171
17221
  modelId: effectiveModelId,
17172
17222
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
17173
- }).where(eq30(agentSessions.projectId, projectId)).run();
17223
+ }).where(eq31(agentSessions.projectId, projectId)).run();
17174
17224
  }
17175
17225
  const agent2 = createAeroSession({
17176
17226
  projectName,
@@ -17489,7 +17539,7 @@ ${lines.join("\n")}
17489
17539
  modelProvider: nextProvider,
17490
17540
  modelId: nextModelId,
17491
17541
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
17492
- }).where(eq30(agentSessions.projectId, projectId)).run();
17542
+ }).where(eq31(agentSessions.projectId, projectId)).run();
17493
17543
  }
17494
17544
  /** Snapshot pending work without consuming it before an atomic conversation switch. */
17495
17545
  prepareConversationChange(projectName) {
@@ -17714,11 +17764,11 @@ ${lines.join("\n")}
17714
17764
  return id;
17715
17765
  }
17716
17766
  tryResolveProjectId(projectName) {
17717
- const row = this.opts.db.select({ id: projects.id }).from(projects).where(eq30(projects.name, projectName)).get();
17767
+ const row = this.opts.db.select({ id: projects.id }).from(projects).where(eq31(projects.name, projectName)).get();
17718
17768
  return row?.id;
17719
17769
  }
17720
17770
  loadRow(projectId) {
17721
- const row = this.opts.db.select().from(agentSessions).where(eq30(agentSessions.projectId, projectId)).get();
17771
+ const row = this.opts.db.select().from(agentSessions).where(eq31(agentSessions.projectId, projectId)).get();
17722
17772
  return row ?? null;
17723
17773
  }
17724
17774
  insertRow(params) {
@@ -17738,7 +17788,7 @@ ${lines.join("\n")}
17738
17788
  }
17739
17789
  updateRow(projectId, patch) {
17740
17790
  const now = (/* @__PURE__ */ new Date()).toISOString();
17741
- this.opts.db.update(agentSessions).set({ ...patch, updatedAt: now }).where(eq30(agentSessions.projectId, projectId)).run();
17791
+ this.opts.db.update(agentSessions).set({ ...patch, updatedAt: now }).where(eq31(agentSessions.projectId, projectId)).run();
17742
17792
  }
17743
17793
  /**
17744
17794
  * Store a refreshed prompt snapshot without touching `updatedAt`, which the
@@ -17747,13 +17797,13 @@ ${lines.join("\n")}
17747
17797
  * recently used right after an upgrade.
17748
17798
  */
17749
17799
  persistPromptSnapshot(projectId, systemPrompt) {
17750
- this.opts.db.update(agentSessions).set({ systemPrompt }).where(eq30(agentSessions.projectId, projectId)).run();
17800
+ this.opts.db.update(agentSessions).set({ systemPrompt }).where(eq31(agentSessions.projectId, projectId)).run();
17751
17801
  }
17752
17802
  };
17753
17803
 
17754
17804
  // src/agent/viewer-sessions.ts
17755
17805
  import crypto26 from "crypto";
17756
- import { and as and26, eq as eq31, isNotNull as isNotNull4, like as like2 } from "drizzle-orm";
17806
+ import { and as and27, eq as eq32, isNotNull as isNotNull4, like as like2 } from "drizzle-orm";
17757
17807
  var AERO_VIEWER_EXCLUDED_MCP_TOOLS = /* @__PURE__ */ new Set([
17758
17808
  CanonryMcpToolNames.canonry_ads_account,
17759
17809
  CanonryMcpToolNames.canonry_ads_geo_search,
@@ -17930,12 +17980,12 @@ var ViewerAeroSessions = class {
17930
17980
  */
17931
17981
  removeKey(id) {
17932
17982
  try {
17933
- this.opts.db.delete(apiKeys).where(eq31(apiKeys.id, id)).run();
17983
+ this.opts.db.delete(apiKeys).where(eq32(apiKeys.id, id)).run();
17934
17984
  } catch {
17935
17985
  try {
17936
17986
  this.opts.db.transaction((tx) => {
17937
- tx.delete(dashboardSessions).where(eq31(dashboardSessions.apiKeyId, id)).run();
17938
- tx.update(apiKeys).set({ revokedAt: new Date(this.now()).toISOString() }).where(eq31(apiKeys.id, id)).run();
17987
+ tx.delete(dashboardSessions).where(eq32(dashboardSessions.apiKeyId, id)).run();
17988
+ tx.update(apiKeys).set({ revokedAt: new Date(this.now()).toISOString() }).where(eq32(apiKeys.id, id)).run();
17939
17989
  });
17940
17990
  } catch {
17941
17991
  }
@@ -17948,7 +17998,7 @@ var ViewerAeroSessions = class {
17948
17998
  */
17949
17999
  revokeOrphanedKeys() {
17950
18000
  try {
17951
- this.opts.db.delete(apiKeys).where(and26(like2(apiKeys.name, `${VIEWER_AERO_KEY_PREFIX}%`), isNotNull4(apiKeys.delegatedUserId))).run();
18001
+ this.opts.db.delete(apiKeys).where(and27(like2(apiKeys.name, `${VIEWER_AERO_KEY_PREFIX}%`), isNotNull4(apiKeys.delegatedUserId))).run();
17952
18002
  } catch {
17953
18003
  }
17954
18004
  }
@@ -17965,7 +18015,7 @@ var ViewerAeroSessions = class {
17965
18015
  // src/mcp-http.ts
17966
18016
  import crypto27 from "crypto";
17967
18017
  import { isIP } from "net";
17968
- import { and as and27, eq as eq32, isNull as isNull6 } from "drizzle-orm";
18018
+ import { and as and28, eq as eq33, isNull as isNull6 } from "drizzle-orm";
17969
18019
  import { NodeStreamableHTTPServerTransport, toNodeHandler, toWebRequest } from "@modelcontextprotocol/node";
17970
18020
  import { McpServer, createMcpHandler, isInitializeRequest, isLegacyRequest } from "@modelcontextprotocol/server";
17971
18021
  var SESSION_IDLE_MS = 10 * 60 * 1e3;
@@ -18071,12 +18121,12 @@ function registerMcpHttpRoutes(scope, opts) {
18071
18121
  try {
18072
18122
  withoutLockWait(() => {
18073
18123
  opts.db.transaction((tx) => {
18074
- tx.delete(dashboardSessions).where(eq32(dashboardSessions.apiKeyId, id)).run();
18075
- tx.update(apiKeys).set({ revokedAt: new Date(now()).toISOString() }).where(and27(eq32(apiKeys.id, id), isNull6(apiKeys.revokedAt))).run();
18124
+ tx.delete(dashboardSessions).where(eq33(dashboardSessions.apiKeyId, id)).run();
18125
+ tx.update(apiKeys).set({ revokedAt: new Date(now()).toISOString() }).where(and28(eq33(apiKeys.id, id), isNull6(apiKeys.revokedAt))).run();
18076
18126
  });
18077
18127
  if (remove) {
18078
18128
  try {
18079
- opts.db.delete(apiKeys).where(eq32(apiKeys.id, id)).run();
18129
+ opts.db.delete(apiKeys).where(eq33(apiKeys.id, id)).run();
18080
18130
  } catch (error) {
18081
18131
  scope.log.warn({ err: error, keyId: id }, "Retained revoked MCP request key after deletion failed");
18082
18132
  }
@@ -18127,14 +18177,14 @@ function registerMcpHttpRoutes(scope, opts) {
18127
18177
  withoutLockWait(() => {
18128
18178
  const cutoff = now() - SESSION_IDLE_MS;
18129
18179
  for (const session of legacyServers) {
18130
- const key = session.sessionKeyId ? opts.db.select({ revokedAt: apiKeys.revokedAt }).from(apiKeys).where(eq32(apiKeys.id, session.sessionKeyId)).get() : void 0;
18180
+ const key = session.sessionKeyId ? opts.db.select({ revokedAt: apiKeys.revokedAt }).from(apiKeys).where(eq33(apiKeys.id, session.sessionKeyId)).get() : void 0;
18131
18181
  if (session.lastSeenAt < cutoff || session.expiresAt !== void 0 && session.expiresAt <= now() || session.sessionKeyId && (!key || key.revokedAt)) {
18132
18182
  void session.close().catch((error) => scope.log.error({ err: error }, "Failed to close expired MCP session"));
18133
18183
  }
18134
18184
  }
18135
18185
  for (const exchange of modernExchanges) {
18136
18186
  if (!exchange.sessionKey) continue;
18137
- const key = opts.db.select({ revokedAt: apiKeys.revokedAt }).from(apiKeys).where(eq32(apiKeys.id, exchange.sessionKey.id)).get();
18187
+ const key = opts.db.select({ revokedAt: apiKeys.revokedAt }).from(apiKeys).where(eq33(apiKeys.id, exchange.sessionKey.id)).get();
18138
18188
  if (!key || key.revokedAt || exchange.sessionKey.expiresAt <= now()) {
18139
18189
  void exchange.close().catch((error) => scope.log.error({ err: error }, "Failed to close expired MCP request"));
18140
18190
  }
@@ -18384,7 +18434,7 @@ function registerMcpHttpRoutes(scope, opts) {
18384
18434
  }
18385
18435
 
18386
18436
  // src/agent/agent-routes.ts
18387
- import { eq as eq33 } from "drizzle-orm";
18437
+ import { eq as eq34 } from "drizzle-orm";
18388
18438
  function viewerAeroCaller(request, opts) {
18389
18439
  if (!opts.viewerSessions) return null;
18390
18440
  const principal = request.principal;
@@ -18424,7 +18474,7 @@ function turnAttribution(request) {
18424
18474
  };
18425
18475
  }
18426
18476
  function resolveProject(db, name) {
18427
- const row = db.select({ id: projects.id, name: projects.name }).from(projects).where(eq33(projects.name, name)).get();
18477
+ const row = db.select({ id: projects.id, name: projects.name }).from(projects).where(eq34(projects.name, name)).get();
18428
18478
  if (!row) throw notFound("project", name);
18429
18479
  return row;
18430
18480
  }
@@ -18543,7 +18593,7 @@ function registerAgentRoutes(app, opts) {
18543
18593
  }
18544
18594
  requireInstanceAdministrator(request);
18545
18595
  const project = resolveProject(opts.db, request.params.name);
18546
- const row = opts.db.select().from(agentSessions).where(eq33(agentSessions.projectId, project.id)).get();
18596
+ const row = opts.db.select().from(agentSessions).where(eq34(agentSessions.projectId, project.id)).get();
18547
18597
  const nextTurn = opts.sessionRegistry.nextTurnModel(project.name);
18548
18598
  if (!row) {
18549
18599
  return { conversationId: null, messages: [], modelProvider: null, modelId: null, nextTurn, updatedAt: null };
@@ -18585,7 +18635,7 @@ function registerAgentRoutes(app, opts) {
18585
18635
  const project = resolveProject(opts.db, request.params.name);
18586
18636
  if (opts.sessionRegistry.isBusy(project.name)) throw agentBusy(project.name);
18587
18637
  opts.sessionRegistry.reset(project.name);
18588
- opts.db.update(agentSessions).set({ messages: "[]", followUpQueue: "[]", updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq33(agentSessions.projectId, project.id)).run();
18638
+ opts.db.update(agentSessions).set({ messages: "[]", followUpQueue: "[]", updatedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq34(agentSessions.projectId, project.id)).run();
18589
18639
  return { status: "reset" };
18590
18640
  }
18591
18641
  );
@@ -18609,7 +18659,7 @@ function registerAgentRoutes(app, opts) {
18609
18659
  return streamViewerTurn(opts, project, viewerId, body, reply, turnAttribution(request));
18610
18660
  }
18611
18661
  if (body.conversationId !== void 0) {
18612
- const current = opts.db.select({ id: agentSessions.id }).from(agentSessions).where(eq33(agentSessions.projectId, project.id)).get();
18662
+ const current = opts.db.select({ id: agentSessions.id }).from(agentSessions).where(eq34(agentSessions.projectId, project.id)).get();
18613
18663
  if ((current?.id ?? null) !== body.conversationId) throw validationError("The active conversation changed. Reload the conversation before sending.");
18614
18664
  }
18615
18665
  const promptText = body.prompt;
@@ -19569,7 +19619,7 @@ function clipText(value, length) {
19569
19619
  }
19570
19620
 
19571
19621
  // src/research-runner.ts
19572
- import { and as and28, eq as eq34, inArray as inArray13, sql as sql13 } from "drizzle-orm";
19622
+ import { and as and29, eq as eq35, inArray as inArray13, sql as sql13 } from "drizzle-orm";
19573
19623
  var unfinishedResearchQueryStatuses = [ResearchQueryStatuses.queued, ResearchQueryStatuses.running];
19574
19624
  function finalResearchRunStatus(completed, failed, waiting) {
19575
19625
  if (waiting > 0) return ResearchRunStatuses["waiting-upstream"];
@@ -19577,13 +19627,13 @@ function finalResearchRunStatus(completed, failed, waiting) {
19577
19627
  return completed > 0 ? ResearchRunStatuses.partial : ResearchRunStatuses.failed;
19578
19628
  }
19579
19629
  async function executeResearchRun(db, registry, runId, projectId, options = {}) {
19580
- const run = db.select().from(researchRuns).where(and28(eq34(researchRuns.id, runId), eq34(researchRuns.projectId, projectId))).get();
19630
+ const run = db.select().from(researchRuns).where(and29(eq35(researchRuns.id, runId), eq35(researchRuns.projectId, projectId))).get();
19581
19631
  if (!run || run.status !== ResearchRunStatuses.queued) return;
19582
- const project = db.select().from(projects).where(eq34(projects.id, projectId)).get();
19632
+ const project = db.select().from(projects).where(eq35(projects.id, projectId)).get();
19583
19633
  if (!project) return;
19584
19634
  const provider = registry.get(run.provider);
19585
19635
  const now = (/* @__PURE__ */ new Date()).toISOString();
19586
- const claim = db.update(researchRuns).set({ status: ResearchRunStatuses.running, startedAt: now }).where(and28(eq34(researchRuns.id, runId), eq34(researchRuns.status, ResearchRunStatuses.queued))).run();
19636
+ const claim = db.update(researchRuns).set({ status: ResearchRunStatuses.running, startedAt: now }).where(and29(eq35(researchRuns.id, runId), eq35(researchRuns.status, ResearchRunStatuses.queued))).run();
19587
19637
  if (claim.changes !== 1) return;
19588
19638
  const elapsed = startOutcomeTimer();
19589
19639
  const requested = currentOutcomeOrigin();
@@ -19617,8 +19667,8 @@ async function executeResearchRun(db, registry, runId, projectId, options = {})
19617
19667
  }
19618
19668
  reserved = run.totalQueries;
19619
19669
  reservation = { scope, period };
19620
- const rows = db.select().from(researchRunQueries).where(eq34(researchRunQueries.researchRunId, runId)).orderBy(researchRunQueries.position).all();
19621
- const competitorRows = db.select(competitorIdentityColumns).from(competitors).where(eq34(competitors.projectId, projectId)).orderBy(competitors.domain).all();
19670
+ const rows = db.select().from(researchRunQueries).where(eq35(researchRunQueries.researchRunId, runId)).orderBy(researchRunQueries.position).all();
19671
+ const competitorRows = db.select(competitorIdentityColumns).from(competitors).where(eq35(competitors.projectId, projectId)).orderBy(competitors.domain).all();
19622
19672
  const competitorDomains = competitorRows.map((row) => row.domain);
19623
19673
  const competitorAliases = new Map(competitorRows.map((row) => [row.domain, competitorIdentityAliases(row)]).filter(([, aliases]) => aliases.length > 0));
19624
19674
  const domains = effectiveDomains(project);
@@ -19628,7 +19678,7 @@ async function executeResearchRun(db, registry, runId, projectId, options = {})
19628
19678
  await mapWithConcurrency(rows, Math.max(1, provider.config.quotaPolicy.maxConcurrency), async (row) => {
19629
19679
  try {
19630
19680
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
19631
- db.update(researchRunQueries).set({ status: ResearchQueryStatuses.running, startedAt }).where(and28(eq34(researchRunQueries.id, row.id), eq34(researchRunQueries.status, ResearchQueryStatuses.queued))).run();
19681
+ db.update(researchRunQueries).set({ status: ResearchQueryStatuses.running, startedAt }).where(and29(eq35(researchRunQueries.id, row.id), eq35(researchRunQueries.status, ResearchQueryStatuses.queued))).run();
19632
19682
  const raw = await gate.run(async () => {
19633
19683
  dispatched++;
19634
19684
  return provider.adapter.executeTrackedQuery({ query: row.queryText, canonicalDomains: domains, competitorDomains, ...run.location ? { location: run.location } : {} }, config);
@@ -19659,7 +19709,7 @@ async function executeResearchRun(db, registry, runId, projectId, options = {})
19659
19709
  rawResponse: raw.rawResponse,
19660
19710
  answerEvidence: raw.evidence ?? null,
19661
19711
  finishedAt: (/* @__PURE__ */ new Date()).toISOString()
19662
- }).where(and28(eq34(researchRunQueries.id, row.id), eq34(researchRunQueries.status, ResearchQueryStatuses.running))).run();
19712
+ }).where(and29(eq35(researchRunQueries.id, row.id), eq35(researchRunQueries.status, ResearchQueryStatuses.running))).run();
19663
19713
  if (completed.changes === 1) incrementResearchProgress(db, runId, "completedQueries");
19664
19714
  } catch (error) {
19665
19715
  if (!(error instanceof IncompleteAnswerError && error.resumable)) queryFailure ??= error;
@@ -19710,11 +19760,11 @@ function researchOutcomeStatus(status) {
19710
19760
  }
19711
19761
  }
19712
19762
  function incrementResearchProgress(db, runId, column) {
19713
- db.update(researchRuns).set({ [column]: sql13`${researchRuns[column]} + 1` }).where(eq34(researchRuns.id, runId)).run();
19763
+ db.update(researchRuns).set({ [column]: sql13`${researchRuns[column]} + 1` }).where(eq35(researchRuns.id, runId)).run();
19714
19764
  }
19715
19765
  function markResearchQueryFailed(db, runId, queryId, error) {
19716
19766
  const message = describeError(error);
19717
- const unfinished = and28(eq34(researchRunQueries.id, queryId), inArray13(researchRunQueries.status, unfinishedResearchQueryStatuses));
19767
+ const unfinished = and29(eq35(researchRunQueries.id, queryId), inArray13(researchRunQueries.status, unfinishedResearchQueryStatuses));
19718
19768
  if (error instanceof IncompleteAnswerError && error.resumable) {
19719
19769
  db.update(researchRunQueries).set({
19720
19770
  status: ResearchQueryStatuses["waiting-upstream"],
@@ -19730,10 +19780,10 @@ function markResearchQueryFailed(db, runId, queryId, error) {
19730
19780
  if (failed.changes === 1) incrementResearchProgress(db, runId, "failedQueries");
19731
19781
  }
19732
19782
  function markUnfinishedResearchQueriesFailed(db, runId, error) {
19733
- db.update(researchRunQueries).set({ status: ResearchQueryStatuses.failed, error, finishedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(and28(eq34(researchRunQueries.researchRunId, runId), inArray13(researchRunQueries.status, unfinishedResearchQueryStatuses))).run();
19783
+ db.update(researchRunQueries).set({ status: ResearchQueryStatuses.failed, error, finishedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(and29(eq35(researchRunQueries.researchRunId, runId), inArray13(researchRunQueries.status, unfinishedResearchQueryStatuses))).run();
19734
19784
  }
19735
19785
  function finalizeResearchRun(db, runId, fatalError) {
19736
- const rows = db.select({ status: researchRunQueries.status }).from(researchRunQueries).where(eq34(researchRunQueries.researchRunId, runId)).all();
19786
+ const rows = db.select({ status: researchRunQueries.status }).from(researchRunQueries).where(eq35(researchRunQueries.researchRunId, runId)).all();
19737
19787
  const completed = rows.filter((row) => row.status === ResearchQueryStatuses.completed).length;
19738
19788
  const failed = rows.filter((row) => row.status === ResearchQueryStatuses.failed).length;
19739
19789
  const waiting = rows.filter((row) => row.status === ResearchQueryStatuses["waiting-upstream"]).length;
@@ -19745,12 +19795,12 @@ function finalizeResearchRun(db, runId, fatalError) {
19745
19795
  error: fatalError ?? (failed === rows.length ? "Every research query failed." : null),
19746
19796
  // A run waiting on upstream jobs has not finished.
19747
19797
  finishedAt: waiting > 0 ? null : (/* @__PURE__ */ new Date()).toISOString()
19748
- }).where(eq34(researchRuns.id, runId)).run();
19798
+ }).where(eq35(researchRuns.id, runId)).run();
19749
19799
  return { status, total: rows.length, completed, failed };
19750
19800
  }
19751
19801
 
19752
19802
  // src/google-marketing-sync.ts
19753
- import { and as and29, eq as eq35, isNull as isNull7, sql as sql14 } from "drizzle-orm";
19803
+ import { and as and30, eq as eq36, isNull as isNull7, sql as sql14 } from "drizzle-orm";
19754
19804
  var RUNTIME_FAILURE_REASONS = {
19755
19805
  INVALID_INPUT: OutcomeReasonCodes.VALIDATION,
19756
19806
  NOT_CONFIGURED: OutcomeReasonCodes.NOT_CONNECTED,
@@ -19787,10 +19837,10 @@ function assertSnapshotContext(metadata, expected) {
19787
19837
  }
19788
19838
  }
19789
19839
  function requireSyncRun(db, runId, projectId, kind) {
19790
- const run = db.select().from(runs).where(and29(
19791
- eq35(runs.id, runId),
19792
- eq35(runs.projectId, projectId),
19793
- eq35(runs.kind, kind)
19840
+ const run = db.select().from(runs).where(and30(
19841
+ eq36(runs.id, runId),
19842
+ eq36(runs.projectId, projectId),
19843
+ eq36(runs.kind, kind)
19794
19844
  )).get();
19795
19845
  if (!run) throw withOutcomeReason(new Error(`Run ${runId} is not a ${kind} run for this project.`), OutcomeReasonCodes.NOT_FOUND);
19796
19846
  if (run.status !== RunStatuses.queued) {
@@ -19806,19 +19856,19 @@ function markFailed(db, runId, projectId, kind, expectedStatus, error) {
19806
19856
  status: RunStatuses.failed,
19807
19857
  error: serializeRunError({ message: safeErrorMessage(error) }),
19808
19858
  finishedAt: (/* @__PURE__ */ new Date()).toISOString()
19809
- }).where(and29(
19810
- eq35(runs.id, runId),
19811
- eq35(runs.projectId, projectId),
19812
- eq35(runs.kind, kind),
19813
- eq35(runs.status, expectedStatus)
19859
+ }).where(and30(
19860
+ eq36(runs.id, runId),
19861
+ eq36(runs.projectId, projectId),
19862
+ eq36(runs.kind, kind),
19863
+ eq36(runs.status, expectedStatus)
19814
19864
  )).run();
19815
19865
  }
19816
19866
  function claimSyncRun(db, runId, projectId, kind, startedAt) {
19817
- const claim = db.update(runs).set({ status: RunStatuses.running, startedAt, error: null }).where(and29(
19818
- eq35(runs.id, runId),
19819
- eq35(runs.projectId, projectId),
19820
- eq35(runs.kind, kind),
19821
- eq35(runs.status, RunStatuses.queued)
19867
+ const claim = db.update(runs).set({ status: RunStatuses.running, startedAt, error: null }).where(and30(
19868
+ eq36(runs.id, runId),
19869
+ eq36(runs.projectId, projectId),
19870
+ eq36(runs.kind, kind),
19871
+ eq36(runs.status, RunStatuses.queued)
19822
19872
  )).run();
19823
19873
  return claim.changes === 1;
19824
19874
  }
@@ -19828,9 +19878,9 @@ async function executeGoogleAdsMarketingSync(db, runtime, runId, projectId) {
19828
19878
  let evidenceCollected = false;
19829
19879
  try {
19830
19880
  requireSyncRun(db, runId, projectId, RunKinds["google-ads-sync"]);
19831
- const project = db.select().from(projects).where(eq35(projects.id, projectId)).get();
19881
+ const project = db.select().from(projects).where(eq36(projects.id, projectId)).get();
19832
19882
  if (!project) throw withOutcomeReason(new Error(`Project ${projectId} was not found.`), OutcomeReasonCodes.NOT_FOUND);
19833
- const connection = db.select().from(googleAdsConnections).where(eq35(googleAdsConnections.projectId, projectId)).get();
19883
+ const connection = db.select().from(googleAdsConnections).where(eq36(googleAdsConnections.projectId, projectId)).get();
19834
19884
  if (!connection?.selectedCustomerId) {
19835
19885
  throw withOutcomeReason(new Error("Google Ads needs a selected customer before it can sync."), OutcomeReasonCodes.ACCOUNT_NOT_FOUND);
19836
19886
  }
@@ -19882,11 +19932,11 @@ async function executeGoogleAdsMarketingSync(db, runtime, runId, projectId) {
19882
19932
  status: RunStatuses.completed,
19883
19933
  finishedAt,
19884
19934
  error: null
19885
- }).where(and29(
19886
- eq35(runs.id, runId),
19887
- eq35(runs.projectId, projectId),
19888
- eq35(runs.kind, RunKinds["google-ads-sync"]),
19889
- eq35(runs.status, RunStatuses.running)
19935
+ }).where(and30(
19936
+ eq36(runs.id, runId),
19937
+ eq36(runs.projectId, projectId),
19938
+ eq36(runs.kind, RunKinds["google-ads-sync"]),
19939
+ eq36(runs.status, RunStatuses.running)
19890
19940
  )).run();
19891
19941
  if (terminalClaim.changes !== 1) {
19892
19942
  throw withOutcomeReason(
@@ -19906,12 +19956,12 @@ async function executeGoogleAdsMarketingSync(db, runtime, runId, projectId) {
19906
19956
  lastMetricsSnapshotAt: result.metrics?.metadata.capturedAt ?? connection.lastMetricsSnapshotAt,
19907
19957
  lastMetricsSnapshotId: result.metrics?.metadata.id ?? connection.lastMetricsSnapshotId,
19908
19958
  updatedAt: finishedAt
19909
- }).where(and29(
19910
- eq35(googleAdsConnections.id, connection.id),
19911
- eq35(googleAdsConnections.projectId, projectId),
19912
- eq35(googleAdsConnections.selectedCustomerId, connection.selectedCustomerId),
19913
- connection.selectedLoginCustomerId === null ? isNull7(googleAdsConnections.selectedLoginCustomerId) : eq35(googleAdsConnections.selectedLoginCustomerId, connection.selectedLoginCustomerId),
19914
- eq35(googleAdsConnections.selectionGeneration, connection.selectionGeneration)
19959
+ }).where(and30(
19960
+ eq36(googleAdsConnections.id, connection.id),
19961
+ eq36(googleAdsConnections.projectId, projectId),
19962
+ eq36(googleAdsConnections.selectedCustomerId, connection.selectedCustomerId),
19963
+ connection.selectedLoginCustomerId === null ? isNull7(googleAdsConnections.selectedLoginCustomerId) : eq36(googleAdsConnections.selectedLoginCustomerId, connection.selectedLoginCustomerId),
19964
+ eq36(googleAdsConnections.selectionGeneration, connection.selectionGeneration)
19915
19965
  )).run();
19916
19966
  if (connectionClaim.changes !== 1) {
19917
19967
  throw withOutcomeReason(
@@ -19951,9 +20001,9 @@ async function executeGtmMarketingSync(db, runtime, runId, projectId) {
19951
20001
  let evidenceCollected = false;
19952
20002
  try {
19953
20003
  requireSyncRun(db, runId, projectId, RunKinds["gtm-sync"]);
19954
- const project = db.select().from(projects).where(eq35(projects.id, projectId)).get();
20004
+ const project = db.select().from(projects).where(eq36(projects.id, projectId)).get();
19955
20005
  if (!project) throw withOutcomeReason(new Error(`Project ${projectId} was not found.`), OutcomeReasonCodes.NOT_FOUND);
19956
- const connection = db.select().from(gtmConnections).where(eq35(gtmConnections.projectId, projectId)).get();
20006
+ const connection = db.select().from(gtmConnections).where(eq36(gtmConnections.projectId, projectId)).get();
19957
20007
  if (!connection?.selectedAccountId || !connection.selectedContainerId) {
19958
20008
  throw withOutcomeReason(new Error("GTM needs a selected account and container before it can sync."), OutcomeReasonCodes.ACCOUNT_NOT_FOUND);
19959
20009
  }
@@ -19991,11 +20041,11 @@ async function executeGtmMarketingSync(db, runtime, runId, projectId) {
19991
20041
  status: RunStatuses.completed,
19992
20042
  finishedAt,
19993
20043
  error: null
19994
- }).where(and29(
19995
- eq35(runs.id, runId),
19996
- eq35(runs.projectId, projectId),
19997
- eq35(runs.kind, RunKinds["gtm-sync"]),
19998
- eq35(runs.status, RunStatuses.running)
20044
+ }).where(and30(
20045
+ eq36(runs.id, runId),
20046
+ eq36(runs.projectId, projectId),
20047
+ eq36(runs.kind, RunKinds["gtm-sync"]),
20048
+ eq36(runs.status, RunStatuses.running)
19999
20049
  )).run();
20000
20050
  if (terminalClaim.changes !== 1) {
20001
20051
  throw withOutcomeReason(
@@ -20016,13 +20066,13 @@ async function executeGtmMarketingSync(db, runtime, runId, projectId) {
20016
20066
  lastSnapshotAt: snapshot.metadata.capturedAt,
20017
20067
  lastSnapshotId: snapshot.metadata.id,
20018
20068
  updatedAt: finishedAt
20019
- }).where(and29(
20020
- eq35(gtmConnections.id, connection.id),
20021
- eq35(gtmConnections.projectId, projectId),
20022
- eq35(gtmConnections.selectedAccountId, connection.selectedAccountId),
20023
- eq35(gtmConnections.selectedContainerId, connection.selectedContainerId),
20024
- connection.selectedWorkspaceId === null ? isNull7(gtmConnections.selectedWorkspaceId) : eq35(gtmConnections.selectedWorkspaceId, connection.selectedWorkspaceId),
20025
- eq35(gtmConnections.selectionGeneration, connection.selectionGeneration)
20069
+ }).where(and30(
20070
+ eq36(gtmConnections.id, connection.id),
20071
+ eq36(gtmConnections.projectId, projectId),
20072
+ eq36(gtmConnections.selectedAccountId, connection.selectedAccountId),
20073
+ eq36(gtmConnections.selectedContainerId, connection.selectedContainerId),
20074
+ connection.selectedWorkspaceId === null ? isNull7(gtmConnections.selectedWorkspaceId) : eq36(gtmConnections.selectedWorkspaceId, connection.selectedWorkspaceId),
20075
+ eq36(gtmConnections.selectionGeneration, connection.selectionGeneration)
20026
20076
  )).run();
20027
20077
  if (connectionClaim.changes !== 1) {
20028
20078
  throw withOutcomeReason(
@@ -20678,7 +20728,7 @@ async function createServer(opts) {
20678
20728
  async (ctx) => {
20679
20729
  if (!sessionRegistry) return;
20680
20730
  if (!agentProactive) return;
20681
- const project = opts.db.select({ name: projects.name }).from(projects).where(eq36(projects.id, ctx.projectId)).get();
20731
+ const project = opts.db.select({ name: projects.name }).from(projects).where(eq37(projects.id, ctx.projectId)).get();
20682
20732
  if (!project) return;
20683
20733
  let content;
20684
20734
  if (ctx.kind === RunKinds["aeo-discover-probe"]) {
@@ -21152,7 +21202,7 @@ async function createServer(opts) {
21152
21202
  void (async () => {
21153
21203
  try {
21154
21204
  const report = await schedulerClient.runDoctor({ project: projectName, checkIds: scheduledHealthCheckIds() });
21155
- const project = opts.db.select().from(projects).where(eq36(projects.name, projectName)).get();
21205
+ const project = opts.db.select().from(projects).where(eq37(projects.name, projectName)).get();
21156
21206
  if (!project) {
21157
21207
  app.log.warn({ projectName }, "doctor schedule fired for an unknown project");
21158
21208
  return;
@@ -21444,7 +21494,7 @@ async function createServer(opts) {
21444
21494
  })();
21445
21495
  if (opts.config.apiKey) {
21446
21496
  const keyHash = hashApiKey(opts.config.apiKey);
21447
- const existing = opts.db.select().from(apiKeys).where(eq36(apiKeys.keyHash, keyHash)).get();
21497
+ const existing = opts.db.select().from(apiKeys).where(eq37(apiKeys.keyHash, keyHash)).get();
21448
21498
  if (!existing) {
21449
21499
  const prefix = opts.config.apiKey.slice(0, 12);
21450
21500
  opts.db.insert(apiKeys).values({
@@ -21463,14 +21513,14 @@ async function createServer(opts) {
21463
21513
  );
21464
21514
  const currentPasswordFingerprint = () => hashSessionToken(opts.config.dashboardPasswordHash ?? "");
21465
21515
  opts.db.delete(dashboardSessions).where(or4(
21466
- eq36(dashboardSessions.apiKeyHash, ""),
21467
- and30(
21516
+ eq37(dashboardSessions.apiKeyHash, ""),
21517
+ and31(
21468
21518
  isNotNull5(dashboardSessions.passwordFingerprint),
21469
21519
  ne4(dashboardSessions.passwordFingerprint, currentPasswordFingerprint())
21470
21520
  )
21471
21521
  )).run();
21472
21522
  if (!opts.config.dashboardPasswordHash) {
21473
- const lastPasswordEventAt = (action) => opts.db.select({ at: max(auditLog.createdAt) }).from(auditLog).where(and30(eq36(auditLog.entityType, "dashboard-password"), eq36(auditLog.action, action))).get()?.at ?? null;
21523
+ const lastPasswordEventAt = (action) => opts.db.select({ at: max(auditLog.createdAt) }).from(auditLog).where(and31(eq37(auditLog.entityType, "dashboard-password"), eq37(auditLog.action, action))).get()?.at ?? null;
21474
21524
  const createdAt = lastPasswordEventAt("dashboard-password.created");
21475
21525
  const clearedAt = lastPasswordEventAt("dashboard-password.cleared");
21476
21526
  if (createdAt !== null && (clearedAt === null || clearedAt < createdAt)) {
@@ -21504,23 +21554,23 @@ async function createServer(opts) {
21504
21554
  currentApiKeyHash: apiKeys.keyHash,
21505
21555
  passwordFingerprint: dashboardSessions.passwordFingerprint,
21506
21556
  expiresAt: dashboardSessions.expiresAt
21507
- }).from(dashboardSessions).innerJoin(apiKeys, eq36(apiKeys.id, dashboardSessions.apiKeyId)).where(and30(eq36(dashboardSessions.tokenHash, tokenHash), isNull8(apiKeys.revokedAt))).get();
21557
+ }).from(dashboardSessions).innerJoin(apiKeys, eq37(apiKeys.id, dashboardSessions.apiKeyId)).where(and31(eq37(dashboardSessions.tokenHash, tokenHash), isNull8(apiKeys.revokedAt))).get();
21508
21558
  if (!session) return null;
21509
21559
  const expiresAt = Date.parse(session.expiresAt);
21510
21560
  if (!Number.isFinite(expiresAt) || expiresAt <= Date.now() || session.apiKeyHash !== session.currentApiKeyHash || session.passwordFingerprint !== null && session.passwordFingerprint !== currentPasswordFingerprint()) {
21511
- opts.db.delete(dashboardSessions).where(eq36(dashboardSessions.tokenHash, tokenHash)).run();
21561
+ opts.db.delete(dashboardSessions).where(eq37(dashboardSessions.tokenHash, tokenHash)).run();
21512
21562
  return null;
21513
21563
  }
21514
21564
  return session.apiKeyId;
21515
21565
  };
21516
21566
  const clearSession = (sessionId) => {
21517
21567
  if (sessionId) {
21518
- opts.db.delete(dashboardSessions).where(eq36(dashboardSessions.tokenHash, hashSessionToken(sessionId))).run();
21568
+ opts.db.delete(dashboardSessions).where(eq37(dashboardSessions.tokenHash, hashSessionToken(sessionId))).run();
21519
21569
  }
21520
21570
  };
21521
21571
  const getDefaultApiKey = () => {
21522
21572
  if (!opts.config.apiKey) return void 0;
21523
- return opts.db.select().from(apiKeys).where(eq36(apiKeys.keyHash, hashApiKey(opts.config.apiKey))).get();
21573
+ return opts.db.select().from(apiKeys).where(eq37(apiKeys.keyHash, hashApiKey(opts.config.apiKey))).get();
21524
21574
  };
21525
21575
  const setSessionCookie = (reply, sessionId) => {
21526
21576
  reply.header(
@@ -21681,12 +21731,12 @@ async function createServer(opts) {
21681
21731
  return reply.send({ authenticated: true });
21682
21732
  }
21683
21733
  if (apiKey) {
21684
- const key = opts.db.select().from(apiKeys).where(eq36(apiKeys.keyHash, hashApiKey(apiKey))).get();
21734
+ const key = opts.db.select().from(apiKeys).where(eq37(apiKeys.keyHash, hashApiKey(apiKey))).get();
21685
21735
  if (!key || key.revokedAt) {
21686
21736
  const err2 = authInvalid();
21687
21737
  return reply.status(err2.statusCode).send(err2.toJSON());
21688
21738
  }
21689
- opts.db.update(apiKeys).set({ lastUsedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq36(apiKeys.id, key.id)).run();
21739
+ opts.db.update(apiKeys).set({ lastUsedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq37(apiKeys.id, key.id)).run();
21690
21740
  setSessionCookie(reply, createSession(key));
21691
21741
  return reply.send({ authenticated: true });
21692
21742
  }
@@ -21764,7 +21814,7 @@ async function createServer(opts) {
21764
21814
  const recomputeDebts = /* @__PURE__ */ new Map();
21765
21815
  let recomputeSequence = 0;
21766
21816
  const markAnswerFieldRecompute = (projectId, full) => {
21767
- opts.db.update(projects).set({ answerFieldsRecompute: full ? "full" : sql15`CASE WHEN ${projects.answerFieldsRecompute} = 'full' THEN 'full' ELSE 'competitors' END` }).where(eq36(projects.id, projectId)).run();
21817
+ opts.db.update(projects).set({ answerFieldsRecompute: full ? "full" : sql15`CASE WHEN ${projects.answerFieldsRecompute} = 'full' THEN 'full' ELSE 'competitors' END` }).where(eq37(projects.id, projectId)).run();
21768
21818
  };
21769
21819
  const requestAnswerFieldRecompute = (projectId, projectName, scope, reason) => {
21770
21820
  const sequence = ++recomputeSequence;
@@ -21782,10 +21832,10 @@ async function createServer(opts) {
21782
21832
  if (pass.full && debt.latestFull <= sequence) debt.latestFull = 0;
21783
21833
  try {
21784
21834
  if (debt.latest === sequence && debt.latestFull === 0) {
21785
- opts.db.update(projects).set({ answerFieldsRecompute: null }).where(eq36(projects.id, projectId)).run();
21835
+ opts.db.update(projects).set({ answerFieldsRecompute: null }).where(eq37(projects.id, projectId)).run();
21786
21836
  if (recomputeDebts.get(projectId) === debt) recomputeDebts.delete(projectId);
21787
21837
  } else if (debt.latestFull === 0) {
21788
- opts.db.update(projects).set({ answerFieldsRecompute: "competitors" }).where(and30(eq36(projects.id, projectId), eq36(projects.answerFieldsRecompute, "full"))).run();
21838
+ opts.db.update(projects).set({ answerFieldsRecompute: "competitors" }).where(and31(eq37(projects.id, projectId), eq37(projects.answerFieldsRecompute, "full"))).run();
21789
21839
  }
21790
21840
  } catch (err) {
21791
21841
  app.log.error({ err, projectId }, "could not clear the owed answer field recompute");
@@ -21822,7 +21872,7 @@ async function createServer(opts) {
21822
21872
  await yieldToEventLoop4();
21823
21873
  const reason = (competitorAutoAliasReasons.get(projectId) ?? []).join(",");
21824
21874
  competitorAutoAliasReasons.delete(projectId);
21825
- const project = opts.db.select().from(projects).where(eq36(projects.id, projectId)).get();
21875
+ const project = opts.db.select().from(projects).where(eq37(projects.id, projectId)).get();
21826
21876
  if (!project || project.competitorAutoAliases === "off") return;
21827
21877
  if (project.competitorAutoAliases === "apply") {
21828
21878
  await competitorAutoAliases.request(projectId, reason).catch(() => void 0);
@@ -22022,8 +22072,8 @@ async function createServer(opts) {
22022
22072
  getAgentPin: () => describeAgentPin(opts.config),
22023
22073
  getGoogleMarketingDoctorInput: (ctx) => {
22024
22074
  if (!ctx.project) return null;
22025
- const googleAds = opts.db.select().from(googleAdsConnections).where(eq36(googleAdsConnections.projectId, ctx.project.id)).get();
22026
- const gtm = opts.db.select().from(gtmConnections).where(eq36(gtmConnections.projectId, ctx.project.id)).get();
22075
+ const googleAds = opts.db.select().from(googleAdsConnections).where(eq37(googleAdsConnections.projectId, ctx.project.id)).get();
22076
+ const gtm = opts.db.select().from(gtmConnections).where(eq37(gtmConnections.projectId, ctx.project.id)).get();
22027
22077
  const googleAdsCredential = getGoogleAdsConnection(opts.config, ctx.project.id);
22028
22078
  const gtmCredential = getGtmConnection(opts.config, ctx.project.id);
22029
22079
  const googleAdsConnected = Boolean(googleAdsCredential?.accessToken);
@@ -22273,7 +22323,7 @@ async function createServer(opts) {
22273
22323
  ...inspectOpts,
22274
22324
  config: opts.config
22275
22325
  }).then(() => {
22276
- const finished = opts.db.select({ status: runs.status }).from(runs).where(eq36(runs.id, runId)).get();
22326
+ const finished = opts.db.select({ status: runs.status }).from(runs).where(eq37(runs.id, runId)).get();
22277
22327
  if (finished?.status === RunStatuses.completed || finished?.status === RunStatuses.partial) {
22278
22328
  return maybeRefreshGscCoverage(
22279
22329
  opts.db,
@@ -22785,7 +22835,7 @@ async function createServer(opts) {
22785
22835
  isBacklinksInstalled: () => isDuckdbInstalled()
22786
22836
  });
22787
22837
  }
22788
- for (const run of opts.db.select({ id: researchRuns.id, projectId: researchRuns.projectId }).from(researchRuns).where(eq36(researchRuns.status, ResearchRunStatuses.queued)).all()) {
22838
+ for (const run of opts.db.select({ id: researchRuns.id, projectId: researchRuns.projectId }).from(researchRuns).where(eq37(researchRuns.status, ResearchRunStatuses.queued)).all()) {
22789
22839
  dispatchResearchRun(run.id, run.projectId, OutcomeTriggers.startup);
22790
22840
  }
22791
22841
  runtimeStartupSettled = true;