@ainyc/canonry 4.47.0 → 4.50.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.
@@ -5,7 +5,7 @@ import {
5
5
  loadConfig,
6
6
  loadConfigRaw,
7
7
  saveConfigPatch
8
- } from "./chunk-ON545FBK.js";
8
+ } from "./chunk-MYDJ25GO.js";
9
9
  import {
10
10
  DEFAULT_RUN_HISTORY_LIMIT,
11
11
  IntelligenceService,
@@ -80,7 +80,7 @@ import {
80
80
  smoothedRunDelta,
81
81
  trafficSources,
82
82
  usageCounters
83
- } from "./chunk-M7MSNUNQ.js";
83
+ } from "./chunk-M4USKXJ4.js";
84
84
  import {
85
85
  AGENT_MEMORY_VALUE_MAX_BYTES,
86
86
  AGENT_PROVIDER_IDS,
@@ -120,18 +120,43 @@ import {
120
120
  agentBusy,
121
121
  agentMemoryDeleteRequestSchema,
122
122
  agentMemoryUpsertRequestSchema,
123
+ agentProvidersResponseDtoSchema,
124
+ auditLogEntrySchema,
123
125
  authInvalid,
124
126
  authRequired,
127
+ backlinkHistoryEntrySchema,
128
+ backlinkListResponseSchema,
129
+ backlinkSummaryDtoSchema,
130
+ backlinksInstallResultDtoSchema,
131
+ backlinksInstallStatusDtoSchema,
132
+ bingConnectResponseDtoSchema,
133
+ bingCoverageSnapshotDtoSchema,
134
+ bingCoverageSummaryDtoSchema,
135
+ bingIndexingRequestResponseDtoSchema,
136
+ bingKeywordStatsDtoSchema,
137
+ bingSetSiteResponseDtoSchema,
138
+ bingSitesResponseDtoSchema,
139
+ bingStatusDtoSchema,
140
+ bingUrlInspectionDtoSchema,
125
141
  brandKeyFromText,
126
142
  brandLabelFromDomain,
127
143
  buildRunErrorFromMessages,
128
144
  categorizeSource,
129
145
  categoryLabel,
146
+ ccAvailableReleaseSchema,
147
+ ccCachedReleaseSchema,
148
+ ccReleaseSyncDtoSchema,
149
+ cdpStatusDtoSchema,
130
150
  citationStateSchema,
131
151
  citationStateToCited,
152
+ citationVisibilityResponseSchema,
132
153
  clusterByCosine,
133
154
  competitorBatchRequestSchema,
155
+ competitorDtoSchema,
134
156
  contentActionLabel,
157
+ contentGapsResponseDtoSchema,
158
+ contentSourcesResponseDtoSchema,
159
+ contentTargetsResponseDtoSchema,
135
160
  dedupeReportActions,
136
161
  dedupeReportOpportunities,
137
162
  deliveryFailed,
@@ -139,8 +164,13 @@ import {
139
164
  deltaTone,
140
165
  determineAnswerMentioned,
141
166
  discoveryBucketSchema,
167
+ discoveryPromotePreviewSchema,
142
168
  discoveryPromoteRequestSchema,
169
+ discoveryPromoteResultSchema,
143
170
  discoveryRunRequestSchema,
171
+ discoverySessionDetailDtoSchema,
172
+ discoverySessionDtoSchema,
173
+ doctorReportSchema,
144
174
  effectiveBrandNames,
145
175
  effectiveDomains,
146
176
  emptyCitationVisibility,
@@ -152,12 +182,29 @@ import {
152
182
  formatIsoDate,
153
183
  formatNumber,
154
184
  formatRatio,
185
+ ga4AiReferralHistoryEntrySchema,
186
+ ga4SessionHistoryEntrySchema,
187
+ ga4SocialReferralHistoryEntrySchema,
188
+ ga4StatusDtoSchema,
189
+ ga4SyncResponseDtoSchema,
155
190
  getProviderLocationHandling,
191
+ googleConnectionDtoSchema,
192
+ gscCoverageSnapshotDtoSchema,
193
+ gscCoverageSummaryDtoSchema,
194
+ gscDeindexedRowSchema,
195
+ gscPerformanceDailyDtoSchema,
196
+ gscSearchDataDtoSchema,
197
+ gscSiteListResponseDtoSchema,
198
+ gscSitemapListResponseDtoSchema,
199
+ gscUrlInspectionDtoSchema,
156
200
  hasLocationLabel,
201
+ indexingRequestResponseDtoSchema,
157
202
  internalError,
158
203
  isAgentProviderId,
159
204
  isBrowserProvider,
205
+ keywordDtoSchema,
160
206
  keywordGenerateRequestSchema,
207
+ latestProjectRunDtoSchema,
161
208
  locationContextSchema,
162
209
  mentionStateFromAnswerMentioned,
163
210
  missingDependency,
@@ -166,12 +213,16 @@ import {
166
213
  normalizeUrlPath,
167
214
  notFound,
168
215
  notImplemented,
216
+ notificationDtoSchema,
169
217
  parseRunError,
170
218
  parseWindow,
171
219
  pickClusterRepresentative,
172
220
  projectConfigSchema,
221
+ projectDtoSchema,
222
+ projectReportDtoSchema,
173
223
  projectUpsertRequestSchema,
174
224
  providerError,
225
+ queryDtoSchema,
175
226
  queryGenerateRequestSchema,
176
227
  registrableDomain,
177
228
  reportActionCategoryLabel,
@@ -182,22 +233,47 @@ import {
182
233
  resolveConfigSpecQueries,
183
234
  resolveLocations,
184
235
  resolveSnapshotRequestQueries,
236
+ runDetailDtoSchema,
237
+ runDtoSchema,
185
238
  runInProgress,
186
239
  runNotCancellable,
187
240
  runTriggerRequestSchema,
188
241
  schedulableRunKindSchema,
242
+ scheduleDtoSchema,
189
243
  scheduleUpsertRequestSchema,
190
244
  serializeRunError,
245
+ settingsDtoSchema,
246
+ snapshotDiffResponseSchema,
247
+ snapshotListResponseSchema,
248
+ snapshotReportSchema,
191
249
  snapshotRequestSchema,
192
250
  summarizeCheckResults,
251
+ trafficBackfillResponseSchema,
193
252
  trafficConnectVercelRequestSchema,
194
253
  trafficConnectWordpressRequestSchema,
254
+ trafficEventsResponseSchema,
255
+ trafficSourceDetailDtoSchema,
256
+ trafficSourceDtoSchema,
257
+ trafficSourceListResponseSchema,
258
+ trafficStatusResponseSchema,
259
+ trafficSyncResponseSchema,
195
260
  unsupportedKind,
196
261
  validationError,
197
262
  visibilityStateFromAnswerMentioned,
198
263
  windowCutoff,
199
- wordpressEnvSchema
200
- } from "./chunk-4WXY57ET.js";
264
+ wordpressAuditPageDtoSchema,
265
+ wordpressBulkMetaResultDtoSchema,
266
+ wordpressDiffDtoSchema,
267
+ wordpressEnvSchema,
268
+ wordpressManualAssistDtoSchema,
269
+ wordpressOnboardResultDtoSchema,
270
+ wordpressPageDetailDtoSchema,
271
+ wordpressPageSummaryDtoSchema,
272
+ wordpressSchemaBlockDtoSchema,
273
+ wordpressSchemaDeployResultDtoSchema,
274
+ wordpressSchemaStatusResultDtoSchema,
275
+ wordpressStatusDtoSchema
276
+ } from "./chunk-QIG3TKL4.js";
201
277
 
202
278
  // src/telemetry.ts
203
279
  import crypto from "crypto";
@@ -563,7 +639,10 @@ import { eq as eq3, sql as sql2 } from "drizzle-orm";
563
639
 
564
640
  // ../api-routes/src/helpers.ts
565
641
  import crypto3 from "crypto";
566
- import { eq as eq2, sql } from "drizzle-orm";
642
+ import { eq as eq2, ne, sql } from "drizzle-orm";
643
+ function notProbeRun() {
644
+ return ne(runs.trigger, RunTriggers.probe);
645
+ }
567
646
  function resolveProject(db, name) {
568
647
  const project = db.select().from(projects).where(eq2(projects.name, name)).get();
569
648
  if (!project) {
@@ -2266,7 +2345,7 @@ function normalizeCompetitorList2(domains) {
2266
2345
  }
2267
2346
 
2268
2347
  // ../api-routes/src/history.ts
2269
- import { eq as eq9, desc as desc2, inArray as inArray2 } from "drizzle-orm";
2348
+ import { and as and4, eq as eq9, desc as desc2, inArray as inArray2 } from "drizzle-orm";
2270
2349
 
2271
2350
  // ../api-routes/src/notification-redaction.ts
2272
2351
  var REDACTED_URL = {
@@ -2323,7 +2402,7 @@ async function historyRoutes(app) {
2323
2402
  const project = resolveProject(app.db, request.params.name);
2324
2403
  const limit = parseInt(request.query.limit ?? "50", 10);
2325
2404
  const offset = parseInt(request.query.offset ?? "0", 10);
2326
- const projectRuns = app.db.select({ id: runs.id }).from(runs).where(eq9(runs.projectId, project.id)).all();
2405
+ const projectRuns = app.db.select({ id: runs.id }).from(runs).where(and4(eq9(runs.projectId, project.id), notProbeRun())).all();
2327
2406
  if (projectRuns.length === 0) {
2328
2407
  return reply.send({ snapshots: [], total: 0 });
2329
2408
  }
@@ -2372,7 +2451,7 @@ async function historyRoutes(app) {
2372
2451
  app.get("/projects/:name/timeline", async (request, reply) => {
2373
2452
  const project = resolveProject(app.db, request.params.name);
2374
2453
  const projectQueries = app.db.select().from(queries).where(eq9(queries.projectId, project.id)).all();
2375
- const projectRuns = app.db.select().from(runs).where(eq9(runs.projectId, project.id)).orderBy(runs.createdAt).all();
2454
+ const projectRuns = app.db.select().from(runs).where(and4(eq9(runs.projectId, project.id), notProbeRun())).orderBy(runs.createdAt).all();
2376
2455
  if (projectRuns.length === 0 || projectQueries.length === 0) {
2377
2456
  return reply.send([]);
2378
2457
  }
@@ -2557,13 +2636,13 @@ function formatAuditEntry(row) {
2557
2636
  }
2558
2637
 
2559
2638
  // ../api-routes/src/analytics.ts
2560
- import { eq as eq10, desc as desc3, inArray as inArray3 } from "drizzle-orm";
2639
+ import { and as and5, eq as eq10, desc as desc3, inArray as inArray3 } from "drizzle-orm";
2561
2640
  async function analyticsRoutes(app) {
2562
2641
  app.get("/projects/:name/analytics/metrics", async (request, reply) => {
2563
2642
  const project = resolveProject(app.db, request.params.name);
2564
2643
  const window = parseWindow(request.query.window);
2565
2644
  const cutoff = windowCutoff(window);
2566
- const projectRuns = app.db.select().from(runs).where(eq10(runs.projectId, project.id)).orderBy(runs.createdAt).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
2645
+ const projectRuns = app.db.select().from(runs).where(and5(eq10(runs.projectId, project.id), notProbeRun())).orderBy(runs.createdAt).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
2567
2646
  if (projectRuns.length === 0) {
2568
2647
  return reply.send({
2569
2648
  window,
@@ -2611,14 +2690,14 @@ async function analyticsRoutes(app) {
2611
2690
  const project = resolveProject(app.db, request.params.name);
2612
2691
  const window = parseWindow(request.query.window);
2613
2692
  const cutoff = windowCutoff(window);
2614
- const completedRuns = app.db.select().from(runs).where(eq10(runs.projectId, project.id)).orderBy(desc3(runs.createdAt), desc3(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial");
2693
+ const completedRuns = app.db.select().from(runs).where(and5(eq10(runs.projectId, project.id), notProbeRun())).orderBy(desc3(runs.createdAt), desc3(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial");
2615
2694
  const latestGroup = groupRunsByCreatedAt(completedRuns)[0] ?? [];
2616
2695
  const latestGroupRunIds = latestGroup.map((r) => r.id);
2617
2696
  const latestRun = pickGroupRepresentative(latestGroup);
2618
2697
  if (!latestRun) {
2619
2698
  return reply.send({ cited: [], gap: [], uncited: [], mentionedQueries: [], mentionGap: [], notMentioned: [], runId: "", window });
2620
2699
  }
2621
- const windowRuns = app.db.select().from(runs).where(eq10(runs.projectId, project.id)).orderBy(runs.createdAt).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
2700
+ const windowRuns = app.db.select().from(runs).where(and5(eq10(runs.projectId, project.id), notProbeRun())).orderBy(runs.createdAt).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
2622
2701
  const windowRunIds = windowRuns.map((r) => r.id);
2623
2702
  const runIdToCreatedAt = new Map(windowRuns.map((r) => [r.id, r.createdAt]));
2624
2703
  const consistencyMap = /* @__PURE__ */ new Map();
@@ -2734,7 +2813,7 @@ async function analyticsRoutes(app) {
2734
2813
  const project = resolveProject(app.db, request.params.name);
2735
2814
  const window = parseWindow(request.query.window);
2736
2815
  const cutoff = windowCutoff(window);
2737
- const windowRuns = app.db.select().from(runs).where(eq10(runs.projectId, project.id)).orderBy(desc3(runs.createdAt), desc3(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
2816
+ const windowRuns = app.db.select().from(runs).where(and5(eq10(runs.projectId, project.id), notProbeRun())).orderBy(desc3(runs.createdAt), desc3(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
2738
2817
  if (windowRuns.length === 0) {
2739
2818
  return reply.send({ overall: [], byQuery: {}, runId: "", window });
2740
2819
  }
@@ -2898,7 +2977,7 @@ function buildCategoryCounts(counts) {
2898
2977
  }
2899
2978
 
2900
2979
  // ../api-routes/src/intelligence.ts
2901
- import { eq as eq11, desc as desc4, and as and4, inArray as inArray4 } from "drizzle-orm";
2980
+ import { eq as eq11, desc as desc4, and as and6, inArray as inArray4 } from "drizzle-orm";
2902
2981
  function emptyHealthSnapshot(projectId) {
2903
2982
  return {
2904
2983
  id: `no-data:${projectId}`,
@@ -2987,7 +3066,7 @@ async function intelligenceRoutes(app) {
2987
3066
  if (request.query.runId) {
2988
3067
  conditions.push(eq11(insights.runId, request.query.runId));
2989
3068
  }
2990
- const rows = app.db.select().from(insights).where(conditions.length === 1 ? conditions[0] : and4(...conditions)).orderBy(desc4(insights.createdAt)).all();
3069
+ const rows = app.db.select().from(insights).where(conditions.length === 1 ? conditions[0] : and6(...conditions)).orderBy(desc4(insights.createdAt)).all();
2991
3070
  const showDismissed = request.query.dismissed === "true";
2992
3071
  const result = rows.filter((r) => showDismissed || !r.dismissed).map(mapInsightRow);
2993
3072
  return reply.send(result);
@@ -3011,15 +3090,18 @@ async function intelligenceRoutes(app) {
3011
3090
  });
3012
3091
  app.get("/projects/:name/health/latest", async (request, reply) => {
3013
3092
  const project = resolveProject(app.db, request.params.name);
3014
- const projectVisRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and4(
3093
+ const projectVisRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and6(
3015
3094
  eq11(runs.projectId, project.id),
3016
3095
  eq11(runs.kind, RunKinds["answer-visibility"]),
3017
- inArray4(runs.status, [RunStatuses.completed, RunStatuses.partial])
3096
+ inArray4(runs.status, [RunStatuses.completed, RunStatuses.partial]),
3097
+ // Health-latest is the dashboard headline; probe runs must not
3098
+ // displace the most recent real visibility sweep.
3099
+ notProbeRun()
3018
3100
  )).orderBy(desc4(runs.createdAt), desc4(runs.id)).all();
3019
3101
  const latestGroup = groupRunsByCreatedAt(projectVisRuns)[0] ?? [];
3020
3102
  const latestGroupRunIds = latestGroup.map((r) => r.id);
3021
3103
  if (latestGroupRunIds.length > 0) {
3022
- const groupRows = app.db.select().from(healthSnapshots).where(and4(
3104
+ const groupRows = app.db.select().from(healthSnapshots).where(and6(
3023
3105
  eq11(healthSnapshots.projectId, project.id),
3024
3106
  inArray4(healthSnapshots.runId, latestGroupRunIds)
3025
3107
  )).all();
@@ -3043,7 +3125,7 @@ async function intelligenceRoutes(app) {
3043
3125
  }
3044
3126
 
3045
3127
  // ../api-routes/src/report.ts
3046
- import { and as and6, desc as desc6, eq as eq13, gte, inArray as inArray6, lt, lte, ne, or as or3, sql as sql5 } from "drizzle-orm";
3128
+ import { and as and8, desc as desc6, eq as eq13, gte, inArray as inArray6, lt, lte, ne as ne2, or as or3, sql as sql5 } from "drizzle-orm";
3047
3129
 
3048
3130
  // ../api-routes/src/report-renderer.ts
3049
3131
  var COLORS = {
@@ -5283,7 +5365,7 @@ function renderReportHtml(report, opts = {}) {
5283
5365
  }
5284
5366
 
5285
5367
  // ../api-routes/src/content-data.ts
5286
- import { and as and5, eq as eq12, desc as desc5, inArray as inArray5 } from "drizzle-orm";
5368
+ import { and as and7, eq as eq12, desc as desc5, inArray as inArray5 } from "drizzle-orm";
5287
5369
  var RECENT_RUNS_WINDOW = 5;
5288
5370
  function loadOrchestratorInput(db, project, locationFilter = void 0) {
5289
5371
  const projectId = project.id;
@@ -5407,13 +5489,16 @@ function listCompetitorDomains(db, projectId) {
5407
5489
  }
5408
5490
  function listRecentAnswerVisibilityRunIds(db, projectId, limit, locationFilter) {
5409
5491
  const rows = db.select({ id: runs.id, location: runs.location }).from(runs).where(
5410
- and5(
5492
+ and7(
5411
5493
  eq12(runs.projectId, projectId),
5412
5494
  eq12(runs.kind, RunKinds["answer-visibility"]),
5413
5495
  // Queued/running/failed/cancelled runs may have partial or no
5414
5496
  // snapshots; including them risks pointing latestRunId at a run with
5415
5497
  // no usable evidence.
5416
- inArray5(runs.status, [RunStatuses.completed, RunStatuses.partial])
5498
+ inArray5(runs.status, [RunStatuses.completed, RunStatuses.partial]),
5499
+ // Probe runs are operator/agent test runs; they must not poison the
5500
+ // recent-runs window the content engine uses to recommend actions.
5501
+ notProbeRun()
5417
5502
  )
5418
5503
  ).orderBy(desc5(runs.createdAt)).all();
5419
5504
  const filtered = locationFilter === void 0 ? rows : rows.filter((r) => (r.location ?? null) === locationFilter);
@@ -5774,7 +5859,7 @@ function buildGscSection(db, projectId, projectBrandNames, canonicalDomain, trac
5774
5859
  }
5775
5860
  function buildGaSection(db, projectId) {
5776
5861
  const windowSummary = db.select().from(gaTrafficWindowSummaries).where(
5777
- and6(
5862
+ and8(
5778
5863
  eq13(gaTrafficWindowSummaries.projectId, projectId),
5779
5864
  eq13(gaTrafficWindowSummaries.windowKey, "30d")
5780
5865
  )
@@ -5952,9 +6037,9 @@ function nonSubresourceReferralPathCondition() {
5952
6037
  }
5953
6038
  function buildServerActivity(db, projectId) {
5954
6039
  const sourceRows = db.select({ id: trafficSources.id }).from(trafficSources).where(
5955
- and6(
6040
+ and8(
5956
6041
  eq13(trafficSources.projectId, projectId),
5957
- ne(trafficSources.status, TrafficSourceStatuses.archived)
6042
+ ne2(trafficSources.status, TrafficSourceStatuses.archived)
5958
6043
  )
5959
6044
  ).all();
5960
6045
  if (sourceRows.length === 0) return null;
@@ -5968,7 +6053,7 @@ function buildServerActivity(db, projectId) {
5968
6053
  const trendStart = new Date(trendStartMs).toISOString();
5969
6054
  const sumVerifiedCrawlers = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
5970
6055
  db.select({ total: sql5`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
5971
- and6(
6056
+ and8(
5972
6057
  eq13(crawlerEventsHourly.projectId, projectId),
5973
6058
  eq13(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
5974
6059
  gte(crawlerEventsHourly.tsHour, windowStartIso),
@@ -5978,9 +6063,9 @@ function buildServerActivity(db, projectId) {
5978
6063
  );
5979
6064
  const sumUnverifiedCrawlers = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
5980
6065
  db.select({ total: sql5`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
5981
- and6(
6066
+ and8(
5982
6067
  eq13(crawlerEventsHourly.projectId, projectId),
5983
- ne(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
6068
+ ne2(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
5984
6069
  gte(crawlerEventsHourly.tsHour, windowStartIso),
5985
6070
  exclusiveEnd ? lt(crawlerEventsHourly.tsHour, windowEndIso) : lte(crawlerEventsHourly.tsHour, windowEndIso)
5986
6071
  )
@@ -5988,7 +6073,7 @@ function buildServerActivity(db, projectId) {
5988
6073
  );
5989
6074
  const sumReferrals = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
5990
6075
  db.select({ total: sql5`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
5991
- and6(
6076
+ and8(
5992
6077
  eq13(aiReferralEventsHourly.projectId, projectId),
5993
6078
  nonSubresourceReferralPathCondition(),
5994
6079
  gte(aiReferralEventsHourly.tsHour, windowStartIso),
@@ -6007,7 +6092,7 @@ function buildServerActivity(db, projectId) {
6007
6092
  verificationStatus: crawlerEventsHourly.verificationStatus,
6008
6093
  hits: sql5`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
6009
6094
  }).from(crawlerEventsHourly).where(
6010
- and6(
6095
+ and8(
6011
6096
  eq13(crawlerEventsHourly.projectId, projectId),
6012
6097
  gte(crawlerEventsHourly.tsHour, headlineStart),
6013
6098
  lte(crawlerEventsHourly.tsHour, headlineEnd)
@@ -6017,7 +6102,7 @@ function buildServerActivity(db, projectId) {
6017
6102
  operator: crawlerEventsHourly.operator,
6018
6103
  hits: sql5`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
6019
6104
  }).from(crawlerEventsHourly).where(
6020
- and6(
6105
+ and8(
6021
6106
  eq13(crawlerEventsHourly.projectId, projectId),
6022
6107
  eq13(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
6023
6108
  gte(crawlerEventsHourly.tsHour, priorStart),
@@ -6028,7 +6113,7 @@ function buildServerActivity(db, projectId) {
6028
6113
  operator: aiReferralEventsHourly.operator,
6029
6114
  hits: sql5`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
6030
6115
  }).from(aiReferralEventsHourly).where(
6031
- and6(
6116
+ and8(
6032
6117
  eq13(aiReferralEventsHourly.projectId, projectId),
6033
6118
  nonSubresourceReferralPathCondition(),
6034
6119
  gte(aiReferralEventsHourly.tsHour, headlineStart),
@@ -6069,7 +6154,7 @@ function buildServerActivity(db, projectId) {
6069
6154
  hits: sql5`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`,
6070
6155
  operators: sql5`COUNT(DISTINCT ${crawlerEventsHourly.operator})`
6071
6156
  }).from(crawlerEventsHourly).where(
6072
- and6(
6157
+ and8(
6073
6158
  eq13(crawlerEventsHourly.projectId, projectId),
6074
6159
  eq13(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
6075
6160
  gte(crawlerEventsHourly.tsHour, headlineStart),
@@ -6086,7 +6171,7 @@ function buildServerActivity(db, projectId) {
6086
6171
  arrivals: sql5`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
6087
6172
  landingPaths: sql5`COUNT(DISTINCT ${aiReferralEventsHourly.landingPathNormalized})`
6088
6173
  }).from(aiReferralEventsHourly).where(
6089
- and6(
6174
+ and8(
6090
6175
  eq13(aiReferralEventsHourly.projectId, projectId),
6091
6176
  nonSubresourceReferralPathCondition(),
6092
6177
  gte(aiReferralEventsHourly.tsHour, headlineStart),
@@ -6103,7 +6188,7 @@ function buildServerActivity(db, projectId) {
6103
6188
  arrivals: sql5`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
6104
6189
  products: sql5`COUNT(DISTINCT ${aiReferralEventsHourly.product})`
6105
6190
  }).from(aiReferralEventsHourly).where(
6106
- and6(
6191
+ and8(
6107
6192
  eq13(aiReferralEventsHourly.projectId, projectId),
6108
6193
  nonSubresourceReferralPathCondition(),
6109
6194
  gte(aiReferralEventsHourly.tsHour, headlineStart),
@@ -6119,7 +6204,7 @@ function buildServerActivity(db, projectId) {
6119
6204
  date: sql5`SUBSTR(${crawlerEventsHourly.tsHour}, 1, 10)`,
6120
6205
  hits: sql5`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
6121
6206
  }).from(crawlerEventsHourly).where(
6122
- and6(
6207
+ and8(
6123
6208
  eq13(crawlerEventsHourly.projectId, projectId),
6124
6209
  eq13(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
6125
6210
  gte(crawlerEventsHourly.tsHour, trendStart),
@@ -6130,7 +6215,7 @@ function buildServerActivity(db, projectId) {
6130
6215
  date: sql5`SUBSTR(${aiReferralEventsHourly.tsHour}, 1, 10)`,
6131
6216
  hits: sql5`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
6132
6217
  }).from(aiReferralEventsHourly).where(
6133
- and6(
6218
+ and8(
6134
6219
  eq13(aiReferralEventsHourly.projectId, projectId),
6135
6220
  nonSubresourceReferralPathCondition(),
6136
6221
  gte(aiReferralEventsHourly.tsHour, trendStart),
@@ -6205,7 +6290,7 @@ function buildIndexingHealth(db, projectId) {
6205
6290
  return null;
6206
6291
  }
6207
6292
  function buildCitationsTrend(db, projectId, queryLookup, locationFilter) {
6208
- const visibilityRuns = db.select().from(runs).where(and6(eq13(runs.projectId, projectId), eq13(runs.kind, RunKinds["answer-visibility"]))).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter);
6293
+ const visibilityRuns = db.select().from(runs).where(and8(eq13(runs.projectId, projectId), eq13(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter);
6209
6294
  const totalQueries = queryLookup.byId.size;
6210
6295
  const points = [];
6211
6296
  for (const run of visibilityRuns) {
@@ -6251,14 +6336,15 @@ function buildCitationsTrend(db, projectId, queryLookup, locationFilter) {
6251
6336
  }
6252
6337
  function buildInsightList(db, projectId, locationFilter) {
6253
6338
  const recentRunIds = db.select({ id: runs.id, location: runs.location }).from(runs).where(
6254
- and6(
6339
+ and8(
6255
6340
  eq13(runs.projectId, projectId),
6256
6341
  eq13(runs.kind, RunKinds["answer-visibility"]),
6257
- or3(eq13(runs.status, RunStatuses.completed), eq13(runs.status, RunStatuses.partial))
6342
+ or3(eq13(runs.status, RunStatuses.completed), eq13(runs.status, RunStatuses.partial)),
6343
+ notProbeRun()
6258
6344
  )
6259
6345
  ).orderBy(desc6(runs.createdAt)).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter).slice(0, INSIGHT_LOOKBACK_RUNS).map((r) => r.id);
6260
6346
  if (recentRunIds.length === 0) return [];
6261
- const rows = db.select().from(insights).where(and6(eq13(insights.projectId, projectId), inArray6(insights.runId, recentRunIds))).orderBy(desc6(insights.createdAt)).all();
6347
+ const rows = db.select().from(insights).where(and8(eq13(insights.projectId, projectId), inArray6(insights.runId, recentRunIds))).orderBy(desc6(insights.createdAt)).all();
6262
6348
  const severityRank = { critical: 0, high: 1, medium: 2, low: 3 };
6263
6349
  const flat = rows.filter((r) => !r.dismissed).map((r) => {
6264
6350
  const recommendation = parseJsonColumn(r.recommendation, null);
@@ -6803,7 +6889,7 @@ function buildWhatsChanged(input) {
6803
6889
  function buildProjectReport(db, projectName) {
6804
6890
  const project = resolveProject(db, projectName);
6805
6891
  const queryLookup = loadQueryLookup(db, project.id);
6806
- const allRuns = db.select().from(runs).where(eq13(runs.projectId, project.id)).orderBy(desc6(runs.createdAt), desc6(runs.id)).all();
6892
+ const allRuns = db.select().from(runs).where(and8(eq13(runs.projectId, project.id), notProbeRun())).orderBy(desc6(runs.createdAt), desc6(runs.id)).all();
6807
6893
  const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
6808
6894
  const completedVisRunGroups = groupRunsByCreatedAt(
6809
6895
  visibilityRuns.filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial)
@@ -7031,7 +7117,7 @@ async function reportRoutes(app) {
7031
7117
  }
7032
7118
 
7033
7119
  // ../api-routes/src/citations.ts
7034
- import { eq as eq14, inArray as inArray7 } from "drizzle-orm";
7120
+ import { and as and9, eq as eq14, inArray as inArray7 } from "drizzle-orm";
7035
7121
  async function citationRoutes(app) {
7036
7122
  app.get("/projects/:name/citations/visibility", async (request, reply) => {
7037
7123
  const project = resolveProject(app.db, request.params.name);
@@ -7040,7 +7126,7 @@ async function citationRoutes(app) {
7040
7126
  if (projectQueries.length === 0) {
7041
7127
  return reply.send(emptyCitationVisibility("no-queries"));
7042
7128
  }
7043
- const projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(eq14(runs.projectId, project.id)).all();
7129
+ const projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and9(eq14(runs.projectId, project.id), notProbeRun())).all();
7044
7130
  if (projectRuns.length === 0) {
7045
7131
  return reply.send(emptyCitationVisibility("no-runs-yet"));
7046
7132
  }
@@ -7196,7 +7282,7 @@ function normalizeDomain2(domain) {
7196
7282
  }
7197
7283
 
7198
7284
  // ../api-routes/src/composites.ts
7199
- import { eq as eq15, and as and7, desc as desc7, sql as sql6, like, or as or4, inArray as inArray8 } from "drizzle-orm";
7285
+ import { eq as eq15, and as and10, desc as desc7, sql as sql6, like, or as or4, inArray as inArray8 } from "drizzle-orm";
7200
7286
  var TOP_INSIGHT_LIMIT = 5;
7201
7287
  var SEARCH_HIT_HARD_LIMIT = 50;
7202
7288
  var SEARCH_SNIPPET_RADIUS = 80;
@@ -7214,7 +7300,7 @@ async function compositeRoutes(app) {
7214
7300
  const project = resolveProject(app.db, request.params.name);
7215
7301
  const filterLocation = (request.query.location ?? "").trim() || null;
7216
7302
  const sinceIso = parseSinceFilter(request.query.since);
7217
- const allRunsRaw = app.db.select().from(runs).where(eq15(runs.projectId, project.id)).orderBy(desc7(runs.createdAt), desc7(runs.id)).all();
7303
+ const allRunsRaw = app.db.select().from(runs).where(and10(eq15(runs.projectId, project.id), notProbeRun())).orderBy(desc7(runs.createdAt), desc7(runs.id)).all();
7218
7304
  const allRuns = allRunsRaw.filter((r) => runMatchesFilters(r, filterLocation, sinceIso));
7219
7305
  const totalRuns = allRuns.length;
7220
7306
  const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
@@ -7343,7 +7429,7 @@ async function compositeRoutes(app) {
7343
7429
  rawResponse: querySnapshots.rawResponse,
7344
7430
  createdAt: querySnapshots.createdAt
7345
7431
  }).from(querySnapshots).innerJoin(queries, eq15(querySnapshots.queryId, queries.id)).where(
7346
- and7(
7432
+ and10(
7347
7433
  eq15(queries.projectId, project.id),
7348
7434
  or4(
7349
7435
  sql6`${querySnapshots.answerText} LIKE ${pattern} ESCAPE '\\'`,
@@ -7354,7 +7440,7 @@ async function compositeRoutes(app) {
7354
7440
  )
7355
7441
  ).orderBy(desc7(querySnapshots.createdAt)).limit(limit + 1).all());
7356
7442
  const insightMatches = app.db.select().from(insights).where(
7357
- and7(
7443
+ and10(
7358
7444
  eq15(insights.projectId, project.id),
7359
7445
  or4(
7360
7446
  like(insights.title, pattern),
@@ -7527,7 +7613,7 @@ function buildSuggestedQueriesFromGsc(app, projectId, trackedQueries) {
7527
7613
  // NULLIF guards the degenerate impressions=0 case (SQLite returns NULL,
7528
7614
  // which the JS coerces to 0 — caught by the impression floor anyway).
7529
7615
  avgPosition: sql6`COALESCE(SUM(${gscSearchData.position} * ${gscSearchData.impressions}) * 1.0 / NULLIF(SUM(${gscSearchData.impressions}), 0), 0)`
7530
- }).from(gscSearchData).where(and7(
7616
+ }).from(gscSearchData).where(and10(
7531
7617
  eq15(gscSearchData.projectId, projectId),
7532
7618
  sql6`${gscSearchData.date} >= ${cutoff}`,
7533
7619
  sql6`${gscSearchData.impressions} > 0`
@@ -7716,6 +7802,7 @@ function formatProject2(row) {
7716
7802
  language: row.language,
7717
7803
  tags: parseJsonColumn(row.tags, []),
7718
7804
  labels: parseJsonColumn(row.labels, {}),
7805
+ providers: parseJsonColumn(row.providers, []),
7719
7806
  locations: parseJsonColumn(row.locations, []),
7720
7807
  defaultLocation: row.defaultLocation,
7721
7808
  autoExtractBacklinks: row.autoExtractBacklinks === 1,
@@ -7862,6 +7949,141 @@ function parseLimitParam(raw) {
7862
7949
  return parsed;
7863
7950
  }
7864
7951
 
7952
+ // ../api-routes/src/openapi-schemas.ts
7953
+ import { z } from "zod";
7954
+ var SCHEMA_TABLE = {
7955
+ AgentProvidersResponseDto: agentProvidersResponseDtoSchema,
7956
+ AuditLogEntry: auditLogEntrySchema,
7957
+ BacklinkHistoryEntry: backlinkHistoryEntrySchema,
7958
+ BacklinkListResponse: backlinkListResponseSchema,
7959
+ BacklinkSummaryDto: backlinkSummaryDtoSchema,
7960
+ BacklinksInstallResultDto: backlinksInstallResultDtoSchema,
7961
+ BacklinksInstallStatusDto: backlinksInstallStatusDtoSchema,
7962
+ BingConnectResponseDto: bingConnectResponseDtoSchema,
7963
+ BingCoverageSnapshotDto: bingCoverageSnapshotDtoSchema,
7964
+ BingCoverageSummaryDto: bingCoverageSummaryDtoSchema,
7965
+ BingIndexingRequestResponseDto: bingIndexingRequestResponseDtoSchema,
7966
+ BingKeywordStatsDto: bingKeywordStatsDtoSchema,
7967
+ BingSetSiteResponseDto: bingSetSiteResponseDtoSchema,
7968
+ BingSitesResponseDto: bingSitesResponseDtoSchema,
7969
+ BingStatusDto: bingStatusDtoSchema,
7970
+ BingUrlInspectionDto: bingUrlInspectionDtoSchema,
7971
+ CcAvailableRelease: ccAvailableReleaseSchema,
7972
+ CcCachedRelease: ccCachedReleaseSchema,
7973
+ CcReleaseSyncDto: ccReleaseSyncDtoSchema,
7974
+ CdpStatusDto: cdpStatusDtoSchema,
7975
+ CitationVisibilityResponse: citationVisibilityResponseSchema,
7976
+ CompetitorDto: competitorDtoSchema,
7977
+ ContentGapsResponseDto: contentGapsResponseDtoSchema,
7978
+ ContentSourcesResponseDto: contentSourcesResponseDtoSchema,
7979
+ ContentTargetsResponseDto: contentTargetsResponseDtoSchema,
7980
+ DiscoveryPromotePreview: discoveryPromotePreviewSchema,
7981
+ DiscoveryPromoteResult: discoveryPromoteResultSchema,
7982
+ DiscoverySessionDetailDto: discoverySessionDetailDtoSchema,
7983
+ DiscoverySessionDto: discoverySessionDtoSchema,
7984
+ DoctorReportDto: doctorReportSchema,
7985
+ GA4AiReferralHistoryEntry: ga4AiReferralHistoryEntrySchema,
7986
+ GA4SessionHistoryEntry: ga4SessionHistoryEntrySchema,
7987
+ GA4SocialReferralHistoryEntry: ga4SocialReferralHistoryEntrySchema,
7988
+ GA4StatusDto: ga4StatusDtoSchema,
7989
+ GA4SyncResponseDto: ga4SyncResponseDtoSchema,
7990
+ GoogleConnectionDto: googleConnectionDtoSchema,
7991
+ GscCoverageSnapshotDto: gscCoverageSnapshotDtoSchema,
7992
+ GscCoverageSummaryDto: gscCoverageSummaryDtoSchema,
7993
+ GscDeindexedRowDto: gscDeindexedRowSchema,
7994
+ GscPerformanceDailyDto: gscPerformanceDailyDtoSchema,
7995
+ GscSearchDataDto: gscSearchDataDtoSchema,
7996
+ GscSiteListResponseDto: gscSiteListResponseDtoSchema,
7997
+ GscSitemapListResponseDto: gscSitemapListResponseDtoSchema,
7998
+ GscUrlInspectionDto: gscUrlInspectionDtoSchema,
7999
+ IndexingRequestResponseDto: indexingRequestResponseDtoSchema,
8000
+ KeywordDto: keywordDtoSchema,
8001
+ LatestProjectRunDto: latestProjectRunDtoSchema,
8002
+ LocationContext: locationContextSchema,
8003
+ NotificationDto: notificationDtoSchema,
8004
+ ProjectDto: projectDtoSchema,
8005
+ ProjectReportDto: projectReportDtoSchema,
8006
+ QueryDto: queryDtoSchema,
8007
+ RunDetailDto: runDetailDtoSchema,
8008
+ RunDto: runDtoSchema,
8009
+ ScheduleDto: scheduleDtoSchema,
8010
+ SettingsDto: settingsDtoSchema,
8011
+ SnapshotDiffResponse: snapshotDiffResponseSchema,
8012
+ SnapshotListResponse: snapshotListResponseSchema,
8013
+ SnapshotReportDto: snapshotReportSchema,
8014
+ TrafficBackfillResponse: trafficBackfillResponseSchema,
8015
+ TrafficEventsResponse: trafficEventsResponseSchema,
8016
+ TrafficSourceDetailDto: trafficSourceDetailDtoSchema,
8017
+ TrafficSourceDto: trafficSourceDtoSchema,
8018
+ TrafficSourceListResponse: trafficSourceListResponseSchema,
8019
+ TrafficStatusResponse: trafficStatusResponseSchema,
8020
+ TrafficSyncResponse: trafficSyncResponseSchema,
8021
+ WordpressAuditPageDto: wordpressAuditPageDtoSchema,
8022
+ WordpressBulkMetaResultDto: wordpressBulkMetaResultDtoSchema,
8023
+ WordpressDiffDto: wordpressDiffDtoSchema,
8024
+ WordpressManualAssistDto: wordpressManualAssistDtoSchema,
8025
+ WordpressOnboardResultDto: wordpressOnboardResultDtoSchema,
8026
+ WordpressPageDetailDto: wordpressPageDetailDtoSchema,
8027
+ WordpressPageSummaryDto: wordpressPageSummaryDtoSchema,
8028
+ WordpressSchemaBlockDto: wordpressSchemaBlockDtoSchema,
8029
+ WordpressSchemaDeployResultDto: wordpressSchemaDeployResultDtoSchema,
8030
+ WordpressSchemaStatusResultDto: wordpressSchemaStatusResultDtoSchema,
8031
+ WordpressStatusDto: wordpressStatusDtoSchema,
8032
+ // Shared envelope used by every 4xx/5xx response. Defined locally because
8033
+ // the API never returns this from a typed handler — it's emitted by the
8034
+ // global error handler. Codegen consumers reference it through the
8035
+ // ErrorEnvelope ref so error shape is part of the public contract.
8036
+ ErrorEnvelope: z.object({
8037
+ error: z.object({
8038
+ code: z.string(),
8039
+ message: z.string(),
8040
+ details: z.unknown().optional()
8041
+ })
8042
+ })
8043
+ };
8044
+ function buildComponentSchemas() {
8045
+ const out = {};
8046
+ for (const [name, schema] of Object.entries(SCHEMA_TABLE)) {
8047
+ out[name] = z.toJSONSchema(schema, { target: "openapi-3.0" });
8048
+ }
8049
+ return out;
8050
+ }
8051
+ function jsonResponse(description, schemaName) {
8052
+ return {
8053
+ description,
8054
+ content: {
8055
+ "application/json": {
8056
+ schema: { $ref: `#/components/schemas/${schemaName}` }
8057
+ }
8058
+ }
8059
+ };
8060
+ }
8061
+ function jsonArrayResponse(description, schemaName) {
8062
+ return {
8063
+ description,
8064
+ content: {
8065
+ "application/json": {
8066
+ schema: {
8067
+ type: "array",
8068
+ items: { $ref: `#/components/schemas/${schemaName}` }
8069
+ }
8070
+ }
8071
+ }
8072
+ };
8073
+ }
8074
+ function rawJsonResponse(description, schema) {
8075
+ return {
8076
+ description,
8077
+ content: {
8078
+ "application/json": { schema }
8079
+ }
8080
+ };
8081
+ }
8082
+ var looseObjectSchema = { type: "object", additionalProperties: true };
8083
+ function errorResponse(description) {
8084
+ return jsonResponse(description, "ErrorEnvelope");
8085
+ }
8086
+
7865
8087
  // ../api-routes/src/openapi.ts
7866
8088
  var stringSchema = { type: "string" };
7867
8089
  var booleanSchema = { type: "boolean" };
@@ -7994,7 +8216,7 @@ var routeCatalog = [
7994
8216
  tags: ["meta"],
7995
8217
  auth: false,
7996
8218
  responses: {
7997
- 200: { description: "OpenAPI document." }
8219
+ 200: rawJsonResponse("OpenAPI document.", looseObjectSchema)
7998
8220
  }
7999
8221
  },
8000
8222
  {
@@ -8029,8 +8251,8 @@ var routeCatalog = [
8029
8251
  }
8030
8252
  },
8031
8253
  responses: {
8032
- 200: { description: "Project updated." },
8033
- 201: { description: "Project created." }
8254
+ 200: jsonResponse("Project updated.", "ProjectDto"),
8255
+ 201: jsonResponse("Project created.", "ProjectDto")
8034
8256
  }
8035
8257
  },
8036
8258
  {
@@ -8039,7 +8261,7 @@ var routeCatalog = [
8039
8261
  summary: "List projects",
8040
8262
  tags: ["projects"],
8041
8263
  responses: {
8042
- 200: { description: "Projects returned." }
8264
+ 200: jsonArrayResponse("Projects returned.", "ProjectDto")
8043
8265
  }
8044
8266
  },
8045
8267
  {
@@ -8049,8 +8271,8 @@ var routeCatalog = [
8049
8271
  tags: ["projects"],
8050
8272
  parameters: [nameParameter],
8051
8273
  responses: {
8052
- 200: { description: "Project returned." },
8053
- 404: { description: "Project not found." }
8274
+ 200: jsonResponse("Project returned.", "ProjectDto"),
8275
+ 404: errorResponse("Project not found.")
8054
8276
  }
8055
8277
  },
8056
8278
  {
@@ -8061,7 +8283,7 @@ var routeCatalog = [
8061
8283
  parameters: [nameParameter],
8062
8284
  responses: {
8063
8285
  204: { description: "Project deleted." },
8064
- 404: { description: "Project not found." }
8286
+ 404: errorResponse("Project not found.")
8065
8287
  }
8066
8288
  },
8067
8289
  {
@@ -8072,8 +8294,9 @@ var routeCatalog = [
8072
8294
  tags: ["projects"],
8073
8295
  parameters: [nameParameter],
8074
8296
  responses: {
8075
- 200: { description: "Preview of cascade impact." },
8076
- 404: { description: "Project not found." }
8297
+ // TODO: Define `ProjectDeletePreviewDto` Zod schema in contracts and reference here.
8298
+ 200: rawJsonResponse("Preview of cascade impact.", looseObjectSchema),
8299
+ 404: errorResponse("Project not found.")
8077
8300
  }
8078
8301
  },
8079
8302
  {
@@ -8091,9 +8314,9 @@ var routeCatalog = [
8091
8314
  }
8092
8315
  },
8093
8316
  responses: {
8094
- 201: { description: "Location created." },
8095
- 400: { description: "Invalid location." },
8096
- 404: { description: "Project not found." }
8317
+ 201: jsonResponse("Location created.", "LocationContext"),
8318
+ 400: errorResponse("Invalid location."),
8319
+ 404: errorResponse("Project not found.")
8097
8320
  }
8098
8321
  },
8099
8322
  {
@@ -8103,8 +8326,9 @@ var routeCatalog = [
8103
8326
  tags: ["projects"],
8104
8327
  parameters: [nameParameter],
8105
8328
  responses: {
8106
- 200: { description: "Locations returned." },
8107
- 404: { description: "Project not found." }
8329
+ // TODO: Define `ProjectLocationsResponse` Zod schema (`{ locations: LocationContext[]; defaultLocation: string | null }`) in contracts.
8330
+ 200: rawJsonResponse("Locations returned.", looseObjectSchema),
8331
+ 404: errorResponse("Project not found.")
8108
8332
  }
8109
8333
  },
8110
8334
  {
@@ -8115,8 +8339,8 @@ var routeCatalog = [
8115
8339
  parameters: [nameParameter, locationLabelParameter],
8116
8340
  responses: {
8117
8341
  204: { description: "Location removed." },
8118
- 400: { description: "Invalid location." },
8119
- 404: { description: "Project or location not found." }
8342
+ 400: errorResponse("Invalid location."),
8343
+ 404: errorResponse("Project or location not found.")
8120
8344
  }
8121
8345
  },
8122
8346
  {
@@ -8140,9 +8364,9 @@ var routeCatalog = [
8140
8364
  }
8141
8365
  },
8142
8366
  responses: {
8143
- 200: { description: "Default location updated." },
8144
- 400: { description: "Invalid location." },
8145
- 404: { description: "Project not found." }
8367
+ 200: jsonResponse("Default location updated.", "ProjectDto"),
8368
+ 400: errorResponse("Invalid location."),
8369
+ 404: errorResponse("Project not found.")
8146
8370
  }
8147
8371
  },
8148
8372
  {
@@ -8152,8 +8376,9 @@ var routeCatalog = [
8152
8376
  tags: ["projects"],
8153
8377
  parameters: [nameParameter],
8154
8378
  responses: {
8155
- 200: { description: "Project configuration returned." },
8156
- 404: { description: "Project not found." }
8379
+ // TODO: Define an `ExportedProjectConfig` Zod schema in contracts (mirrors canonry.yaml shape).
8380
+ 200: rawJsonResponse("Project configuration returned.", looseObjectSchema),
8381
+ 404: errorResponse("Project not found.")
8157
8382
  }
8158
8383
  },
8159
8384
  {
@@ -8163,7 +8388,7 @@ var routeCatalog = [
8163
8388
  tags: ["queries"],
8164
8389
  parameters: [nameParameter],
8165
8390
  responses: {
8166
- 200: { description: "Queries returned." }
8391
+ 200: jsonArrayResponse("Queries returned.", "QueryDto")
8167
8392
  }
8168
8393
  },
8169
8394
  {
@@ -8187,7 +8412,7 @@ var routeCatalog = [
8187
8412
  }
8188
8413
  },
8189
8414
  responses: {
8190
- 200: { description: "Queries replaced." }
8415
+ 200: jsonArrayResponse("Queries replaced.", "QueryDto")
8191
8416
  }
8192
8417
  },
8193
8418
  {
@@ -8211,8 +8436,8 @@ var routeCatalog = [
8211
8436
  }
8212
8437
  },
8213
8438
  responses: {
8214
- 200: { description: "Remaining queries returned." },
8215
- 400: { description: "Invalid query delete request." }
8439
+ 200: jsonArrayResponse("Remaining queries returned.", "QueryDto"),
8440
+ 400: errorResponse("Invalid query delete request.")
8216
8441
  }
8217
8442
  },
8218
8443
  {
@@ -8236,7 +8461,7 @@ var routeCatalog = [
8236
8461
  }
8237
8462
  },
8238
8463
  responses: {
8239
- 200: { description: "Queries appended." }
8464
+ 200: jsonArrayResponse("Queries appended.", "QueryDto")
8240
8465
  }
8241
8466
  },
8242
8467
  {
@@ -8261,8 +8486,9 @@ var routeCatalog = [
8261
8486
  }
8262
8487
  },
8263
8488
  responses: {
8264
- 200: { description: "Replace preview returned." },
8265
- 404: { description: "Project not found." }
8489
+ // TODO: Add `QueriesReplacePreviewDto` Zod schema in contracts.
8490
+ 200: rawJsonResponse("Replace preview returned.", looseObjectSchema),
8491
+ 404: errorResponse("Project not found.")
8266
8492
  }
8267
8493
  },
8268
8494
  {
@@ -8287,8 +8513,8 @@ var routeCatalog = [
8287
8513
  }
8288
8514
  },
8289
8515
  responses: {
8290
- 200: { description: "Query suggestions returned." },
8291
- 501: { description: "Query generation is not available." }
8516
+ 200: rawJsonResponse("Query suggestions returned.", { type: "object", properties: { suggestions: { type: "array", items: { type: "string" } } } }),
8517
+ 501: errorResponse("Query generation is not available.")
8292
8518
  }
8293
8519
  },
8294
8520
  {
@@ -8298,7 +8524,7 @@ var routeCatalog = [
8298
8524
  tags: ["queries"],
8299
8525
  parameters: [nameParameter],
8300
8526
  responses: {
8301
- 200: { description: "Legacy keyword-shaped queries returned." }
8527
+ 200: jsonArrayResponse("Legacy keyword-shaped queries returned.", "KeywordDto")
8302
8528
  }
8303
8529
  },
8304
8530
  {
@@ -8322,7 +8548,7 @@ var routeCatalog = [
8322
8548
  }
8323
8549
  },
8324
8550
  responses: {
8325
- 200: { description: "Legacy keyword-shaped queries replaced." }
8551
+ 200: jsonArrayResponse("Legacy keyword-shaped queries replaced.", "KeywordDto")
8326
8552
  }
8327
8553
  },
8328
8554
  {
@@ -8346,8 +8572,8 @@ var routeCatalog = [
8346
8572
  }
8347
8573
  },
8348
8574
  responses: {
8349
- 200: { description: "Remaining legacy keyword-shaped queries returned." },
8350
- 400: { description: "Invalid legacy keyword delete request." }
8575
+ 200: jsonArrayResponse("Remaining legacy keyword-shaped queries returned.", "KeywordDto"),
8576
+ 400: errorResponse("Invalid legacy keyword delete request.")
8351
8577
  }
8352
8578
  },
8353
8579
  {
@@ -8371,7 +8597,7 @@ var routeCatalog = [
8371
8597
  }
8372
8598
  },
8373
8599
  responses: {
8374
- 200: { description: "Legacy keyword-shaped queries appended." }
8600
+ 200: jsonArrayResponse("Legacy keyword-shaped queries appended.", "KeywordDto")
8375
8601
  }
8376
8602
  },
8377
8603
  {
@@ -8396,8 +8622,9 @@ var routeCatalog = [
8396
8622
  }
8397
8623
  },
8398
8624
  responses: {
8399
- 200: { description: "Legacy keyword suggestions returned." },
8400
- 501: { description: "Legacy keyword generation is not available." }
8625
+ // TODO: Add `KeywordGenerateResponse` Zod schema (`{ suggestions: string[] }`) in contracts.
8626
+ 200: rawJsonResponse("Legacy keyword suggestions returned.", looseObjectSchema),
8627
+ 501: errorResponse("Legacy keyword generation is not available.")
8401
8628
  }
8402
8629
  },
8403
8630
  {
@@ -8407,7 +8634,7 @@ var routeCatalog = [
8407
8634
  tags: ["competitors"],
8408
8635
  parameters: [nameParameter],
8409
8636
  responses: {
8410
- 200: { description: "Competitors returned." }
8637
+ 200: jsonArrayResponse("Competitors returned.", "CompetitorDto")
8411
8638
  }
8412
8639
  },
8413
8640
  {
@@ -8431,7 +8658,7 @@ var routeCatalog = [
8431
8658
  }
8432
8659
  },
8433
8660
  responses: {
8434
- 200: { description: "Competitors replaced." }
8661
+ 200: jsonArrayResponse("Competitors replaced.", "CompetitorDto")
8435
8662
  }
8436
8663
  },
8437
8664
  {
@@ -8455,8 +8682,8 @@ var routeCatalog = [
8455
8682
  }
8456
8683
  },
8457
8684
  responses: {
8458
- 200: { description: "Competitors appended." },
8459
- 400: { description: "Invalid competitor append request." }
8685
+ 200: jsonArrayResponse("Competitors appended.", "CompetitorDto"),
8686
+ 400: errorResponse("Invalid competitor append request.")
8460
8687
  }
8461
8688
  },
8462
8689
  {
@@ -8480,8 +8707,8 @@ var routeCatalog = [
8480
8707
  }
8481
8708
  },
8482
8709
  responses: {
8483
- 200: { description: "Remaining competitors returned." },
8484
- 400: { description: "Invalid competitor delete request." }
8710
+ 200: jsonArrayResponse("Remaining competitors returned.", "CompetitorDto"),
8711
+ 400: errorResponse("Invalid competitor delete request.")
8485
8712
  }
8486
8713
  },
8487
8714
  {
@@ -8509,8 +8736,8 @@ var routeCatalog = [
8509
8736
  }
8510
8737
  },
8511
8738
  responses: {
8512
- 201: { description: "Run queued." },
8513
- 409: { description: "Run already in progress." }
8739
+ 201: jsonResponse("Run queued.", "RunDto"),
8740
+ 409: errorResponse("Run already in progress.")
8514
8741
  }
8515
8742
  },
8516
8743
  {
@@ -8520,7 +8747,7 @@ var routeCatalog = [
8520
8747
  tags: ["runs"],
8521
8748
  parameters: [nameParameter, limitQueryParameter],
8522
8749
  responses: {
8523
- 200: { description: "Runs returned." }
8750
+ 200: jsonArrayResponse("Runs returned.", "RunDto")
8524
8751
  }
8525
8752
  },
8526
8753
  {
@@ -8530,7 +8757,7 @@ var routeCatalog = [
8530
8757
  tags: ["runs"],
8531
8758
  parameters: [nameParameter],
8532
8759
  responses: {
8533
- 200: { description: "Latest run returned." }
8760
+ 200: jsonResponse("Latest run returned.", "LatestProjectRunDto")
8534
8761
  }
8535
8762
  },
8536
8763
  {
@@ -8539,7 +8766,7 @@ var routeCatalog = [
8539
8766
  summary: "List all runs",
8540
8767
  tags: ["runs"],
8541
8768
  responses: {
8542
- 200: { description: "Runs returned." }
8769
+ 200: jsonArrayResponse("Runs returned.", "RunDto")
8543
8770
  }
8544
8771
  },
8545
8772
  {
@@ -8561,7 +8788,8 @@ var routeCatalog = [
8561
8788
  }
8562
8789
  },
8563
8790
  responses: {
8564
- 207: { description: "Run results returned." }
8791
+ // TODO: Add `TriggerAllRunsResponse` Zod schema in contracts.
8792
+ 207: rawJsonResponse("Run results returned.", looseObjectSchema)
8565
8793
  }
8566
8794
  },
8567
8795
  {
@@ -8571,8 +8799,8 @@ var routeCatalog = [
8571
8799
  tags: ["runs"],
8572
8800
  parameters: [runIdParameter],
8573
8801
  responses: {
8574
- 200: { description: "Run returned." },
8575
- 404: { description: "Run not found." }
8802
+ 200: jsonResponse("Run returned.", "RunDetailDto"),
8803
+ 404: errorResponse("Run not found.")
8576
8804
  }
8577
8805
  },
8578
8806
  {
@@ -8582,9 +8810,9 @@ var routeCatalog = [
8582
8810
  tags: ["runs"],
8583
8811
  parameters: [runIdParameter],
8584
8812
  responses: {
8585
- 200: { description: "Run cancelled." },
8586
- 404: { description: "Run not found." },
8587
- 409: { description: "Run is not cancellable." }
8813
+ 200: jsonResponse("Run cancelled.", "RunDto"),
8814
+ 404: errorResponse("Run not found."),
8815
+ 409: errorResponse("Run is not cancellable.")
8588
8816
  }
8589
8817
  },
8590
8818
  {
@@ -8602,8 +8830,9 @@ var routeCatalog = [
8602
8830
  }
8603
8831
  },
8604
8832
  responses: {
8605
- 200: { description: "Config applied." },
8606
- 400: { description: "Invalid config." }
8833
+ // TODO: Add `ApplyResultDto` Zod schema in contracts (single-doc apply result).
8834
+ 200: jsonResponse("Config applied.", "ProjectDto"),
8835
+ 400: errorResponse("Invalid config.")
8607
8836
  }
8608
8837
  },
8609
8838
  {
@@ -8613,7 +8842,7 @@ var routeCatalog = [
8613
8842
  tags: ["history"],
8614
8843
  parameters: [nameParameter],
8615
8844
  responses: {
8616
- 200: { description: "Audit history returned." }
8845
+ 200: jsonArrayResponse("Audit history returned.", "AuditLogEntry")
8617
8846
  }
8618
8847
  },
8619
8848
  {
@@ -8622,7 +8851,7 @@ var routeCatalog = [
8622
8851
  summary: "Get global audit history",
8623
8852
  tags: ["history"],
8624
8853
  responses: {
8625
- 200: { description: "Audit history returned." }
8854
+ 200: jsonArrayResponse("Audit history returned.", "AuditLogEntry")
8626
8855
  }
8627
8856
  },
8628
8857
  {
@@ -8637,7 +8866,7 @@ var routeCatalog = [
8637
8866
  locationQueryParameter
8638
8867
  ],
8639
8868
  responses: {
8640
- 200: { description: "Snapshots returned." }
8869
+ 200: jsonResponse("Snapshots returned.", "SnapshotListResponse")
8641
8870
  }
8642
8871
  },
8643
8872
  {
@@ -8647,7 +8876,8 @@ var routeCatalog = [
8647
8876
  tags: ["history"],
8648
8877
  parameters: [nameParameter, locationQueryParameter],
8649
8878
  responses: {
8650
- 200: { description: "Timeline returned." }
8879
+ // TODO: Add `ProjectTimelineDto` Zod schema in contracts.
8880
+ 200: rawJsonResponse("Timeline returned.", looseObjectSchema)
8651
8881
  }
8652
8882
  },
8653
8883
  {
@@ -8657,8 +8887,9 @@ var routeCatalog = [
8657
8887
  tags: ["analytics"],
8658
8888
  parameters: [nameParameter, analyticsWindowParameter],
8659
8889
  responses: {
8660
- 200: { description: "Citation metrics returned." },
8661
- 404: { description: "Project not found." }
8890
+ // TODO: Add `BrandMetricsDto` Zod schema in contracts.
8891
+ 200: rawJsonResponse("Citation metrics returned.", looseObjectSchema),
8892
+ 404: errorResponse("Project not found.")
8662
8893
  }
8663
8894
  },
8664
8895
  {
@@ -8668,8 +8899,9 @@ var routeCatalog = [
8668
8899
  tags: ["analytics"],
8669
8900
  parameters: [nameParameter, analyticsWindowParameter],
8670
8901
  responses: {
8671
- 200: { description: "Gap analysis returned." },
8672
- 404: { description: "Project not found." }
8902
+ // TODO: Add `GapAnalysisDto` Zod schema in contracts.
8903
+ 200: rawJsonResponse("Gap analysis returned.", looseObjectSchema),
8904
+ 404: errorResponse("Project not found.")
8673
8905
  }
8674
8906
  },
8675
8907
  {
@@ -8679,8 +8911,9 @@ var routeCatalog = [
8679
8911
  tags: ["analytics"],
8680
8912
  parameters: [nameParameter, analyticsWindowParameter],
8681
8913
  responses: {
8682
- 200: { description: "Source breakdown returned." },
8683
- 404: { description: "Project not found." }
8914
+ // TODO: Add `SourceBreakdownDto` Zod schema in contracts.
8915
+ 200: rawJsonResponse("Source breakdown returned.", looseObjectSchema),
8916
+ 404: errorResponse("Project not found.")
8684
8917
  }
8685
8918
  },
8686
8919
  {
@@ -8706,8 +8939,8 @@ var routeCatalog = [
8706
8939
  }
8707
8940
  ],
8708
8941
  responses: {
8709
- 200: { description: "Diff returned." },
8710
- 400: { description: "Missing run IDs." }
8942
+ 200: jsonResponse("Diff returned.", "SnapshotDiffResponse"),
8943
+ 400: errorResponse("Missing run IDs.")
8711
8944
  }
8712
8945
  },
8713
8946
  {
@@ -8716,7 +8949,7 @@ var routeCatalog = [
8716
8949
  summary: "Get provider settings summary",
8717
8950
  tags: ["settings"],
8718
8951
  responses: {
8719
- 200: { description: "Settings returned." }
8952
+ 200: jsonResponse("Settings returned.", "SettingsDto")
8720
8953
  }
8721
8954
  },
8722
8955
  {
@@ -8742,9 +8975,10 @@ var routeCatalog = [
8742
8975
  }
8743
8976
  },
8744
8977
  responses: {
8745
- 200: { description: "Provider updated." },
8746
- 400: { description: "Invalid provider settings." },
8747
- 501: { description: "Provider updates are not supported." }
8978
+ // TODO: Add `ProviderSettingsDto` Zod schema in contracts.
8979
+ 200: rawJsonResponse("Provider updated.", looseObjectSchema),
8980
+ 400: errorResponse("Invalid provider settings."),
8981
+ 501: errorResponse("Provider updates are not supported.")
8748
8982
  }
8749
8983
  },
8750
8984
  {
@@ -8768,9 +9002,10 @@ var routeCatalog = [
8768
9002
  }
8769
9003
  },
8770
9004
  responses: {
8771
- 200: { description: "Google settings updated." },
8772
- 400: { description: "Invalid Google settings." },
8773
- 501: { description: "Google settings updates are not supported." }
9005
+ // TODO: Add `GoogleSettingsDto` Zod schema in contracts.
9006
+ 200: rawJsonResponse("Google settings updated.", looseObjectSchema),
9007
+ 400: errorResponse("Invalid Google settings."),
9008
+ 501: errorResponse("Google settings updates are not supported.")
8774
9009
  }
8775
9010
  },
8776
9011
  {
@@ -8796,9 +9031,9 @@ var routeCatalog = [
8796
9031
  }
8797
9032
  },
8798
9033
  responses: {
8799
- 200: { description: "Snapshot report returned." },
8800
- 400: { description: "Invalid snapshot input." },
8801
- 501: { description: "Snapshot reporting is not supported." }
9034
+ 200: jsonResponse("Snapshot report returned.", "SnapshotReportDto"),
9035
+ 400: errorResponse("Invalid snapshot input."),
9036
+ 501: errorResponse("Snapshot reporting is not supported.")
8802
9037
  }
8803
9038
  },
8804
9039
  {
@@ -8821,9 +9056,10 @@ var routeCatalog = [
8821
9056
  }
8822
9057
  },
8823
9058
  responses: {
8824
- 200: { description: "Bing settings updated." },
8825
- 400: { description: "Invalid Bing settings." },
8826
- 501: { description: "Bing settings updates are not supported." }
9059
+ // TODO: Add `BingSettingsDto` Zod schema in contracts.
9060
+ 200: rawJsonResponse("Bing settings updated.", looseObjectSchema),
9061
+ 400: errorResponse("Invalid Bing settings."),
9062
+ 501: errorResponse("Bing settings updates are not supported.")
8827
9063
  }
8828
9064
  },
8829
9065
  {
@@ -8847,9 +9083,10 @@ var routeCatalog = [
8847
9083
  }
8848
9084
  },
8849
9085
  responses: {
8850
- 200: { description: "CDP endpoint updated." },
8851
- 400: { description: "Invalid CDP settings." },
8852
- 501: { description: "CDP updates are not supported." }
9086
+ // TODO: Add `CdpEndpointConfigDto` Zod schema in contracts.
9087
+ 200: rawJsonResponse("CDP endpoint updated.", looseObjectSchema),
9088
+ 400: errorResponse("Invalid CDP settings."),
9089
+ 501: errorResponse("CDP updates are not supported.")
8853
9090
  }
8854
9091
  },
8855
9092
  {
@@ -8878,9 +9115,9 @@ var routeCatalog = [
8878
9115
  }
8879
9116
  },
8880
9117
  responses: {
8881
- 200: { description: "Schedule updated." },
8882
- 201: { description: "Schedule created." },
8883
- 400: { description: "Invalid payload (e.g. sourceId missing for kind=traffic-sync, or providers set for kind=traffic-sync)." }
9118
+ 200: jsonResponse("Schedule updated.", "ScheduleDto"),
9119
+ 201: jsonResponse("Schedule created.", "ScheduleDto"),
9120
+ 400: errorResponse("Invalid payload (e.g. sourceId missing for kind=traffic-sync, or providers set for kind=traffic-sync).")
8884
9121
  }
8885
9122
  },
8886
9123
  {
@@ -8890,8 +9127,8 @@ var routeCatalog = [
8890
9127
  tags: ["schedules"],
8891
9128
  parameters: [nameParameter, scheduleKindQueryParameter],
8892
9129
  responses: {
8893
- 200: { description: "Schedule returned." },
8894
- 404: { description: "Schedule not found." }
9130
+ 200: jsonResponse("Schedule returned.", "ScheduleDto"),
9131
+ 404: errorResponse("Schedule not found.")
8895
9132
  }
8896
9133
  },
8897
9134
  {
@@ -8902,7 +9139,7 @@ var routeCatalog = [
8902
9139
  parameters: [nameParameter, scheduleKindQueryParameter],
8903
9140
  responses: {
8904
9141
  204: { description: "Schedule deleted." },
8905
- 404: { description: "Schedule not found." }
9142
+ 404: errorResponse("Schedule not found.")
8906
9143
  }
8907
9144
  },
8908
9145
  {
@@ -8911,7 +9148,7 @@ var routeCatalog = [
8911
9148
  summary: "List notification event types",
8912
9149
  tags: ["notifications"],
8913
9150
  responses: {
8914
- 200: { description: "Events returned." }
9151
+ 200: rawJsonResponse("Events returned.", { type: "array", items: stringSchema })
8915
9152
  }
8916
9153
  },
8917
9154
  {
@@ -8937,7 +9174,7 @@ var routeCatalog = [
8937
9174
  }
8938
9175
  },
8939
9176
  responses: {
8940
- 201: { description: "Notification created." }
9177
+ 201: jsonResponse("Notification created.", "NotificationDto")
8941
9178
  }
8942
9179
  },
8943
9180
  {
@@ -8947,7 +9184,7 @@ var routeCatalog = [
8947
9184
  tags: ["notifications"],
8948
9185
  parameters: [nameParameter],
8949
9186
  responses: {
8950
- 200: { description: "Notifications returned." }
9187
+ 200: jsonArrayResponse("Notifications returned.", "NotificationDto")
8951
9188
  }
8952
9189
  },
8953
9190
  {
@@ -8958,7 +9195,7 @@ var routeCatalog = [
8958
9195
  parameters: [nameParameter, notificationIdParameter],
8959
9196
  responses: {
8960
9197
  204: { description: "Notification deleted." },
8961
- 404: { description: "Notification not found." }
9198
+ 404: errorResponse("Notification not found.")
8962
9199
  }
8963
9200
  },
8964
9201
  {
@@ -8968,10 +9205,11 @@ var routeCatalog = [
8968
9205
  tags: ["notifications"],
8969
9206
  parameters: [nameParameter, notificationIdParameter],
8970
9207
  responses: {
8971
- 200: { description: "Test notification sent." },
8972
- 400: { description: "Stored notification config is invalid." },
8973
- 404: { description: "Notification not found." },
8974
- 502: { description: "Notification delivery failed." }
9208
+ // TODO: Add `NotificationTestResult` Zod schema in contracts.
9209
+ 200: rawJsonResponse("Test notification sent.", looseObjectSchema),
9210
+ 400: errorResponse("Stored notification config is invalid."),
9211
+ 404: errorResponse("Notification not found."),
9212
+ 502: errorResponse("Notification delivery failed.")
8975
9213
  }
8976
9214
  },
8977
9215
  {
@@ -8980,8 +9218,9 @@ var routeCatalog = [
8980
9218
  summary: "Get telemetry status",
8981
9219
  tags: ["telemetry"],
8982
9220
  responses: {
8983
- 200: { description: "Telemetry status returned." },
8984
- 501: { description: "Telemetry status is not available." }
9221
+ // TODO: Add `TelemetryStatusDto` Zod schema in contracts.
9222
+ 200: rawJsonResponse("Telemetry status returned.", looseObjectSchema),
9223
+ 501: errorResponse("Telemetry status is not available.")
8985
9224
  }
8986
9225
  },
8987
9226
  {
@@ -9004,9 +9243,10 @@ var routeCatalog = [
9004
9243
  }
9005
9244
  },
9006
9245
  responses: {
9007
- 200: { description: "Telemetry updated." },
9008
- 400: { description: "Invalid telemetry request." },
9009
- 501: { description: "Telemetry configuration is not available." }
9246
+ // TODO: Add `TelemetryStatusDto` Zod schema in contracts.
9247
+ 200: rawJsonResponse("Telemetry updated.", looseObjectSchema),
9248
+ 400: errorResponse("Invalid telemetry request."),
9249
+ 501: errorResponse("Telemetry configuration is not available.")
9010
9250
  }
9011
9251
  },
9012
9252
  {
@@ -9016,8 +9256,9 @@ var routeCatalog = [
9016
9256
  tags: ["cdp"],
9017
9257
  parameters: [snapshotIdParameter],
9018
9258
  responses: {
9019
- 200: { description: "Screenshot returned." },
9020
- 404: { description: "Screenshot not found." }
9259
+ // Returns image bytes, not JSON. Codegen consumers should treat this as a binary stream.
9260
+ 200: { description: "Screenshot returned.", content: { "image/png": { schema: { type: "string", format: "binary" } } } },
9261
+ 404: errorResponse("Screenshot not found.")
9021
9262
  }
9022
9263
  },
9023
9264
  {
@@ -9026,8 +9267,8 @@ var routeCatalog = [
9026
9267
  summary: "Get CDP connection status",
9027
9268
  tags: ["cdp"],
9028
9269
  responses: {
9029
- 200: { description: "CDP status returned." },
9030
- 501: { description: "CDP is not configured." }
9270
+ 200: jsonResponse("CDP status returned.", "CdpStatusDto"),
9271
+ 501: errorResponse("CDP is not configured.")
9031
9272
  }
9032
9273
  },
9033
9274
  {
@@ -9051,9 +9292,10 @@ var routeCatalog = [
9051
9292
  }
9052
9293
  },
9053
9294
  responses: {
9054
- 200: { description: "CDP screenshot results returned." },
9055
- 400: { description: "Invalid CDP screenshot request." },
9056
- 501: { description: "CDP screenshot support is not available." }
9295
+ // TODO: Add `CdpScreenshotResultDto` Zod schema in contracts.
9296
+ 200: rawJsonResponse("CDP screenshot results returned.", looseObjectSchema),
9297
+ 400: errorResponse("Invalid CDP screenshot request."),
9298
+ 501: errorResponse("CDP screenshot support is not available.")
9057
9299
  }
9058
9300
  },
9059
9301
  {
@@ -9063,8 +9305,9 @@ var routeCatalog = [
9063
9305
  tags: ["cdp", "runs"],
9064
9306
  parameters: [nameParameter, projectRunIdParameter],
9065
9307
  responses: {
9066
- 200: { description: "Browser diff returned." },
9067
- 404: { description: "Project or run not found." }
9308
+ // TODO: Add `BrowserDiffDto` Zod schema in contracts.
9309
+ 200: rawJsonResponse("Browser diff returned.", looseObjectSchema),
9310
+ 404: errorResponse("Project or run not found.")
9068
9311
  }
9069
9312
  },
9070
9313
  {
@@ -9079,9 +9322,9 @@ var routeCatalog = [
9079
9322
  { name: "error", in: "query", description: "OAuth error code.", schema: stringSchema }
9080
9323
  ],
9081
9324
  responses: {
9082
- 200: { description: "OAuth callback handled." },
9083
- 400: { description: "Invalid callback request." },
9084
- 500: { description: "OAuth configuration is incomplete." }
9325
+ 200: rawJsonResponse("OAuth callback handled.", { type: "object", properties: { status: { type: "string" } } }),
9326
+ 400: errorResponse("Invalid callback request."),
9327
+ 500: errorResponse("OAuth configuration is incomplete.")
9085
9328
  }
9086
9329
  },
9087
9330
  {
@@ -9097,9 +9340,9 @@ var routeCatalog = [
9097
9340
  { name: "error", in: "query", description: "OAuth error code.", schema: stringSchema }
9098
9341
  ],
9099
9342
  responses: {
9100
- 200: { description: "OAuth callback handled." },
9101
- 400: { description: "Invalid callback request." },
9102
- 500: { description: "OAuth configuration is incomplete." }
9343
+ 200: rawJsonResponse("OAuth callback handled.", { type: "object", properties: { status: { type: "string" } } }),
9344
+ 400: errorResponse("Invalid callback request."),
9345
+ 500: errorResponse("OAuth configuration is incomplete.")
9103
9346
  }
9104
9347
  },
9105
9348
  {
@@ -9109,8 +9352,8 @@ var routeCatalog = [
9109
9352
  tags: ["google"],
9110
9353
  parameters: [nameParameter],
9111
9354
  responses: {
9112
- 200: { description: "Google connections returned." },
9113
- 404: { description: "Project not found." }
9355
+ 200: jsonArrayResponse("Google connections returned.", "GoogleConnectionDto"),
9356
+ 404: errorResponse("Project not found.")
9114
9357
  }
9115
9358
  },
9116
9359
  {
@@ -9136,8 +9379,8 @@ var routeCatalog = [
9136
9379
  }
9137
9380
  },
9138
9381
  responses: {
9139
- 200: { description: "Google auth URL returned." },
9140
- 400: { description: "Invalid Google connection request." }
9382
+ 200: rawJsonResponse("Google auth URL returned.", { type: "object", properties: { url: { type: "string" } } }),
9383
+ 400: errorResponse("Invalid Google connection request.")
9141
9384
  }
9142
9385
  },
9143
9386
  {
@@ -9148,7 +9391,7 @@ var routeCatalog = [
9148
9391
  parameters: [nameParameter, googleTypeParameter],
9149
9392
  responses: {
9150
9393
  204: { description: "Google connection deleted." },
9151
- 404: { description: "Project or connection not found." }
9394
+ 404: errorResponse("Project or connection not found.")
9152
9395
  }
9153
9396
  },
9154
9397
  {
@@ -9158,9 +9401,9 @@ var routeCatalog = [
9158
9401
  tags: ["google"],
9159
9402
  parameters: [nameParameter],
9160
9403
  responses: {
9161
- 200: { description: "Google properties returned." },
9162
- 400: { description: "Google OAuth is not configured." },
9163
- 404: { description: "Project not found." }
9404
+ 200: jsonResponse("Google properties returned.", "GscSiteListResponseDto"),
9405
+ 400: errorResponse("Google OAuth is not configured."),
9406
+ 404: errorResponse("Project not found.")
9164
9407
  }
9165
9408
  },
9166
9409
  {
@@ -9184,9 +9427,9 @@ var routeCatalog = [
9184
9427
  }
9185
9428
  },
9186
9429
  responses: {
9187
- 200: { description: "Google property updated." },
9188
- 400: { description: "Invalid property request." },
9189
- 404: { description: "Project or connection not found." }
9430
+ 200: jsonResponse("Google property updated.", "GoogleConnectionDto"),
9431
+ 400: errorResponse("Invalid property request."),
9432
+ 404: errorResponse("Project or connection not found.")
9190
9433
  }
9191
9434
  },
9192
9435
  {
@@ -9210,9 +9453,9 @@ var routeCatalog = [
9210
9453
  }
9211
9454
  },
9212
9455
  responses: {
9213
- 200: { description: "Google sitemap updated." },
9214
- 400: { description: "Invalid sitemap request." },
9215
- 404: { description: "Project or connection not found." }
9456
+ 200: jsonResponse("Google sitemap updated.", "GoogleConnectionDto"),
9457
+ 400: errorResponse("Invalid sitemap request."),
9458
+ 404: errorResponse("Project or connection not found.")
9216
9459
  }
9217
9460
  },
9218
9461
  {
@@ -9235,9 +9478,9 @@ var routeCatalog = [
9235
9478
  }
9236
9479
  },
9237
9480
  responses: {
9238
- 200: { description: "GSC sync run returned." },
9239
- 400: { description: "Invalid GSC sync request." },
9240
- 404: { description: "Project or connection not found." }
9481
+ 200: jsonResponse("GSC sync run returned.", "RunDto"),
9482
+ 400: errorResponse("Invalid GSC sync request."),
9483
+ 404: errorResponse("Project or connection not found.")
9241
9484
  }
9242
9485
  },
9243
9486
  {
@@ -9256,8 +9499,11 @@ var routeCatalog = [
9256
9499
  analyticsWindowParameter
9257
9500
  ],
9258
9501
  responses: {
9259
- 200: { description: "GSC performance rows returned." },
9260
- 404: { description: "Project not found." }
9502
+ // Handler returns an array of GscSearchDataDto rows (web's
9503
+ // ApiGscPerformanceRow[] confirms). Was incorrectly spec'd as a
9504
+ // single object, which silently truncated client types to one row.
9505
+ 200: jsonArrayResponse("GSC performance rows returned.", "GscSearchDataDto"),
9506
+ 404: errorResponse("Project not found.")
9261
9507
  }
9262
9508
  },
9263
9509
  {
@@ -9272,8 +9518,8 @@ var routeCatalog = [
9272
9518
  analyticsWindowParameter
9273
9519
  ],
9274
9520
  responses: {
9275
- 200: { description: "Daily aggregate (date \u2192 clicks/impressions/ctr) plus window totals." },
9276
- 404: { description: "Project not found." }
9521
+ 200: jsonResponse("Daily aggregate (date \u2192 clicks/impressions/ctr) plus window totals.", "GscPerformanceDailyDto"),
9522
+ 404: errorResponse("Project not found.")
9277
9523
  }
9278
9524
  },
9279
9525
  {
@@ -9297,9 +9543,9 @@ var routeCatalog = [
9297
9543
  }
9298
9544
  },
9299
9545
  responses: {
9300
- 200: { description: "GSC inspection result returned." },
9301
- 400: { description: "Invalid inspection request." },
9302
- 404: { description: "Project or connection not found." }
9546
+ 200: jsonResponse("GSC inspection result returned.", "GscUrlInspectionDto"),
9547
+ 400: errorResponse("Invalid inspection request."),
9548
+ 404: errorResponse("Project or connection not found.")
9303
9549
  }
9304
9550
  },
9305
9551
  {
@@ -9309,8 +9555,8 @@ var routeCatalog = [
9309
9555
  tags: ["google"],
9310
9556
  parameters: [nameParameter, { name: "url", in: "query", description: "Filter by URL.", schema: stringSchema }, limitQueryParameter],
9311
9557
  responses: {
9312
- 200: { description: "GSC inspections returned." },
9313
- 404: { description: "Project not found." }
9558
+ 200: jsonArrayResponse("GSC inspections returned.", "GscUrlInspectionDto"),
9559
+ 404: errorResponse("Project not found.")
9314
9560
  }
9315
9561
  },
9316
9562
  {
@@ -9320,8 +9566,8 @@ var routeCatalog = [
9320
9566
  tags: ["google"],
9321
9567
  parameters: [nameParameter],
9322
9568
  responses: {
9323
- 200: { description: "Deindexed pages returned." },
9324
- 404: { description: "Project not found." }
9569
+ 200: jsonArrayResponse("Deindexed pages returned.", "GscDeindexedRowDto"),
9570
+ 404: errorResponse("Project not found.")
9325
9571
  }
9326
9572
  },
9327
9573
  {
@@ -9331,8 +9577,8 @@ var routeCatalog = [
9331
9577
  tags: ["google"],
9332
9578
  parameters: [nameParameter],
9333
9579
  responses: {
9334
- 200: { description: "GSC coverage returned." },
9335
- 404: { description: "Project not found." }
9580
+ 200: jsonResponse("GSC coverage returned.", "GscCoverageSummaryDto"),
9581
+ 404: errorResponse("Project not found.")
9336
9582
  }
9337
9583
  },
9338
9584
  {
@@ -9342,8 +9588,8 @@ var routeCatalog = [
9342
9588
  tags: ["google"],
9343
9589
  parameters: [nameParameter, limitQueryParameter],
9344
9590
  responses: {
9345
- 200: { description: "GSC coverage history returned." },
9346
- 404: { description: "Project not found." }
9591
+ 200: jsonArrayResponse("GSC coverage history returned.", "GscCoverageSnapshotDto"),
9592
+ 404: errorResponse("Project not found.")
9347
9593
  }
9348
9594
  },
9349
9595
  {
@@ -9353,9 +9599,9 @@ var routeCatalog = [
9353
9599
  tags: ["google"],
9354
9600
  parameters: [nameParameter],
9355
9601
  responses: {
9356
- 200: { description: "GSC sitemaps returned." },
9357
- 400: { description: "Invalid sitemap request." },
9358
- 404: { description: "Project or connection not found." }
9602
+ 200: jsonResponse("GSC sitemaps returned.", "GscSitemapListResponseDto"),
9603
+ 400: errorResponse("Invalid sitemap request."),
9604
+ 404: errorResponse("Project or connection not found.")
9359
9605
  }
9360
9606
  },
9361
9607
  {
@@ -9365,9 +9611,10 @@ var routeCatalog = [
9365
9611
  tags: ["google"],
9366
9612
  parameters: [nameParameter],
9367
9613
  responses: {
9368
- 200: { description: "Discovered sitemaps and queued run returned." },
9369
- 400: { description: "Invalid sitemap discovery request." },
9370
- 404: { description: "Project or connection not found." }
9614
+ // TODO: Add `DiscoverSitemapsResponse` Zod schema in contracts.
9615
+ 200: rawJsonResponse("Discovered sitemaps and queued run returned.", looseObjectSchema),
9616
+ 400: errorResponse("Invalid sitemap discovery request."),
9617
+ 404: errorResponse("Project or connection not found.")
9371
9618
  }
9372
9619
  },
9373
9620
  {
@@ -9389,9 +9636,9 @@ var routeCatalog = [
9389
9636
  }
9390
9637
  },
9391
9638
  responses: {
9392
- 200: { description: "Sitemap inspection run returned." },
9393
- 400: { description: "Invalid sitemap inspection request." },
9394
- 404: { description: "Project or connection not found." }
9639
+ 200: jsonResponse("Sitemap inspection run returned.", "RunDto"),
9640
+ 400: errorResponse("Invalid sitemap inspection request."),
9641
+ 404: errorResponse("Project or connection not found.")
9395
9642
  }
9396
9643
  },
9397
9644
  {
@@ -9415,9 +9662,9 @@ var routeCatalog = [
9415
9662
  }
9416
9663
  },
9417
9664
  responses: {
9418
- 200: { description: "Indexing request results returned." },
9419
- 400: { description: "Invalid indexing request." },
9420
- 404: { description: "Project or connection not found." }
9665
+ 200: jsonResponse("Indexing request results returned.", "IndexingRequestResponseDto"),
9666
+ 400: errorResponse("Invalid indexing request."),
9667
+ 404: errorResponse("Project or connection not found.")
9421
9668
  }
9422
9669
  },
9423
9670
  {
@@ -9441,9 +9688,9 @@ var routeCatalog = [
9441
9688
  }
9442
9689
  },
9443
9690
  responses: {
9444
- 200: { description: "Bing connection returned." },
9445
- 400: { description: "Invalid Bing connection request." },
9446
- 404: { description: "Project not found." }
9691
+ 200: jsonResponse("Bing connection returned.", "BingConnectResponseDto"),
9692
+ 400: errorResponse("Invalid Bing connection request."),
9693
+ 404: errorResponse("Project not found.")
9447
9694
  }
9448
9695
  },
9449
9696
  {
@@ -9454,7 +9701,7 @@ var routeCatalog = [
9454
9701
  parameters: [nameParameter],
9455
9702
  responses: {
9456
9703
  204: { description: "Bing connection deleted." },
9457
- 404: { description: "Project or connection not found." }
9704
+ 404: errorResponse("Project or connection not found.")
9458
9705
  }
9459
9706
  },
9460
9707
  {
@@ -9464,8 +9711,8 @@ var routeCatalog = [
9464
9711
  tags: ["bing"],
9465
9712
  parameters: [nameParameter],
9466
9713
  responses: {
9467
- 200: { description: "Bing status returned." },
9468
- 404: { description: "Project not found." }
9714
+ 200: jsonResponse("Bing status returned.", "BingStatusDto"),
9715
+ 404: errorResponse("Project not found.")
9469
9716
  }
9470
9717
  },
9471
9718
  {
@@ -9475,9 +9722,9 @@ var routeCatalog = [
9475
9722
  tags: ["bing"],
9476
9723
  parameters: [nameParameter],
9477
9724
  responses: {
9478
- 200: { description: "Bing sites returned." },
9479
- 400: { description: "Bing is not configured for this project." },
9480
- 404: { description: "Project not found." }
9725
+ 200: jsonResponse("Bing sites returned.", "BingSitesResponseDto"),
9726
+ 400: errorResponse("Bing is not configured for this project."),
9727
+ 404: errorResponse("Project not found.")
9481
9728
  }
9482
9729
  },
9483
9730
  {
@@ -9501,9 +9748,9 @@ var routeCatalog = [
9501
9748
  }
9502
9749
  },
9503
9750
  responses: {
9504
- 200: { description: "Active Bing site updated." },
9505
- 400: { description: "Invalid Bing site request." },
9506
- 404: { description: "Project or connection not found." }
9751
+ 200: jsonResponse("Active Bing site updated.", "BingSetSiteResponseDto"),
9752
+ 400: errorResponse("Invalid Bing site request."),
9753
+ 404: errorResponse("Project or connection not found.")
9507
9754
  }
9508
9755
  },
9509
9756
  {
@@ -9513,9 +9760,13 @@ var routeCatalog = [
9513
9760
  tags: ["bing"],
9514
9761
  parameters: [nameParameter],
9515
9762
  responses: {
9516
- 200: { description: "Bing coverage returned." },
9517
- 400: { description: "Bing is not configured for this project." },
9518
- 404: { description: "Project not found." }
9763
+ // Was incorrectly mapped to `BingCoverageSnapshotDto` (the daily
9764
+ // history snapshot 4 fields). The /coverage handler actually
9765
+ // returns the nested summary shape with indexed/notIndexed/unknown
9766
+ // arrays. `BingCoverageSummaryDto` is the right ref.
9767
+ 200: jsonResponse("Bing coverage returned.", "BingCoverageSummaryDto"),
9768
+ 400: errorResponse("Bing is not configured for this project."),
9769
+ 404: errorResponse("Project not found.")
9519
9770
  }
9520
9771
  },
9521
9772
  {
@@ -9525,9 +9776,9 @@ var routeCatalog = [
9525
9776
  tags: ["bing"],
9526
9777
  parameters: [nameParameter, limitQueryParameter],
9527
9778
  responses: {
9528
- 200: { description: "Bing coverage history returned." },
9529
- 400: { description: "Bing is not configured for this project." },
9530
- 404: { description: "Project not found." }
9779
+ 200: jsonArrayResponse("Bing coverage history returned.", "BingCoverageSnapshotDto"),
9780
+ 400: errorResponse("Bing is not configured for this project."),
9781
+ 404: errorResponse("Project not found.")
9531
9782
  }
9532
9783
  },
9533
9784
  {
@@ -9537,9 +9788,9 @@ var routeCatalog = [
9537
9788
  tags: ["bing"],
9538
9789
  parameters: [nameParameter, { name: "url", in: "query", description: "Filter by URL.", schema: stringSchema }, limitQueryParameter],
9539
9790
  responses: {
9540
- 200: { description: "Bing inspections returned." },
9541
- 400: { description: "Bing is not configured for this project." },
9542
- 404: { description: "Project not found." }
9791
+ 200: jsonArrayResponse("Bing inspections returned.", "BingUrlInspectionDto"),
9792
+ 400: errorResponse("Bing is not configured for this project."),
9793
+ 404: errorResponse("Project not found.")
9543
9794
  }
9544
9795
  },
9545
9796
  {
@@ -9563,9 +9814,9 @@ var routeCatalog = [
9563
9814
  }
9564
9815
  },
9565
9816
  responses: {
9566
- 200: { description: "Bing inspection result returned." },
9567
- 400: { description: "Invalid inspection request." },
9568
- 404: { description: "Project or connection not found." }
9817
+ 200: jsonResponse("Bing inspection result returned.", "BingUrlInspectionDto"),
9818
+ 400: errorResponse("Invalid inspection request."),
9819
+ 404: errorResponse("Project or connection not found.")
9569
9820
  }
9570
9821
  },
9571
9822
  {
@@ -9588,9 +9839,9 @@ var routeCatalog = [
9588
9839
  }
9589
9840
  },
9590
9841
  responses: {
9591
- 200: { description: "Sitemap inspection run queued." },
9592
- 400: { description: "Bing is not configured for this project." },
9593
- 404: { description: "Project not found." }
9842
+ 200: jsonResponse("Sitemap inspection run queued.", "RunDto"),
9843
+ 400: errorResponse("Bing is not configured for this project."),
9844
+ 404: errorResponse("Project not found.")
9594
9845
  }
9595
9846
  },
9596
9847
  {
@@ -9614,9 +9865,9 @@ var routeCatalog = [
9614
9865
  }
9615
9866
  },
9616
9867
  responses: {
9617
- 200: { description: "Bing indexing request results returned." },
9618
- 400: { description: "Invalid indexing request." },
9619
- 404: { description: "Project or connection not found." }
9868
+ 200: jsonResponse("Bing indexing request results returned.", "BingIndexingRequestResponseDto"),
9869
+ 400: errorResponse("Invalid indexing request."),
9870
+ 404: errorResponse("Project or connection not found.")
9620
9871
  }
9621
9872
  },
9622
9873
  {
@@ -9626,9 +9877,9 @@ var routeCatalog = [
9626
9877
  tags: ["bing"],
9627
9878
  parameters: [nameParameter, limitQueryParameter],
9628
9879
  responses: {
9629
- 200: { description: "Bing performance returned." },
9630
- 400: { description: "Bing is not configured for this project." },
9631
- 404: { description: "Project not found." }
9880
+ 200: jsonArrayResponse("Bing performance returned.", "BingKeywordStatsDto"),
9881
+ 400: errorResponse("Bing is not configured for this project."),
9882
+ 404: errorResponse("Project not found.")
9632
9883
  }
9633
9884
  },
9634
9885
  {
@@ -9656,9 +9907,9 @@ var routeCatalog = [
9656
9907
  }
9657
9908
  },
9658
9909
  responses: {
9659
- 200: { description: "WordPress connection status returned." },
9660
- 400: { description: "Invalid WordPress connection request." },
9661
- 404: { description: "Project not found." }
9910
+ 200: jsonResponse("WordPress connection status returned.", "WordpressStatusDto"),
9911
+ 400: errorResponse("Invalid WordPress connection request."),
9912
+ 404: errorResponse("Project not found.")
9662
9913
  }
9663
9914
  },
9664
9915
  {
@@ -9669,7 +9920,7 @@ var routeCatalog = [
9669
9920
  parameters: [nameParameter],
9670
9921
  responses: {
9671
9922
  204: { description: "WordPress connection deleted." },
9672
- 404: { description: "Project or connection not found." }
9923
+ 404: errorResponse("Project or connection not found.")
9673
9924
  }
9674
9925
  },
9675
9926
  {
@@ -9679,8 +9930,8 @@ var routeCatalog = [
9679
9930
  tags: ["wordpress"],
9680
9931
  parameters: [nameParameter],
9681
9932
  responses: {
9682
- 200: { description: "WordPress status returned." },
9683
- 404: { description: "Project not found." }
9933
+ 200: jsonResponse("WordPress status returned.", "WordpressStatusDto"),
9934
+ 404: errorResponse("Project not found.")
9684
9935
  }
9685
9936
  },
9686
9937
  {
@@ -9690,9 +9941,9 @@ var routeCatalog = [
9690
9941
  tags: ["wordpress"],
9691
9942
  parameters: [nameParameter, wordpressEnvQueryParameter],
9692
9943
  responses: {
9693
- 200: { description: "WordPress pages returned." },
9694
- 400: { description: "Invalid environment or missing connection." },
9695
- 404: { description: "Project not found." }
9944
+ 200: jsonArrayResponse("WordPress pages returned.", "WordpressPageSummaryDto"),
9945
+ 400: errorResponse("Invalid environment or missing connection."),
9946
+ 404: errorResponse("Project not found.")
9696
9947
  }
9697
9948
  },
9698
9949
  {
@@ -9702,9 +9953,9 @@ var routeCatalog = [
9702
9953
  tags: ["wordpress"],
9703
9954
  parameters: [nameParameter, wordpressSlugQueryParameter, wordpressEnvQueryParameter],
9704
9955
  responses: {
9705
- 200: { description: "WordPress page returned." },
9706
- 400: { description: "Invalid slug or environment." },
9707
- 404: { description: "Project, connection, or page not found." }
9956
+ 200: jsonResponse("WordPress page returned.", "WordpressPageDetailDto"),
9957
+ 400: errorResponse("Invalid slug or environment."),
9958
+ 404: errorResponse("Project, connection, or page not found.")
9708
9959
  }
9709
9960
  },
9710
9961
  {
@@ -9732,9 +9983,9 @@ var routeCatalog = [
9732
9983
  }
9733
9984
  },
9734
9985
  responses: {
9735
- 200: { description: "WordPress page created." },
9736
- 400: { description: "Invalid page creation request." },
9737
- 404: { description: "Project or connection not found." }
9986
+ 200: jsonResponse("WordPress page created.", "WordpressPageDetailDto"),
9987
+ 400: errorResponse("Invalid page creation request."),
9988
+ 404: errorResponse("Project or connection not found.")
9738
9989
  }
9739
9990
  },
9740
9991
  {
@@ -9763,9 +10014,9 @@ var routeCatalog = [
9763
10014
  }
9764
10015
  },
9765
10016
  responses: {
9766
- 200: { description: "WordPress page updated." },
9767
- 400: { description: "Invalid page update request." },
9768
- 404: { description: "Project, connection, or page not found." }
10017
+ 200: jsonResponse("WordPress page updated.", "WordpressPageDetailDto"),
10018
+ 400: errorResponse("Invalid page update request."),
10019
+ 404: errorResponse("Project, connection, or page not found.")
9769
10020
  }
9770
10021
  },
9771
10022
  {
@@ -9793,9 +10044,10 @@ var routeCatalog = [
9793
10044
  }
9794
10045
  },
9795
10046
  responses: {
9796
- 200: { description: "WordPress SEO meta updated." },
9797
- 400: { description: "SEO meta is unsupported or the request is invalid." },
9798
- 404: { description: "Project, connection, or page not found." }
10047
+ // TODO: Add `WordpressSeoStateDto` to the schema table (already in contracts).
10048
+ 200: rawJsonResponse("WordPress SEO meta updated.", looseObjectSchema),
10049
+ 400: errorResponse("SEO meta is unsupported or the request is invalid."),
10050
+ 404: errorResponse("Project, connection, or page not found.")
9799
10051
  }
9800
10052
  },
9801
10053
  {
@@ -9832,9 +10084,9 @@ var routeCatalog = [
9832
10084
  }
9833
10085
  },
9834
10086
  responses: {
9835
- 200: { description: "Bulk SEO meta update results returned." },
9836
- 400: { description: "Invalid entries or environment." },
9837
- 404: { description: "Project or connection not found." }
10087
+ 200: jsonResponse("Bulk SEO meta update results returned.", "WordpressBulkMetaResultDto"),
10088
+ 400: errorResponse("Invalid entries or environment."),
10089
+ 404: errorResponse("Project or connection not found.")
9838
10090
  }
9839
10091
  },
9840
10092
  {
@@ -9844,9 +10096,9 @@ var routeCatalog = [
9844
10096
  tags: ["wordpress"],
9845
10097
  parameters: [nameParameter, wordpressSlugQueryParameter, wordpressEnvQueryParameter],
9846
10098
  responses: {
9847
- 200: { description: "WordPress schema blocks returned." },
9848
- 400: { description: "Invalid slug or environment." },
9849
- 404: { description: "Project, connection, or page not found." }
10099
+ 200: jsonArrayResponse("WordPress schema blocks returned.", "WordpressSchemaBlockDto"),
10100
+ 400: errorResponse("Invalid slug or environment."),
10101
+ 404: errorResponse("Project, connection, or page not found.")
9850
10102
  }
9851
10103
  },
9852
10104
  {
@@ -9873,9 +10125,9 @@ var routeCatalog = [
9873
10125
  }
9874
10126
  },
9875
10127
  responses: {
9876
- 200: { description: "Manual schema instructions returned." },
9877
- 400: { description: "Invalid schema request." },
9878
- 404: { description: "Project, connection, or page not found." }
10128
+ 200: jsonResponse("Manual schema instructions returned.", "WordpressManualAssistDto"),
10129
+ 400: errorResponse("Invalid schema request."),
10130
+ 404: errorResponse("Project, connection, or page not found.")
9879
10131
  }
9880
10132
  },
9881
10133
  {
@@ -9903,9 +10155,9 @@ var routeCatalog = [
9903
10155
  }
9904
10156
  },
9905
10157
  responses: {
9906
- 200: { description: "Schema deployment results returned." },
9907
- 400: { description: "Invalid profile or environment." },
9908
- 404: { description: "Project or connection not found." }
10158
+ 200: jsonResponse("Schema deployment results returned.", "WordpressSchemaDeployResultDto"),
10159
+ 400: errorResponse("Invalid profile or environment."),
10160
+ 404: errorResponse("Project or connection not found.")
9909
10161
  }
9910
10162
  },
9911
10163
  {
@@ -9915,9 +10167,9 @@ var routeCatalog = [
9915
10167
  tags: ["wordpress"],
9916
10168
  parameters: [nameParameter, wordpressEnvQueryParameter],
9917
10169
  responses: {
9918
- 200: { description: "Schema status per page returned." },
9919
- 400: { description: "Invalid environment." },
9920
- 404: { description: "Project or connection not found." }
10170
+ 200: jsonResponse("Schema status per page returned.", "WordpressSchemaStatusResultDto"),
10171
+ 400: errorResponse("Invalid environment."),
10172
+ 404: errorResponse("Project or connection not found.")
9921
10173
  }
9922
10174
  },
9923
10175
  {
@@ -9927,9 +10179,10 @@ var routeCatalog = [
9927
10179
  tags: ["wordpress"],
9928
10180
  parameters: [nameParameter, wordpressEnvQueryParameter],
9929
10181
  responses: {
9930
- 200: { description: "llms.txt returned." },
9931
- 400: { description: "Invalid environment or missing connection." },
9932
- 404: { description: "Project not found." }
10182
+ // Returns raw text/plain content of llms.txt.
10183
+ 200: { description: "llms.txt returned.", content: { "text/plain": { schema: { type: "string" } } } },
10184
+ 400: errorResponse("Invalid environment or missing connection."),
10185
+ 404: errorResponse("Project not found.")
9933
10186
  }
9934
10187
  },
9935
10188
  {
@@ -9954,9 +10207,9 @@ var routeCatalog = [
9954
10207
  }
9955
10208
  },
9956
10209
  responses: {
9957
- 200: { description: "Manual llms.txt instructions returned." },
9958
- 400: { description: "Invalid llms.txt request." },
9959
- 404: { description: "Project or connection not found." }
10210
+ 200: jsonResponse("Manual llms.txt instructions returned.", "WordpressManualAssistDto"),
10211
+ 400: errorResponse("Invalid llms.txt request."),
10212
+ 404: errorResponse("Project or connection not found.")
9960
10213
  }
9961
10214
  },
9962
10215
  {
@@ -9966,9 +10219,9 @@ var routeCatalog = [
9966
10219
  tags: ["wordpress"],
9967
10220
  parameters: [nameParameter, wordpressEnvQueryParameter],
9968
10221
  responses: {
9969
- 200: { description: "WordPress audit returned." },
9970
- 400: { description: "Invalid environment or missing connection." },
9971
- 404: { description: "Project not found." }
10222
+ 200: jsonArrayResponse("WordPress audit returned.", "WordpressAuditPageDto"),
10223
+ 400: errorResponse("Invalid environment or missing connection."),
10224
+ 404: errorResponse("Project not found.")
9972
10225
  }
9973
10226
  },
9974
10227
  {
@@ -9978,9 +10231,9 @@ var routeCatalog = [
9978
10231
  tags: ["wordpress"],
9979
10232
  parameters: [nameParameter, wordpressSlugQueryParameter],
9980
10233
  responses: {
9981
- 200: { description: "WordPress diff returned." },
9982
- 400: { description: "Invalid slug or missing staging configuration." },
9983
- 404: { description: "Project, connection, or page not found." }
10234
+ 200: jsonResponse("WordPress diff returned.", "WordpressDiffDto"),
10235
+ 400: errorResponse("Invalid slug or missing staging configuration."),
10236
+ 404: errorResponse("Project, connection, or page not found.")
9984
10237
  }
9985
10238
  },
9986
10239
  {
@@ -9990,9 +10243,10 @@ var routeCatalog = [
9990
10243
  tags: ["wordpress"],
9991
10244
  parameters: [nameParameter],
9992
10245
  responses: {
9993
- 200: { description: "WordPress staging status returned." },
9994
- 400: { description: "WordPress is not configured for this project." },
9995
- 404: { description: "Project not found." }
10246
+ // TODO: Add `WordpressSiteStatusDto` to the schema table (already in contracts).
10247
+ 200: rawJsonResponse("WordPress staging status returned.", looseObjectSchema),
10248
+ 400: errorResponse("WordPress is not configured for this project."),
10249
+ 404: errorResponse("Project not found.")
9996
10250
  }
9997
10251
  },
9998
10252
  {
@@ -10002,9 +10256,9 @@ var routeCatalog = [
10002
10256
  tags: ["wordpress"],
10003
10257
  parameters: [nameParameter],
10004
10258
  responses: {
10005
- 200: { description: "Manual staging push instructions returned." },
10006
- 400: { description: "Missing staging configuration." },
10007
- 404: { description: "Project or connection not found." }
10259
+ 200: jsonResponse("Manual staging push instructions returned.", "WordpressManualAssistDto"),
10260
+ 400: errorResponse("Missing staging configuration."),
10261
+ 404: errorResponse("Project or connection not found.")
10008
10262
  }
10009
10263
  },
10010
10264
  {
@@ -10035,9 +10289,9 @@ var routeCatalog = [
10035
10289
  }
10036
10290
  },
10037
10291
  responses: {
10038
- 200: { description: "Onboarding result with step-by-step status." },
10039
- 400: { description: "Invalid onboarding request." },
10040
- 404: { description: "Project not found." }
10292
+ 200: jsonResponse("Onboarding result with step-by-step status.", "WordpressOnboardResultDto"),
10293
+ 400: errorResponse("Invalid onboarding request."),
10294
+ 404: errorResponse("Project not found.")
10041
10295
  }
10042
10296
  },
10043
10297
  // GA4 routes
@@ -10063,9 +10317,10 @@ var routeCatalog = [
10063
10317
  }
10064
10318
  },
10065
10319
  responses: {
10066
- 200: { description: "GA4 connection established." },
10067
- 400: { description: "Invalid GA4 connection request." },
10068
- 404: { description: "Project not found." }
10320
+ // TODO: Add `GaConnectResponse` Zod schema in contracts.
10321
+ 200: rawJsonResponse("GA4 connection established.", looseObjectSchema),
10322
+ 400: errorResponse("Invalid GA4 connection request."),
10323
+ 404: errorResponse("Project not found.")
10069
10324
  }
10070
10325
  },
10071
10326
  {
@@ -10076,7 +10331,7 @@ var routeCatalog = [
10076
10331
  parameters: [nameParameter],
10077
10332
  responses: {
10078
10333
  204: { description: "GA4 connection deleted." },
10079
- 404: { description: "Project or connection not found." }
10334
+ 404: errorResponse("Project or connection not found.")
10080
10335
  }
10081
10336
  },
10082
10337
  {
@@ -10086,8 +10341,8 @@ var routeCatalog = [
10086
10341
  tags: ["ga4"],
10087
10342
  parameters: [nameParameter],
10088
10343
  responses: {
10089
- 200: { description: "GA4 status returned." },
10090
- 404: { description: "Project not found." }
10344
+ 200: jsonResponse("GA4 status returned.", "GA4StatusDto"),
10345
+ 404: errorResponse("Project not found.")
10091
10346
  }
10092
10347
  },
10093
10348
  {
@@ -10110,9 +10365,9 @@ var routeCatalog = [
10110
10365
  }
10111
10366
  },
10112
10367
  responses: {
10113
- 200: { description: "GA4 sync completed." },
10114
- 400: { description: "GA4 is not connected." },
10115
- 404: { description: "Project not found." }
10368
+ 200: jsonResponse("GA4 sync completed.", "GA4SyncResponseDto"),
10369
+ 400: errorResponse("GA4 is not connected."),
10370
+ 404: errorResponse("Project not found.")
10116
10371
  }
10117
10372
  },
10118
10373
  {
@@ -10122,9 +10377,10 @@ var routeCatalog = [
10122
10377
  tags: ["ga4"],
10123
10378
  parameters: [nameParameter, limitQueryParameter, analyticsWindowParameter],
10124
10379
  responses: {
10125
- 200: { description: "GA4 traffic data returned." },
10126
- 400: { description: "GA4 is not connected." },
10127
- 404: { description: "Project not found." }
10380
+ // TODO: Add `GaTrafficResponse` Zod schema in contracts.
10381
+ 200: rawJsonResponse("GA4 traffic data returned.", looseObjectSchema),
10382
+ 400: errorResponse("GA4 is not connected."),
10383
+ 404: errorResponse("Project not found.")
10128
10384
  }
10129
10385
  },
10130
10386
  {
@@ -10134,9 +10390,9 @@ var routeCatalog = [
10134
10390
  tags: ["ga4"],
10135
10391
  parameters: [nameParameter, analyticsWindowParameter],
10136
10392
  responses: {
10137
- 200: { description: "AI referral history returned." },
10138
- 400: { description: "GA4 is not connected." },
10139
- 404: { description: "Project not found." }
10393
+ 200: jsonArrayResponse("AI referral history returned.", "GA4AiReferralHistoryEntry"),
10394
+ 400: errorResponse("GA4 is not connected."),
10395
+ 404: errorResponse("Project not found.")
10140
10396
  }
10141
10397
  },
10142
10398
  {
@@ -10146,9 +10402,9 @@ var routeCatalog = [
10146
10402
  tags: ["ga4"],
10147
10403
  parameters: [nameParameter, analyticsWindowParameter],
10148
10404
  responses: {
10149
- 200: { description: "Social referral history returned." },
10150
- 400: { description: "GA4 is not connected." },
10151
- 404: { description: "Project not found." }
10405
+ 200: jsonArrayResponse("Social referral history returned.", "GA4SocialReferralHistoryEntry"),
10406
+ 400: errorResponse("GA4 is not connected."),
10407
+ 404: errorResponse("Project not found.")
10152
10408
  }
10153
10409
  },
10154
10410
  {
@@ -10158,9 +10414,10 @@ var routeCatalog = [
10158
10414
  tags: ["ga4"],
10159
10415
  parameters: [nameParameter],
10160
10416
  responses: {
10161
- 200: { description: "Social referral trend returned." },
10162
- 400: { description: "GA4 is not connected." },
10163
- 404: { description: "Project not found." }
10417
+ // TODO: Add `GaSocialReferralTrendResponse` Zod schema in contracts.
10418
+ 200: rawJsonResponse("Social referral trend returned.", looseObjectSchema),
10419
+ 400: errorResponse("GA4 is not connected."),
10420
+ 404: errorResponse("Project not found.")
10164
10421
  }
10165
10422
  },
10166
10423
  {
@@ -10170,9 +10427,10 @@ var routeCatalog = [
10170
10427
  tags: ["ga4"],
10171
10428
  parameters: [nameParameter],
10172
10429
  responses: {
10173
- 200: { description: "Attribution trend returned." },
10174
- 400: { description: "GA4 is not connected." },
10175
- 404: { description: "Project not found." }
10430
+ // TODO: Add `GaAttributionTrendResponse` Zod schema in contracts.
10431
+ 200: rawJsonResponse("Attribution trend returned.", looseObjectSchema),
10432
+ 400: errorResponse("GA4 is not connected."),
10433
+ 404: errorResponse("Project not found.")
10176
10434
  }
10177
10435
  },
10178
10436
  {
@@ -10182,9 +10440,9 @@ var routeCatalog = [
10182
10440
  tags: ["ga4"],
10183
10441
  parameters: [nameParameter, analyticsWindowParameter],
10184
10442
  responses: {
10185
- 200: { description: "Session history returned." },
10186
- 400: { description: "GA4 is not connected." },
10187
- 404: { description: "Project not found." }
10443
+ 200: jsonArrayResponse("Session history returned.", "GA4SessionHistoryEntry"),
10444
+ 400: errorResponse("GA4 is not connected."),
10445
+ 404: errorResponse("Project not found.")
10188
10446
  }
10189
10447
  },
10190
10448
  {
@@ -10194,9 +10452,10 @@ var routeCatalog = [
10194
10452
  tags: ["ga4"],
10195
10453
  parameters: [nameParameter],
10196
10454
  responses: {
10197
- 200: { description: "GA4 coverage data returned." },
10198
- 400: { description: "GA4 is not connected." },
10199
- 404: { description: "Project not found." }
10455
+ // TODO: Add `GaCoverageResponse` Zod schema in contracts.
10456
+ 200: rawJsonResponse("GA4 coverage data returned.", looseObjectSchema),
10457
+ 400: errorResponse("GA4 is not connected."),
10458
+ 404: errorResponse("Project not found.")
10200
10459
  }
10201
10460
  },
10202
10461
  // Intelligence
@@ -10211,8 +10470,9 @@ var routeCatalog = [
10211
10470
  { name: "runId", in: "query", description: "Filter by run ID.", schema: stringSchema }
10212
10471
  ],
10213
10472
  responses: {
10214
- 200: { description: "Insights returned." },
10215
- 404: { description: "Project not found." }
10473
+ // TODO: Add `InsightDto` Zod schema in contracts.
10474
+ 200: rawJsonResponse("Insights returned.", { type: "array", items: looseObjectSchema }),
10475
+ 404: errorResponse("Project not found.")
10216
10476
  }
10217
10477
  },
10218
10478
  {
@@ -10225,8 +10485,9 @@ var routeCatalog = [
10225
10485
  { name: "id", in: "path", required: true, description: "Insight ID.", schema: stringSchema }
10226
10486
  ],
10227
10487
  responses: {
10228
- 200: { description: "Insight returned." },
10229
- 404: { description: "Insight not found." }
10488
+ // TODO: Add `InsightDto` Zod schema in contracts.
10489
+ 200: rawJsonResponse("Insight returned.", looseObjectSchema),
10490
+ 404: errorResponse("Insight not found.")
10230
10491
  }
10231
10492
  },
10232
10493
  {
@@ -10239,8 +10500,9 @@ var routeCatalog = [
10239
10500
  { name: "id", in: "path", required: true, description: "Insight ID.", schema: stringSchema }
10240
10501
  ],
10241
10502
  responses: {
10242
- 200: { description: "Insight dismissed." },
10243
- 404: { description: "Insight not found." }
10503
+ // TODO: Add `InsightDto` Zod schema in contracts.
10504
+ 200: rawJsonResponse("Insight dismissed.", looseObjectSchema),
10505
+ 404: errorResponse("Insight not found.")
10244
10506
  }
10245
10507
  },
10246
10508
  {
@@ -10251,8 +10513,8 @@ var routeCatalog = [
10251
10513
  description: "Bundles every section the canonry-report HTML output needs (executive summary, client summary, agency diagnostics, action plan, citation scorecard, competitor landscape \u2014 citation + mention landscapes, AI citation sources, GSC, GA4, social/AI referrals, indexing health, citations trend, insights, and recommended next steps) into a single canonical JSON payload. Backs `canonry report <project>` and MCP report reads.",
10252
10514
  parameters: [nameParameter],
10253
10515
  responses: {
10254
- 200: { description: "Report returned." },
10255
- 404: { description: "Project not found." }
10516
+ 200: jsonResponse("Report returned.", "ProjectReportDto"),
10517
+ 404: errorResponse("Project not found.")
10256
10518
  }
10257
10519
  },
10258
10520
  {
@@ -10263,8 +10525,8 @@ var routeCatalog = [
10263
10525
  description: "Server-rendered self-contained HTML version of the project report. Same data as `/projects/{name}/report` (JSON), rendered through the canonry HTML report renderer in agency or client mode. Returns `text/html` with `Content-Disposition: attachment` so browsers download it as `canonry-report-<project>-<audience>-YYYY-MM-DD.html`. Open in a browser and Print \u2192 Save as PDF for a PDF copy.",
10264
10526
  parameters: [nameParameter, reportAudienceQueryParameter],
10265
10527
  responses: {
10266
- 200: { description: "HTML report returned." },
10267
- 404: { description: "Project not found." }
10528
+ 200: { description: "HTML report returned.", content: { "text/html": { schema: { type: "string" } } } },
10529
+ 404: errorResponse("Project not found.")
10268
10530
  }
10269
10531
  },
10270
10532
  {
@@ -10275,8 +10537,9 @@ var routeCatalog = [
10275
10537
  tags: ["intelligence"],
10276
10538
  parameters: [nameParameter],
10277
10539
  responses: {
10278
- 200: { description: "Health snapshot or no-data sentinel returned." },
10279
- 404: { description: "Project not found." }
10540
+ // TODO: Add `HealthSnapshotDto` Zod schema in contracts.
10541
+ 200: rawJsonResponse("Health snapshot or no-data sentinel returned.", looseObjectSchema),
10542
+ 404: errorResponse("Project not found.")
10280
10543
  }
10281
10544
  },
10282
10545
  {
@@ -10289,8 +10552,9 @@ var routeCatalog = [
10289
10552
  { name: "limit", in: "query", description: "Max results.", schema: stringSchema }
10290
10553
  ],
10291
10554
  responses: {
10292
- 200: { description: "Health history returned." },
10293
- 404: { description: "Project not found." }
10555
+ // TODO: Add `HealthSnapshotDto` Zod schema in contracts.
10556
+ 200: rawJsonResponse("Health history returned.", { type: "array", items: looseObjectSchema }),
10557
+ 404: errorResponse("Project not found.")
10294
10558
  }
10295
10559
  },
10296
10560
  {
@@ -10301,8 +10565,8 @@ var routeCatalog = [
10301
10565
  tags: ["intelligence"],
10302
10566
  parameters: [nameParameter],
10303
10567
  responses: {
10304
- 200: { description: "Citation visibility report or no-data sentinel returned." },
10305
- 404: { description: "Project not found." }
10568
+ 200: jsonResponse("Citation visibility report or no-data sentinel returned.", "CitationVisibilityResponse"),
10569
+ 404: errorResponse("Project not found.")
10306
10570
  }
10307
10571
  },
10308
10572
  // Content opportunity engine
@@ -10318,9 +10582,9 @@ var routeCatalog = [
10318
10582
  { name: "include-in-progress", in: "query", description: "Include rows with in-flight tracked actions.", schema: stringSchema }
10319
10583
  ],
10320
10584
  responses: {
10321
- 200: { description: "Targets returned." },
10322
- 400: { description: "Invalid limit." },
10323
- 404: { description: "Project not found." }
10585
+ 200: jsonResponse("Targets returned.", "ContentTargetsResponseDto"),
10586
+ 400: errorResponse("Invalid limit."),
10587
+ 404: errorResponse("Project not found.")
10324
10588
  }
10325
10589
  },
10326
10590
  {
@@ -10331,8 +10595,8 @@ var routeCatalog = [
10331
10595
  tags: ["content"],
10332
10596
  parameters: [nameParameter],
10333
10597
  responses: {
10334
- 200: { description: "Sources returned." },
10335
- 404: { description: "Project not found." }
10598
+ 200: jsonResponse("Sources returned.", "ContentSourcesResponseDto"),
10599
+ 404: errorResponse("Project not found.")
10336
10600
  }
10337
10601
  },
10338
10602
  {
@@ -10343,8 +10607,8 @@ var routeCatalog = [
10343
10607
  tags: ["content"],
10344
10608
  parameters: [nameParameter],
10345
10609
  responses: {
10346
- 200: { description: "Gaps returned." },
10347
- 404: { description: "Project not found." }
10610
+ 200: jsonResponse("Gaps returned.", "ContentGapsResponseDto"),
10611
+ 404: errorResponse("Project not found.")
10348
10612
  }
10349
10613
  },
10350
10614
  {
@@ -10355,8 +10619,9 @@ var routeCatalog = [
10355
10619
  tags: ["intelligence"],
10356
10620
  parameters: [nameParameter],
10357
10621
  responses: {
10358
- 200: { description: "Overview returned." },
10359
- 404: { description: "Project not found." }
10622
+ // TODO: Add `ProjectOverviewDto` Zod schema in contracts.
10623
+ 200: rawJsonResponse("Overview returned.", looseObjectSchema),
10624
+ 404: errorResponse("Project not found.")
10360
10625
  }
10361
10626
  },
10362
10627
  {
@@ -10371,9 +10636,10 @@ var routeCatalog = [
10371
10636
  { name: "limit", in: "query", description: "Max combined hits (1-50, default 25).", schema: stringSchema }
10372
10637
  ],
10373
10638
  responses: {
10374
- 200: { description: "Search hits returned." },
10375
- 400: { description: "Query string missing or too short." },
10376
- 404: { description: "Project not found." }
10639
+ // TODO: Add `ProjectSearchResponseDto` Zod schema in contracts (projectSearchResponseSchema exists).
10640
+ 200: rawJsonResponse("Search hits returned.", looseObjectSchema),
10641
+ 400: errorResponse("Query string missing or too short."),
10642
+ 404: errorResponse("Project not found.")
10377
10643
  }
10378
10644
  },
10379
10645
  {
@@ -10391,7 +10657,7 @@ var routeCatalog = [
10391
10657
  }
10392
10658
  ],
10393
10659
  responses: {
10394
- 200: { description: "Doctor report returned." }
10660
+ 200: jsonResponse("Doctor report returned.", "DoctorReportDto")
10395
10661
  }
10396
10662
  },
10397
10663
  {
@@ -10410,8 +10676,8 @@ var routeCatalog = [
10410
10676
  }
10411
10677
  ],
10412
10678
  responses: {
10413
- 200: { description: "Doctor report returned." },
10414
- 404: { description: "Project not found." }
10679
+ 200: jsonResponse("Doctor report returned.", "DoctorReportDto"),
10680
+ 404: errorResponse("Project not found.")
10415
10681
  }
10416
10682
  },
10417
10683
  {
@@ -10421,8 +10687,8 @@ var routeCatalog = [
10421
10687
  description: "Reports whether @duckdb/node-api is installed in the local plugin dir. Returns MISSING_DEPENDENCY (422) on deployments that cannot host the plugin (e.g. the cloud API).",
10422
10688
  tags: ["backlinks"],
10423
10689
  responses: {
10424
- 200: { description: "Install status returned." },
10425
- 422: { description: "Backlinks feature is not available on this deployment." }
10690
+ 200: jsonResponse("Install status returned.", "BacklinksInstallStatusDto"),
10691
+ 422: errorResponse("Backlinks feature is not available on this deployment.")
10426
10692
  }
10427
10693
  },
10428
10694
  {
@@ -10432,8 +10698,8 @@ var routeCatalog = [
10432
10698
  description: "Idempotently installs DuckDB into the canonry plugin dir. Returns MISSING_DEPENDENCY (422) when the host cannot perform the install.",
10433
10699
  tags: ["backlinks"],
10434
10700
  responses: {
10435
- 200: { description: "Installed (or already present)." },
10436
- 422: { description: "Backlinks feature is not available on this deployment." }
10701
+ 200: jsonResponse("Installed (or already present).", "BacklinksInstallResultDto"),
10702
+ 422: errorResponse("Backlinks feature is not available on this deployment.")
10437
10703
  }
10438
10704
  },
10439
10705
  {
@@ -10456,10 +10722,10 @@ var routeCatalog = [
10456
10722
  }
10457
10723
  },
10458
10724
  responses: {
10459
- 200: { description: "Existing in-flight sync returned." },
10460
- 201: { description: "Sync queued." },
10461
- 400: { description: "Invalid release id." },
10462
- 422: { description: "Backlinks feature is not available on this deployment." }
10725
+ 200: jsonResponse("Existing in-flight sync returned.", "CcReleaseSyncDto"),
10726
+ 201: jsonResponse("Sync queued.", "CcReleaseSyncDto"),
10727
+ 400: errorResponse("Invalid release id."),
10728
+ 422: errorResponse("Backlinks feature is not available on this deployment.")
10463
10729
  }
10464
10730
  },
10465
10731
  {
@@ -10469,7 +10735,7 @@ var routeCatalog = [
10469
10735
  description: "Returns syncs ordered by updatedAt DESC \u2014 re-queued rows surface ahead of untouched newer rows.",
10470
10736
  tags: ["backlinks"],
10471
10737
  responses: {
10472
- 200: { description: "Sync history returned." }
10738
+ 200: jsonArrayResponse("Sync history returned.", "CcReleaseSyncDto")
10473
10739
  }
10474
10740
  },
10475
10741
  {
@@ -10478,7 +10744,10 @@ var routeCatalog = [
10478
10744
  summary: "Get the most recently-updated Common Crawl release sync",
10479
10745
  tags: ["backlinks"],
10480
10746
  responses: {
10481
- 200: { description: "Latest sync returned, or null when no sync exists." }
10747
+ // Returns CcReleaseSyncDto | null
10748
+ 200: rawJsonResponse("Latest sync returned, or null when no sync exists.", {
10749
+ oneOf: [{ $ref: "#/components/schemas/CcReleaseSyncDto" }, { type: "null" }]
10750
+ })
10482
10751
  }
10483
10752
  },
10484
10753
  {
@@ -10487,7 +10756,7 @@ var routeCatalog = [
10487
10756
  summary: "List cached Common Crawl releases on the local filesystem",
10488
10757
  tags: ["backlinks"],
10489
10758
  responses: {
10490
- 200: { description: "Cached release metadata returned." }
10759
+ 200: jsonArrayResponse("Cached release metadata returned.", "CcCachedRelease")
10491
10760
  }
10492
10761
  },
10493
10762
  {
@@ -10497,8 +10766,10 @@ var routeCatalog = [
10497
10766
  description: "Probes Common Crawl by HEAD-checking quarterly release slugs and returns the newest one published. The local server caches the result for ~5 minutes so repeated calls do not hammer Common Crawl.",
10498
10767
  tags: ["backlinks"],
10499
10768
  responses: {
10500
- 200: { description: "Latest available release, or null when no candidate slug responded." },
10501
- 422: { description: "Backlinks feature is not available on this deployment." }
10769
+ 200: rawJsonResponse("Latest available release, or null when no candidate slug responded.", {
10770
+ oneOf: [{ $ref: "#/components/schemas/CcAvailableRelease" }, { type: "null" }]
10771
+ }),
10772
+ 422: errorResponse("Backlinks feature is not available on this deployment.")
10502
10773
  }
10503
10774
  },
10504
10775
  {
@@ -10516,9 +10787,10 @@ var routeCatalog = [
10516
10787
  }
10517
10788
  ],
10518
10789
  responses: {
10519
- 200: { description: "Cache pruned." },
10520
- 400: { description: "Invalid release id." },
10521
- 422: { description: "Backlinks feature is not available on this deployment." }
10790
+ // TODO: Add `BacklinksCachePruneResultDto` Zod schema in contracts.
10791
+ 200: rawJsonResponse("Cache pruned.", looseObjectSchema),
10792
+ 400: errorResponse("Invalid release id."),
10793
+ 422: errorResponse("Backlinks feature is not available on this deployment.")
10522
10794
  }
10523
10795
  },
10524
10796
  {
@@ -10542,10 +10814,10 @@ var routeCatalog = [
10542
10814
  }
10543
10815
  },
10544
10816
  responses: {
10545
- 201: { description: "Extract run queued." },
10546
- 400: { description: "Invalid release id." },
10547
- 404: { description: "Project not found." },
10548
- 422: { description: "Backlinks feature is not available on this deployment." }
10817
+ 201: jsonResponse("Extract run queued.", "RunDto"),
10818
+ 400: errorResponse("Invalid release id."),
10819
+ 404: errorResponse("Project not found."),
10820
+ 422: errorResponse("Backlinks feature is not available on this deployment.")
10549
10821
  }
10550
10822
  },
10551
10823
  {
@@ -10558,8 +10830,10 @@ var routeCatalog = [
10558
10830
  { name: "release", in: "query", description: "Release id filter.", schema: stringSchema }
10559
10831
  ],
10560
10832
  responses: {
10561
- 200: { description: "Summary returned, or null when no backlinks exist." },
10562
- 404: { description: "Project not found." }
10833
+ 200: rawJsonResponse("Summary returned, or null when no backlinks exist.", {
10834
+ oneOf: [{ $ref: "#/components/schemas/BacklinkSummaryDto" }, { type: "null" }]
10835
+ }),
10836
+ 404: errorResponse("Project not found.")
10563
10837
  }
10564
10838
  },
10565
10839
  {
@@ -10574,8 +10848,8 @@ var routeCatalog = [
10574
10848
  { name: "offset", in: "query", description: "Pagination offset.", schema: stringSchema }
10575
10849
  ],
10576
10850
  responses: {
10577
- 200: { description: "Domain list returned." },
10578
- 404: { description: "Project not found." }
10851
+ 200: jsonResponse("Domain list returned.", "BacklinkListResponse"),
10852
+ 404: errorResponse("Project not found.")
10579
10853
  }
10580
10854
  },
10581
10855
  {
@@ -10585,8 +10859,8 @@ var routeCatalog = [
10585
10859
  tags: ["backlinks"],
10586
10860
  parameters: [nameParameter],
10587
10861
  responses: {
10588
- 200: { description: "History returned oldest-first by queriedAt." },
10589
- 404: { description: "Project not found." }
10862
+ 200: jsonArrayResponse("History returned oldest-first by queriedAt.", "BacklinkHistoryEntry"),
10863
+ 404: errorResponse("Project not found.")
10590
10864
  }
10591
10865
  },
10592
10866
  {
@@ -10615,9 +10889,9 @@ var routeCatalog = [
10615
10889
  }
10616
10890
  },
10617
10891
  responses: {
10618
- 200: { description: "Traffic source DTO returned." },
10619
- 400: { description: "Invalid Cloud Run connection request." },
10620
- 404: { description: "Project not found." }
10892
+ 200: jsonResponse("Traffic source DTO returned.", "TrafficSourceDto"),
10893
+ 400: errorResponse("Invalid Cloud Run connection request."),
10894
+ 404: errorResponse("Project not found.")
10621
10895
  }
10622
10896
  },
10623
10897
  {
@@ -10645,10 +10919,10 @@ var routeCatalog = [
10645
10919
  }
10646
10920
  },
10647
10921
  responses: {
10648
- 200: { description: "Traffic source DTO returned." },
10649
- 400: { description: "Invalid WordPress connection request." },
10650
- 404: { description: "Project not found." },
10651
- 502: { description: "WordPress plugin endpoint probe failed (bad credentials, unreachable host, etc.)." }
10922
+ 200: jsonResponse("Traffic source DTO returned.", "TrafficSourceDto"),
10923
+ 400: errorResponse("Invalid WordPress connection request."),
10924
+ 404: errorResponse("Project not found."),
10925
+ 502: errorResponse("WordPress plugin endpoint probe failed (bad credentials, unreachable host, etc.).")
10652
10926
  }
10653
10927
  },
10654
10928
  {
@@ -10677,10 +10951,10 @@ var routeCatalog = [
10677
10951
  }
10678
10952
  },
10679
10953
  responses: {
10680
- 200: { description: "Traffic source DTO returned." },
10681
- 400: { description: "Invalid Vercel connection request." },
10682
- 404: { description: "Project not found." },
10683
- 502: { description: "Vercel request-logs endpoint probe failed (bad token, wrong project / team id, unreachable host, etc.)." }
10954
+ 200: jsonResponse("Traffic source DTO returned.", "TrafficSourceDto"),
10955
+ 400: errorResponse("Invalid Vercel connection request."),
10956
+ 404: errorResponse("Project not found."),
10957
+ 502: errorResponse("Vercel request-logs endpoint probe failed (bad token, wrong project / team id, unreachable host, etc.).")
10684
10958
  }
10685
10959
  },
10686
10960
  {
@@ -10707,10 +10981,10 @@ var routeCatalog = [
10707
10981
  }
10708
10982
  },
10709
10983
  responses: {
10710
- 200: { description: "Sync summary returned." },
10711
- 400: { description: "Invalid sync request or missing credentials." },
10712
- 404: { description: "Project or traffic source not found." },
10713
- 502: { description: "Upstream Cloud Run pull or auth-token resolution failed." }
10984
+ 200: jsonResponse("Sync summary returned.", "TrafficSyncResponse"),
10985
+ 400: errorResponse("Invalid sync request or missing credentials."),
10986
+ 404: errorResponse("Project or traffic source not found."),
10987
+ 502: errorResponse("Upstream Cloud Run pull or auth-token resolution failed.")
10714
10988
  }
10715
10989
  },
10716
10990
  {
@@ -10737,9 +11011,9 @@ var routeCatalog = [
10737
11011
  }
10738
11012
  },
10739
11013
  responses: {
10740
- 200: { description: "Backfill submitted; poll the returned runId for completion." },
10741
- 400: { description: "Invalid backfill request or missing credentials." },
10742
- 404: { description: "Project or traffic source not found." }
11014
+ 200: jsonResponse("Backfill submitted; poll the returned runId for completion.", "TrafficBackfillResponse"),
11015
+ 400: errorResponse("Invalid backfill request or missing credentials."),
11016
+ 404: errorResponse("Project or traffic source not found.")
10743
11017
  }
10744
11018
  },
10745
11019
  {
@@ -10749,8 +11023,8 @@ var routeCatalog = [
10749
11023
  tags: ["traffic"],
10750
11024
  parameters: [nameParameter],
10751
11025
  responses: {
10752
- 200: { description: "Source list returned." },
10753
- 404: { description: "Project not found." }
11026
+ 200: jsonResponse("Source list returned.", "TrafficSourceListResponse"),
11027
+ 404: errorResponse("Project not found.")
10754
11028
  }
10755
11029
  },
10756
11030
  {
@@ -10761,8 +11035,8 @@ var routeCatalog = [
10761
11035
  tags: ["traffic"],
10762
11036
  parameters: [nameParameter],
10763
11037
  responses: {
10764
- 200: { description: "Status returned." },
10765
- 404: { description: "Project not found." }
11038
+ 200: jsonResponse("Status returned.", "TrafficStatusResponse"),
11039
+ 404: errorResponse("Project not found.")
10766
11040
  }
10767
11041
  },
10768
11042
  {
@@ -10775,8 +11049,8 @@ var routeCatalog = [
10775
11049
  { name: "id", in: "path", required: true, description: "Traffic source ID.", schema: stringSchema }
10776
11050
  ],
10777
11051
  responses: {
10778
- 200: { description: "Source detail returned." },
10779
- 404: { description: "Project or source not found." }
11052
+ 200: jsonResponse("Source detail returned.", "TrafficSourceDetailDto"),
11053
+ 404: errorResponse("Project or source not found.")
10780
11054
  }
10781
11055
  },
10782
11056
  {
@@ -10794,9 +11068,9 @@ var routeCatalog = [
10794
11068
  { name: "sourceId", in: "query", description: "Restrict to a single traffic source.", schema: stringSchema }
10795
11069
  ],
10796
11070
  responses: {
10797
- 200: { description: "Events returned with windowed totals." },
10798
- 400: { description: "Invalid query parameters." },
10799
- 404: { description: "Project not found." }
11071
+ 200: jsonResponse("Events returned with windowed totals.", "TrafficEventsResponse"),
11072
+ 400: errorResponse("Invalid query parameters."),
11073
+ 404: errorResponse("Project not found.")
10800
11074
  }
10801
11075
  },
10802
11076
  {
@@ -10827,10 +11101,11 @@ var routeCatalog = [
10827
11101
  }
10828
11102
  },
10829
11103
  responses: {
10830
- 200: { description: "An in-flight session with the same project + ICP was reused; returns { runId, sessionId, status, consolidated: true }. The request's dedupThreshold / maxProbes are ignored." },
10831
- 201: { description: "New discovery session enqueued; returns { runId, sessionId, status, consolidated: false }." },
10832
- 400: { description: "Missing or invalid ICP / parameters." },
10833
- 404: { description: "Project not found." }
11104
+ // TODO: Add `DiscoveryRunResponse` Zod schema in contracts (`{ runId, sessionId, status, consolidated }`).
11105
+ 200: rawJsonResponse("An in-flight session with the same project + ICP was reused; returns { runId, sessionId, status, consolidated: true }. The request's dedupThreshold / maxProbes are ignored.", looseObjectSchema),
11106
+ 201: rawJsonResponse("New discovery session enqueued; returns { runId, sessionId, status, consolidated: false }.", looseObjectSchema),
11107
+ 400: errorResponse("Missing or invalid ICP / parameters."),
11108
+ 404: errorResponse("Project not found.")
10834
11109
  }
10835
11110
  },
10836
11111
  {
@@ -10844,8 +11119,8 @@ var routeCatalog = [
10844
11119
  { name: "limit", in: "query", description: "Max sessions returned. Default 50.", schema: stringSchema }
10845
11120
  ],
10846
11121
  responses: {
10847
- 200: { description: "Sessions returned." },
10848
- 404: { description: "Project not found." }
11122
+ 200: jsonArrayResponse("Sessions returned.", "DiscoverySessionDto"),
11123
+ 404: errorResponse("Project not found.")
10849
11124
  }
10850
11125
  },
10851
11126
  {
@@ -10859,8 +11134,8 @@ var routeCatalog = [
10859
11134
  { name: "id", in: "path", required: true, description: "Discovery session ID.", schema: stringSchema }
10860
11135
  ],
10861
11136
  responses: {
10862
- 200: { description: "Session detail returned." },
10863
- 404: { description: "Project or session not found." }
11137
+ 200: jsonResponse("Session detail returned.", "DiscoverySessionDetailDto"),
11138
+ 404: errorResponse("Project or session not found.")
10864
11139
  }
10865
11140
  },
10866
11141
  {
@@ -10874,8 +11149,8 @@ var routeCatalog = [
10874
11149
  { name: "id", in: "path", required: true, description: "Discovery session ID.", schema: stringSchema }
10875
11150
  ],
10876
11151
  responses: {
10877
- 200: { description: "Promote preview returned." },
10878
- 404: { description: "Project or session not found." }
11152
+ 200: jsonResponse("Promote preview returned.", "DiscoveryPromotePreview"),
11153
+ 404: errorResponse("Project or session not found.")
10879
11154
  }
10880
11155
  },
10881
11156
  {
@@ -10918,9 +11193,9 @@ var routeCatalog = [
10918
11193
  }
10919
11194
  },
10920
11195
  responses: {
10921
- 200: { description: "Promotion applied; returns promoted + skipped query/competitor lists." },
10922
- 400: { description: "Session is not completed, or invalid request body." },
10923
- 404: { description: "Project or session not found." }
11196
+ 200: jsonResponse("Promotion applied; returns promoted + skipped query/competitor lists.", "DiscoveryPromoteResult"),
11197
+ 400: errorResponse("Session is not completed, or invalid request body."),
11198
+ 404: errorResponse("Project or session not found.")
10924
11199
  }
10925
11200
  }
10926
11201
  ];
@@ -10933,8 +11208,9 @@ var canonryLocalRouteCatalog = [
10933
11208
  tags: ["agent"],
10934
11209
  parameters: [nameParameter],
10935
11210
  responses: {
10936
- 200: { description: "Transcript returned." },
10937
- 404: { description: "Project not found." }
11211
+ // TODO: Add `AgentTranscriptDto` Zod schema in contracts.
11212
+ 200: rawJsonResponse("Transcript returned.", looseObjectSchema),
11213
+ 404: errorResponse("Project not found.")
10938
11214
  }
10939
11215
  },
10940
11216
  {
@@ -10945,8 +11221,9 @@ var canonryLocalRouteCatalog = [
10945
11221
  tags: ["agent"],
10946
11222
  parameters: [nameParameter],
10947
11223
  responses: {
10948
- 200: { description: "Session reset." },
10949
- 404: { description: "Project not found." }
11224
+ // Returns { status: 'reset' } sentinel.
11225
+ 200: rawJsonResponse("Session reset.", { type: "object", properties: { status: { type: "string", enum: ["reset"] } } }),
11226
+ 404: errorResponse("Project not found.")
10950
11227
  }
10951
11228
  },
10952
11229
  {
@@ -10957,8 +11234,9 @@ var canonryLocalRouteCatalog = [
10957
11234
  tags: ["agent"],
10958
11235
  parameters: [nameParameter],
10959
11236
  responses: {
10960
- 200: { description: "Memory entries returned." },
10961
- 404: { description: "Project not found." }
11237
+ // TODO: Add `AgentMemoryListResponse` Zod schema in contracts.
11238
+ 200: rawJsonResponse("Memory entries returned.", looseObjectSchema),
11239
+ 404: errorResponse("Project not found.")
10962
11240
  }
10963
11241
  },
10964
11242
  {
@@ -10984,9 +11262,10 @@ var canonryLocalRouteCatalog = [
10984
11262
  }
10985
11263
  },
10986
11264
  responses: {
10987
- 200: { description: "Entry upserted." },
10988
- 400: { description: "Validation failed (key length, value size, reserved prefix)." },
10989
- 404: { description: "Project not found." }
11265
+ // TODO: Add `AgentMemoryEntryDto` Zod schema in contracts.
11266
+ 200: rawJsonResponse("Entry upserted.", looseObjectSchema),
11267
+ 400: errorResponse("Validation failed (key length, value size, reserved prefix)."),
11268
+ 404: errorResponse("Project not found.")
10990
11269
  }
10991
11270
  },
10992
11271
  {
@@ -11011,9 +11290,10 @@ var canonryLocalRouteCatalog = [
11011
11290
  }
11012
11291
  },
11013
11292
  responses: {
11014
- 200: { description: "Entry removed or already absent." },
11015
- 400: { description: "Validation failed (reserved prefix)." },
11016
- 404: { description: "Project not found." }
11293
+ // Returns { status: 'removed' | 'missing' } sentinel.
11294
+ 200: rawJsonResponse("Entry removed or already absent.", { type: "object", properties: { status: { type: "string", enum: ["removed", "missing"] } } }),
11295
+ 400: errorResponse("Validation failed (reserved prefix)."),
11296
+ 404: errorResponse("Project not found.")
11017
11297
  }
11018
11298
  },
11019
11299
  {
@@ -11024,8 +11304,8 @@ var canonryLocalRouteCatalog = [
11024
11304
  tags: ["agent"],
11025
11305
  parameters: [nameParameter],
11026
11306
  responses: {
11027
- 200: { description: "Providers returned." },
11028
- 404: { description: "Project not found." }
11307
+ 200: jsonResponse("Providers returned.", "AgentProvidersResponseDto"),
11308
+ 404: errorResponse("Project not found.")
11029
11309
  }
11030
11310
  },
11031
11311
  {
@@ -11064,10 +11344,11 @@ var canonryLocalRouteCatalog = [
11064
11344
  }
11065
11345
  },
11066
11346
  responses: {
11067
- 200: { description: "SSE stream of AgentEvent frames." },
11068
- 400: { description: "Missing or empty prompt." },
11069
- 404: { description: "Project not found." },
11070
- 409: { description: "Another Aero turn is already in flight." }
11347
+ // Returns text/event-stream codegen consumers should treat as a stream.
11348
+ 200: { description: "SSE stream of AgentEvent frames.", content: { "text/event-stream": { schema: { type: "string" } } } },
11349
+ 400: errorResponse("Missing or empty prompt."),
11350
+ 404: errorResponse("Project not found."),
11351
+ 409: errorResponse("Another Aero turn is already in flight.")
11071
11352
  }
11072
11353
  }
11073
11354
  ];
@@ -11093,8 +11374,14 @@ function buildOpenApiDocument(info = {}) {
11093
11374
  acc[fullPath] = pathItem;
11094
11375
  return acc;
11095
11376
  }, {});
11377
+ const schemas = buildComponentSchemas();
11096
11378
  return {
11097
- openapi: "3.1.0",
11379
+ // OpenAPI 3.0 (not 3.1) so `nullable: true` on emitted schemas is the
11380
+ // canonical nullability marker. `z.toJSONSchema(..., { target: 'openapi-3.0' })`
11381
+ // outputs `nullable: true`; declaring 3.1 would tell consumers (and the
11382
+ // hey-api codegen) to expect 3.1-style `type: ["string", "null"]` instead,
11383
+ // and they'd silently strip the `null` from optional fields.
11384
+ openapi: "3.0.0",
11098
11385
  info: {
11099
11386
  title: info.title ?? "Canonry API",
11100
11387
  version: info.version ?? "0.0.0",
@@ -11113,7 +11400,8 @@ function buildOpenApiDocument(info = {}) {
11113
11400
  scheme: "bearer",
11114
11401
  bearerFormat: "API key"
11115
11402
  }
11116
- }
11403
+ },
11404
+ schemas
11117
11405
  },
11118
11406
  paths
11119
11407
  };
@@ -11288,7 +11576,7 @@ async function telemetryRoutes(app, opts) {
11288
11576
 
11289
11577
  // ../api-routes/src/schedules.ts
11290
11578
  import crypto11 from "crypto";
11291
- import { and as and8, eq as eq16 } from "drizzle-orm";
11579
+ import { and as and11, eq as eq16 } from "drizzle-orm";
11292
11580
  function parseKindParam(raw) {
11293
11581
  if (raw === void 0 || raw === null || raw === "") return SchedulableRunKinds["answer-visibility"];
11294
11582
  const parsed = schedulableRunKindSchema.safeParse(raw);
@@ -11354,7 +11642,7 @@ async function scheduleRoutes(app, opts) {
11354
11642
  }
11355
11643
  const now = (/* @__PURE__ */ new Date()).toISOString();
11356
11644
  const enabledInt = enabled === false ? 0 : 1;
11357
- const existing = app.db.select().from(schedules).where(and8(eq16(schedules.projectId, project.id), eq16(schedules.kind, kind))).get();
11645
+ const existing = app.db.select().from(schedules).where(and11(eq16(schedules.projectId, project.id), eq16(schedules.kind, kind))).get();
11358
11646
  if (existing) {
11359
11647
  app.db.update(schedules).set({
11360
11648
  cronExpr,
@@ -11388,13 +11676,13 @@ async function scheduleRoutes(app, opts) {
11388
11676
  diff: { kind, cronExpr, preset, timezone, providers, sourceId }
11389
11677
  });
11390
11678
  opts.onScheduleUpdated?.("upsert", project.id, kind);
11391
- const schedule = app.db.select().from(schedules).where(and8(eq16(schedules.projectId, project.id), eq16(schedules.kind, kind))).get();
11679
+ const schedule = app.db.select().from(schedules).where(and11(eq16(schedules.projectId, project.id), eq16(schedules.kind, kind))).get();
11392
11680
  return reply.status(existing ? 200 : 201).send(formatSchedule(schedule));
11393
11681
  });
11394
11682
  app.get("/projects/:name/schedule", async (request, reply) => {
11395
11683
  const project = resolveProject(app.db, request.params.name);
11396
11684
  const kind = parseKindParam(request.query?.kind);
11397
- const schedule = app.db.select().from(schedules).where(and8(eq16(schedules.projectId, project.id), eq16(schedules.kind, kind))).get();
11685
+ const schedule = app.db.select().from(schedules).where(and11(eq16(schedules.projectId, project.id), eq16(schedules.kind, kind))).get();
11398
11686
  if (!schedule) {
11399
11687
  throw notFound("Schedule", `${request.params.name} (kind=${kind})`);
11400
11688
  }
@@ -11403,7 +11691,7 @@ async function scheduleRoutes(app, opts) {
11403
11691
  app.delete("/projects/:name/schedule", async (request, reply) => {
11404
11692
  const project = resolveProject(app.db, request.params.name);
11405
11693
  const kind = parseKindParam(request.query?.kind);
11406
- const schedule = app.db.select().from(schedules).where(and8(eq16(schedules.projectId, project.id), eq16(schedules.kind, kind))).get();
11694
+ const schedule = app.db.select().from(schedules).where(and11(eq16(schedules.projectId, project.id), eq16(schedules.kind, kind))).get();
11407
11695
  if (!schedule) {
11408
11696
  throw notFound("Schedule", `${request.params.name} (kind=${kind})`);
11409
11697
  }
@@ -11560,7 +11848,7 @@ function formatNotification(row) {
11560
11848
 
11561
11849
  // ../api-routes/src/google.ts
11562
11850
  import crypto14 from "crypto";
11563
- import { eq as eq18, and as and9, desc as desc8, sql as sql7 } from "drizzle-orm";
11851
+ import { eq as eq18, and as and12, desc as desc8, sql as sql7 } from "drizzle-orm";
11564
11852
 
11565
11853
  // ../integration-google/src/constants.ts
11566
11854
  var GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
@@ -12814,7 +13102,7 @@ async function googleRoutes(app, opts) {
12814
13102
  if (page) conditions.push(sql7`${gscSearchData.page} LIKE ${"%" + page + "%"}`);
12815
13103
  const limitVal = Math.max(parseInt(limit ?? "500", 10) || 0, 1);
12816
13104
  const offsetVal = Math.max(parseInt(offset ?? "0", 10) || 0, 0);
12817
- const rows = app.db.select().from(gscSearchData).where(and9(...conditions)).orderBy(desc8(gscSearchData.date)).limit(limitVal).offset(offsetVal).all();
13105
+ const rows = app.db.select().from(gscSearchData).where(and12(...conditions)).orderBy(desc8(gscSearchData.date)).limit(limitVal).offset(offsetVal).all();
12818
13106
  return rows.map((r) => ({
12819
13107
  date: r.date,
12820
13108
  query: r.query,
@@ -12839,7 +13127,7 @@ async function googleRoutes(app, opts) {
12839
13127
  date: gscSearchData.date,
12840
13128
  clicks: sql7`COALESCE(SUM(${gscSearchData.clicks}), 0)`,
12841
13129
  impressions: sql7`COALESCE(SUM(${gscSearchData.impressions}), 0)`
12842
- }).from(gscSearchData).where(and9(...conditions)).groupBy(gscSearchData.date).orderBy(gscSearchData.date).all();
13130
+ }).from(gscSearchData).where(and12(...conditions)).groupBy(gscSearchData.date).orderBy(gscSearchData.date).all();
12843
13131
  const daily = rows.map((r) => ({
12844
13132
  date: r.date,
12845
13133
  clicks: r.clicks,
@@ -12919,7 +13207,7 @@ async function googleRoutes(app, opts) {
12919
13207
  const { url, limit } = request.query;
12920
13208
  const conditions = [eq18(gscUrlInspections.projectId, project.id)];
12921
13209
  if (url) conditions.push(eq18(gscUrlInspections.url, url));
12922
- const rows = app.db.select().from(gscUrlInspections).where(and9(...conditions)).orderBy(desc8(gscUrlInspections.inspectedAt)).limit(parseInt(limit ?? "100", 10)).all();
13210
+ const rows = app.db.select().from(gscUrlInspections).where(and12(...conditions)).orderBy(desc8(gscUrlInspections.inspectedAt)).limit(parseInt(limit ?? "100", 10)).all();
12923
13211
  return rows.map((r) => ({
12924
13212
  id: r.id,
12925
13213
  url: r.url,
@@ -13271,7 +13559,7 @@ async function googleRoutes(app, opts) {
13271
13559
 
13272
13560
  // ../api-routes/src/bing.ts
13273
13561
  import crypto15 from "crypto";
13274
- import { eq as eq19, and as and10, desc as desc9 } from "drizzle-orm";
13562
+ import { eq as eq19, and as and13, desc as desc9 } from "drizzle-orm";
13275
13563
 
13276
13564
  // ../integration-bing/src/constants.ts
13277
13565
  var BING_WMT_API_BASE = "https://ssl.bing.com/webmaster/api.svc/json";
@@ -13685,7 +13973,7 @@ async function bingRoutes(app, opts) {
13685
13973
  requireConnectionStore();
13686
13974
  const project = resolveProject(app.db, request.params.name);
13687
13975
  const { url, limit } = request.query;
13688
- const whereClause = url ? and10(eq19(bingUrlInspections.projectId, project.id), eq19(bingUrlInspections.url, url)) : eq19(bingUrlInspections.projectId, project.id);
13976
+ const whereClause = url ? and13(eq19(bingUrlInspections.projectId, project.id), eq19(bingUrlInspections.url, url)) : eq19(bingUrlInspections.projectId, project.id);
13689
13977
  const filtered = app.db.select().from(bingUrlInspections).where(whereClause).orderBy(desc9(bingUrlInspections.inspectedAt)).limit(Math.max(1, Math.min(parseInt(limit ?? "100", 10) || 100, 1e3))).all();
13690
13978
  return filtered.map((r) => ({
13691
13979
  id: r.id,
@@ -13917,7 +14205,7 @@ async function bingRoutes(app, opts) {
13917
14205
  import fs from "fs";
13918
14206
  import path from "path";
13919
14207
  import os2 from "os";
13920
- import { eq as eq20, and as and11 } from "drizzle-orm";
14208
+ import { eq as eq20, and as and14 } from "drizzle-orm";
13921
14209
  function getScreenshotDir() {
13922
14210
  return path.join(os2.homedir(), ".canonry", "screenshots");
13923
14211
  }
@@ -13990,7 +14278,7 @@ async function cdpRoutes(app, opts) {
13990
14278
  async (request, reply) => {
13991
14279
  const project = resolveProject(app.db, request.params.name);
13992
14280
  const { runId } = request.params;
13993
- const run = app.db.select().from(runs).where(and11(eq20(runs.id, runId), eq20(runs.projectId, project.id))).get();
14281
+ const run = app.db.select().from(runs).where(and14(eq20(runs.id, runId), eq20(runs.projectId, project.id))).get();
13994
14282
  if (!run) {
13995
14283
  const err = notFound("Run", runId);
13996
14284
  return reply.code(err.statusCode).send(err.toJSON());
@@ -14087,7 +14375,7 @@ async function cdpRoutes(app, opts) {
14087
14375
 
14088
14376
  // ../api-routes/src/ga.ts
14089
14377
  import crypto16 from "crypto";
14090
- import { eq as eq21, desc as desc10, and as and12, sql as sql8 } from "drizzle-orm";
14378
+ import { eq as eq21, desc as desc10, and as and15, sql as sql8 } from "drizzle-orm";
14091
14379
  function gaLog(level, action, ctx) {
14092
14380
  const entry = { ts: (/* @__PURE__ */ new Date()).toISOString(), level, module: "GA4Routes", action, ...ctx };
14093
14381
  const stream = level === "error" ? process.stderr : process.stdout;
@@ -14382,7 +14670,7 @@ async function ga4Routes(app, opts) {
14382
14670
  app.db.transaction((tx) => {
14383
14671
  if (syncTraffic) {
14384
14672
  tx.delete(gaTrafficSnapshots).where(
14385
- and12(
14673
+ and15(
14386
14674
  eq21(gaTrafficSnapshots.projectId, project.id),
14387
14675
  sql8`${gaTrafficSnapshots.date} >= ${summary.periodStart}`,
14388
14676
  sql8`${gaTrafficSnapshots.date} <= ${summary.periodEnd}`
@@ -14406,7 +14694,7 @@ async function ga4Routes(app, opts) {
14406
14694
  }
14407
14695
  if (syncAi) {
14408
14696
  tx.delete(gaAiReferrals).where(
14409
- and12(
14697
+ and15(
14410
14698
  eq21(gaAiReferrals.projectId, project.id),
14411
14699
  sql8`${gaAiReferrals.date} >= ${summary.periodStart}`,
14412
14700
  sql8`${gaAiReferrals.date} <= ${summary.periodEnd}`
@@ -14432,7 +14720,7 @@ async function ga4Routes(app, opts) {
14432
14720
  }
14433
14721
  if (syncSocial) {
14434
14722
  tx.delete(gaSocialReferrals).where(
14435
- and12(
14723
+ and15(
14436
14724
  eq21(gaSocialReferrals.projectId, project.id),
14437
14725
  sql8`${gaSocialReferrals.date} >= ${summary.periodStart}`,
14438
14726
  sql8`${gaSocialReferrals.date} <= ${summary.periodEnd}`
@@ -14536,7 +14824,7 @@ async function ga4Routes(app, opts) {
14536
14824
  totalDirectSessions: gaTrafficWindowSummaries.totalDirectSessions,
14537
14825
  totalUsers: gaTrafficWindowSummaries.totalUsers
14538
14826
  }).from(gaTrafficWindowSummaries).where(
14539
- and12(
14827
+ and15(
14540
14828
  eq21(gaTrafficWindowSummaries.projectId, project.id),
14541
14829
  eq21(gaTrafficWindowSummaries.windowKey, window)
14542
14830
  )
@@ -14545,7 +14833,7 @@ async function ga4Routes(app, opts) {
14545
14833
  totalSessions: sql8`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)`,
14546
14834
  totalOrganicSessions: sql8`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)`,
14547
14835
  totalUsers: sql8`COALESCE(SUM(${gaTrafficSnapshots.users}), 0)`
14548
- }).from(gaTrafficSnapshots).where(and12(...snapshotConditions)).get() : null;
14836
+ }).from(gaTrafficSnapshots).where(and15(...snapshotConditions)).get() : null;
14549
14837
  const summaryRow = cutoffDate ? windowSummaryRow ?? snapshotTotalsRow : app.db.select({
14550
14838
  totalSessions: gaTrafficSummaries.totalSessions,
14551
14839
  totalOrganicSessions: gaTrafficSummaries.totalOrganicSessions,
@@ -14553,7 +14841,7 @@ async function ga4Routes(app, opts) {
14553
14841
  }).from(gaTrafficSummaries).where(eq21(gaTrafficSummaries.projectId, project.id)).get();
14554
14842
  const directTotalRow = windowSummaryRow ? { totalDirectSessions: windowSummaryRow.totalDirectSessions } : app.db.select({
14555
14843
  totalDirectSessions: sql8`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`
14556
- }).from(gaTrafficSnapshots).where(and12(...snapshotConditions)).get();
14844
+ }).from(gaTrafficSnapshots).where(and15(...snapshotConditions)).get();
14557
14845
  const summaryMeta = app.db.select({
14558
14846
  periodStart: gaTrafficSummaries.periodStart,
14559
14847
  periodEnd: gaTrafficSummaries.periodEnd
@@ -14564,14 +14852,14 @@ async function ga4Routes(app, opts) {
14564
14852
  organicSessions: sql8`SUM(${gaTrafficSnapshots.organicSessions})`,
14565
14853
  directSessions: sql8`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`,
14566
14854
  users: sql8`SUM(${gaTrafficSnapshots.users})`
14567
- }).from(gaTrafficSnapshots).where(and12(...snapshotConditions)).groupBy(sql8`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`).orderBy(sql8`SUM(${gaTrafficSnapshots.sessions}) DESC`).limit(limit).all();
14855
+ }).from(gaTrafficSnapshots).where(and15(...snapshotConditions)).groupBy(sql8`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`).orderBy(sql8`SUM(${gaTrafficSnapshots.sessions}) DESC`).limit(limit).all();
14568
14856
  const aiReferralRows = app.db.select({
14569
14857
  source: gaAiReferrals.source,
14570
14858
  medium: gaAiReferrals.medium,
14571
14859
  sourceDimension: gaAiReferrals.sourceDimension,
14572
14860
  sessions: sql8`SUM(${gaAiReferrals.sessions})`,
14573
14861
  users: sql8`SUM(${gaAiReferrals.users})`
14574
- }).from(gaAiReferrals).where(and12(...aiConditions)).groupBy(gaAiReferrals.source, gaAiReferrals.medium, gaAiReferrals.sourceDimension).all();
14862
+ }).from(gaAiReferrals).where(and15(...aiConditions)).groupBy(gaAiReferrals.source, gaAiReferrals.medium, gaAiReferrals.sourceDimension).all();
14575
14863
  const aiReferralLandingPageRows = app.db.select({
14576
14864
  source: gaAiReferrals.source,
14577
14865
  medium: gaAiReferrals.medium,
@@ -14579,7 +14867,7 @@ async function ga4Routes(app, opts) {
14579
14867
  landingPage: sql8`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`,
14580
14868
  sessions: sql8`SUM(${gaAiReferrals.sessions})`,
14581
14869
  users: sql8`SUM(${gaAiReferrals.users})`
14582
- }).from(gaAiReferrals).where(and12(...aiConditions)).groupBy(
14870
+ }).from(gaAiReferrals).where(and15(...aiConditions)).groupBy(
14583
14871
  gaAiReferrals.source,
14584
14872
  gaAiReferrals.medium,
14585
14873
  gaAiReferrals.sourceDimension,
@@ -14616,7 +14904,7 @@ async function ga4Routes(app, opts) {
14616
14904
  channelGroup: gaAiReferrals.channelGroup,
14617
14905
  sessions: sql8`COALESCE(SUM(${gaAiReferrals.sessions}), 0)`,
14618
14906
  users: sql8`COALESCE(SUM(${gaAiReferrals.users}), 0)`
14619
- }).from(gaAiReferrals).where(and12(...aiConditions, eq21(gaAiReferrals.sourceDimension, "session"))).groupBy(gaAiReferrals.channelGroup).all();
14907
+ }).from(gaAiReferrals).where(and15(...aiConditions, eq21(gaAiReferrals.sourceDimension, "session"))).groupBy(gaAiReferrals.channelGroup).all();
14620
14908
  const aiSessionsByChannelGroup = /* @__PURE__ */ new Map();
14621
14909
  let aiBySessionUsers = 0;
14622
14910
  for (const row of aiBySessionRows) {
@@ -14630,11 +14918,11 @@ async function ga4Routes(app, opts) {
14630
14918
  channelGroup: gaSocialReferrals.channelGroup,
14631
14919
  sessions: sql8`SUM(${gaSocialReferrals.sessions})`,
14632
14920
  users: sql8`SUM(${gaSocialReferrals.users})`
14633
- }).from(gaSocialReferrals).where(and12(...socialConditions)).groupBy(gaSocialReferrals.source, gaSocialReferrals.medium, gaSocialReferrals.channelGroup).orderBy(sql8`SUM(${gaSocialReferrals.sessions}) DESC`).all();
14921
+ }).from(gaSocialReferrals).where(and15(...socialConditions)).groupBy(gaSocialReferrals.source, gaSocialReferrals.medium, gaSocialReferrals.channelGroup).orderBy(sql8`SUM(${gaSocialReferrals.sessions}) DESC`).all();
14634
14922
  const socialTotals = app.db.select({
14635
14923
  sessions: sql8`SUM(${gaSocialReferrals.sessions})`,
14636
14924
  users: sql8`SUM(${gaSocialReferrals.users})`
14637
- }).from(gaSocialReferrals).where(and12(...socialConditions)).get();
14925
+ }).from(gaSocialReferrals).where(and15(...socialConditions)).get();
14638
14926
  const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq21(gaTrafficSummaries.projectId, project.id)).orderBy(desc10(gaTrafficSummaries.syncedAt)).limit(1).get();
14639
14927
  const total = summaryRow?.totalSessions ?? 0;
14640
14928
  const totalDirectSessions = directTotalRow?.totalDirectSessions ?? 0;
@@ -14725,7 +15013,7 @@ async function ga4Routes(app, opts) {
14725
15013
  sourceDimension: gaAiReferrals.sourceDimension,
14726
15014
  sessions: sql8`SUM(${gaAiReferrals.sessions})`,
14727
15015
  users: sql8`SUM(${gaAiReferrals.users})`
14728
- }).from(gaAiReferrals).where(and12(...conditions)).groupBy(
15016
+ }).from(gaAiReferrals).where(and15(...conditions)).groupBy(
14729
15017
  gaAiReferrals.date,
14730
15018
  gaAiReferrals.source,
14731
15019
  gaAiReferrals.medium,
@@ -14747,7 +15035,7 @@ async function ga4Routes(app, opts) {
14747
15035
  channelGroup: gaSocialReferrals.channelGroup,
14748
15036
  sessions: gaSocialReferrals.sessions,
14749
15037
  users: gaSocialReferrals.users
14750
- }).from(gaSocialReferrals).where(and12(...conditions)).orderBy(gaSocialReferrals.date).all();
15038
+ }).from(gaSocialReferrals).where(and15(...conditions)).orderBy(gaSocialReferrals.date).all();
14751
15039
  return rows;
14752
15040
  });
14753
15041
  app.get("/projects/:name/ga/social-referral-trend", async (request, _reply) => {
@@ -14760,7 +15048,7 @@ async function ga4Routes(app, opts) {
14760
15048
  d.setDate(d.getDate() - n);
14761
15049
  return fmt(d);
14762
15050
  };
14763
- const sumSocial = (from, to) => app.db.select({ sessions: sql8`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and12(
15051
+ const sumSocial = (from, to) => app.db.select({ sessions: sql8`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and15(
14764
15052
  eq21(gaSocialReferrals.projectId, project.id),
14765
15053
  sql8`${gaSocialReferrals.date} >= ${from}`,
14766
15054
  sql8`${gaSocialReferrals.date} < ${to}`
@@ -14773,7 +15061,7 @@ async function ga4Routes(app, opts) {
14773
15061
  const sourceCurrent = app.db.select({
14774
15062
  source: gaSocialReferrals.source,
14775
15063
  sessions: sql8`SUM(${gaSocialReferrals.sessions})`
14776
- }).from(gaSocialReferrals).where(and12(
15064
+ }).from(gaSocialReferrals).where(and15(
14777
15065
  eq21(gaSocialReferrals.projectId, project.id),
14778
15066
  sql8`${gaSocialReferrals.date} >= ${daysAgo2(7)}`,
14779
15067
  sql8`${gaSocialReferrals.date} < ${fmt(today)}`
@@ -14781,7 +15069,7 @@ async function ga4Routes(app, opts) {
14781
15069
  const sourcePrev = app.db.select({
14782
15070
  source: gaSocialReferrals.source,
14783
15071
  sessions: sql8`SUM(${gaSocialReferrals.sessions})`
14784
- }).from(gaSocialReferrals).where(and12(
15072
+ }).from(gaSocialReferrals).where(and15(
14785
15073
  eq21(gaSocialReferrals.projectId, project.id),
14786
15074
  sql8`${gaSocialReferrals.date} >= ${daysAgo2(14)}`,
14787
15075
  sql8`${gaSocialReferrals.date} < ${daysAgo2(7)}`
@@ -14823,16 +15111,16 @@ async function ga4Routes(app, opts) {
14823
15111
  return fmt(d);
14824
15112
  };
14825
15113
  const pct = (cur, prev) => prev === 0 ? null : Math.round((cur - prev) / prev * 100);
14826
- const sumTotal = (from, to) => app.db.select({ sessions: sql8`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)` }).from(gaTrafficSnapshots).where(and12(eq21(gaTrafficSnapshots.projectId, project.id), sql8`${gaTrafficSnapshots.date} >= ${from}`, sql8`${gaTrafficSnapshots.date} < ${to}`)).get();
14827
- const sumOrganic = (from, to) => app.db.select({ sessions: sql8`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)` }).from(gaTrafficSnapshots).where(and12(eq21(gaTrafficSnapshots.projectId, project.id), sql8`${gaTrafficSnapshots.date} >= ${from}`, sql8`${gaTrafficSnapshots.date} < ${to}`)).get();
14828
- const sumDirect = (from, to) => app.db.select({ sessions: sql8`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)` }).from(gaTrafficSnapshots).where(and12(eq21(gaTrafficSnapshots.projectId, project.id), sql8`${gaTrafficSnapshots.date} >= ${from}`, sql8`${gaTrafficSnapshots.date} < ${to}`)).get();
14829
- const sumAi = (from, to) => app.db.select({ sessions: sql8`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and12(
15114
+ const sumTotal = (from, to) => app.db.select({ sessions: sql8`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)` }).from(gaTrafficSnapshots).where(and15(eq21(gaTrafficSnapshots.projectId, project.id), sql8`${gaTrafficSnapshots.date} >= ${from}`, sql8`${gaTrafficSnapshots.date} < ${to}`)).get();
15115
+ const sumOrganic = (from, to) => app.db.select({ sessions: sql8`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)` }).from(gaTrafficSnapshots).where(and15(eq21(gaTrafficSnapshots.projectId, project.id), sql8`${gaTrafficSnapshots.date} >= ${from}`, sql8`${gaTrafficSnapshots.date} < ${to}`)).get();
15116
+ const sumDirect = (from, to) => app.db.select({ sessions: sql8`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)` }).from(gaTrafficSnapshots).where(and15(eq21(gaTrafficSnapshots.projectId, project.id), sql8`${gaTrafficSnapshots.date} >= ${from}`, sql8`${gaTrafficSnapshots.date} < ${to}`)).get();
15117
+ const sumAi = (from, to) => app.db.select({ sessions: sql8`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and15(
14830
15118
  eq21(gaAiReferrals.projectId, project.id),
14831
15119
  sql8`${gaAiReferrals.date} >= ${from}`,
14832
15120
  sql8`${gaAiReferrals.date} < ${to}`,
14833
15121
  eq21(gaAiReferrals.sourceDimension, "session")
14834
15122
  )).get();
14835
- const sumSocial = (from, to) => app.db.select({ sessions: sql8`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and12(eq21(gaSocialReferrals.projectId, project.id), sql8`${gaSocialReferrals.date} >= ${from}`, sql8`${gaSocialReferrals.date} < ${to}`)).get();
15123
+ const sumSocial = (from, to) => app.db.select({ sessions: sql8`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and15(eq21(gaSocialReferrals.projectId, project.id), sql8`${gaSocialReferrals.date} >= ${from}`, sql8`${gaSocialReferrals.date} < ${to}`)).get();
14836
15124
  const todayStr = fmt(today);
14837
15125
  const buildTrend = (sum) => {
14838
15126
  const c7 = sum(daysAgo2(7), todayStr)?.sessions ?? 0;
@@ -14841,13 +15129,13 @@ async function ga4Routes(app, opts) {
14841
15129
  const p30 = sum(daysAgo2(60), daysAgo2(30))?.sessions ?? 0;
14842
15130
  return { sessions7d: c7, sessionsPrev7d: p7, trend7dPct: pct(c7, p7), sessions30d: c30, sessionsPrev30d: p30, trend30dPct: pct(c30, p30) };
14843
15131
  };
14844
- const aiSourceCurrent = app.db.select({ source: gaAiReferrals.source, sessions: sql8`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and12(
15132
+ const aiSourceCurrent = app.db.select({ source: gaAiReferrals.source, sessions: sql8`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and15(
14845
15133
  eq21(gaAiReferrals.projectId, project.id),
14846
15134
  sql8`${gaAiReferrals.date} >= ${daysAgo2(7)}`,
14847
15135
  sql8`${gaAiReferrals.date} < ${todayStr}`,
14848
15136
  eq21(gaAiReferrals.sourceDimension, "session")
14849
15137
  )).groupBy(gaAiReferrals.source).all();
14850
- const aiSourcePrev = app.db.select({ source: gaAiReferrals.source, sessions: sql8`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and12(
15138
+ const aiSourcePrev = app.db.select({ source: gaAiReferrals.source, sessions: sql8`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and15(
14851
15139
  eq21(gaAiReferrals.projectId, project.id),
14852
15140
  sql8`${gaAiReferrals.date} >= ${daysAgo2(14)}`,
14853
15141
  sql8`${gaAiReferrals.date} < ${daysAgo2(7)}`,
@@ -14867,8 +15155,8 @@ async function ga4Routes(app, opts) {
14867
15155
  }
14868
15156
  return mover;
14869
15157
  };
14870
- const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions: sql8`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and12(eq21(gaSocialReferrals.projectId, project.id), sql8`${gaSocialReferrals.date} >= ${daysAgo2(7)}`, sql8`${gaSocialReferrals.date} < ${todayStr}`)).groupBy(gaSocialReferrals.source).all();
14871
- const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions: sql8`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and12(eq21(gaSocialReferrals.projectId, project.id), sql8`${gaSocialReferrals.date} >= ${daysAgo2(14)}`, sql8`${gaSocialReferrals.date} < ${daysAgo2(7)}`)).groupBy(gaSocialReferrals.source).all();
15158
+ const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions: sql8`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and15(eq21(gaSocialReferrals.projectId, project.id), sql8`${gaSocialReferrals.date} >= ${daysAgo2(7)}`, sql8`${gaSocialReferrals.date} < ${todayStr}`)).groupBy(gaSocialReferrals.source).all();
15159
+ const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions: sql8`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and15(eq21(gaSocialReferrals.projectId, project.id), sql8`${gaSocialReferrals.date} >= ${daysAgo2(14)}`, sql8`${gaSocialReferrals.date} < ${daysAgo2(7)}`)).groupBy(gaSocialReferrals.source).all();
14872
15160
  return {
14873
15161
  total: buildTrend(sumTotal),
14874
15162
  organic: buildTrend(sumOrganic),
@@ -14890,7 +15178,7 @@ async function ga4Routes(app, opts) {
14890
15178
  sessions: sql8`SUM(${gaTrafficSnapshots.sessions})`,
14891
15179
  organicSessions: sql8`SUM(${gaTrafficSnapshots.organicSessions})`,
14892
15180
  users: sql8`SUM(${gaTrafficSnapshots.users})`
14893
- }).from(gaTrafficSnapshots).where(and12(...conditions)).groupBy(gaTrafficSnapshots.date).orderBy(gaTrafficSnapshots.date).all();
15181
+ }).from(gaTrafficSnapshots).where(and15(...conditions)).groupBy(gaTrafficSnapshots.date).orderBy(gaTrafficSnapshots.date).all();
14894
15182
  return rows.map((r) => ({
14895
15183
  date: r.date,
14896
15184
  sessions: r.sessions ?? 0,
@@ -16543,7 +16831,7 @@ async function wordpressRoutes(app, opts) {
16543
16831
 
16544
16832
  // ../api-routes/src/backlinks.ts
16545
16833
  import crypto18 from "crypto";
16546
- import { and as and14, asc as asc2, desc as desc11, eq as eq22, sql as sql9 } from "drizzle-orm";
16834
+ import { and as and17, asc as asc2, desc as desc11, eq as eq22, sql as sql9 } from "drizzle-orm";
16547
16835
 
16548
16836
  // ../integration-commoncrawl/src/constants.ts
16549
16837
  import os3 from "os";
@@ -16940,7 +17228,7 @@ function pruneCachedRelease(release, opts = {}) {
16940
17228
  }
16941
17229
 
16942
17230
  // ../api-routes/src/backlinks-filter.ts
16943
- import { and as and13, ne as ne2, notLike } from "drizzle-orm";
17231
+ import { and as and16, ne as ne3, notLike } from "drizzle-orm";
16944
17232
  var BACKLINK_FILTER_PATTERNS = [
16945
17233
  "*.google.com",
16946
17234
  "*.googleusercontent.com",
@@ -16957,13 +17245,13 @@ function backlinkCrawlerExclusionClause() {
16957
17245
  for (const pattern of BACKLINK_FILTER_PATTERNS) {
16958
17246
  if (pattern.startsWith("*.")) {
16959
17247
  const suffix = pattern.slice(2);
16960
- conditions.push(ne2(backlinkDomains.linkingDomain, suffix));
17248
+ conditions.push(ne3(backlinkDomains.linkingDomain, suffix));
16961
17249
  conditions.push(notLike(backlinkDomains.linkingDomain, `%.${suffix}`));
16962
17250
  } else {
16963
- conditions.push(ne2(backlinkDomains.linkingDomain, pattern));
17251
+ conditions.push(ne3(backlinkDomains.linkingDomain, pattern));
16964
17252
  }
16965
17253
  }
16966
- const combined = and13(...conditions);
17254
+ const combined = and16(...conditions);
16967
17255
  if (!combined) throw new Error("BACKLINK_FILTER_PATTERNS is unexpectedly empty");
16968
17256
  return combined;
16969
17257
  }
@@ -17024,7 +17312,7 @@ function mapRunRow(row) {
17024
17312
  };
17025
17313
  }
17026
17314
  function latestSummaryForProject(db, projectId, release) {
17027
- const condition = release ? and14(eq22(backlinkSummaries.projectId, projectId), eq22(backlinkSummaries.release, release)) : eq22(backlinkSummaries.projectId, projectId);
17315
+ const condition = release ? and17(eq22(backlinkSummaries.projectId, projectId), eq22(backlinkSummaries.release, release)) : eq22(backlinkSummaries.projectId, projectId);
17028
17316
  return db.select().from(backlinkSummaries).where(condition).orderBy(desc11(backlinkSummaries.queriedAt)).limit(1).get();
17029
17317
  }
17030
17318
  function parseExcludeCrawlers(value) {
@@ -17033,11 +17321,11 @@ function parseExcludeCrawlers(value) {
17033
17321
  return lower === "1" || lower === "true" || lower === "yes";
17034
17322
  }
17035
17323
  function computeFilteredSummary(db, base) {
17036
- const baseDomainCondition = and14(
17324
+ const baseDomainCondition = and17(
17037
17325
  eq22(backlinkDomains.projectId, base.projectId),
17038
17326
  eq22(backlinkDomains.release, base.release)
17039
17327
  );
17040
- const filteredCondition = and14(baseDomainCondition, backlinkCrawlerExclusionClause());
17328
+ const filteredCondition = and17(baseDomainCondition, backlinkCrawlerExclusionClause());
17041
17329
  const unfilteredAgg = db.select({
17042
17330
  count: sql9`count(*)`,
17043
17331
  total: sql9`coalesce(sum(${backlinkDomains.numHosts}), 0)`
@@ -17213,11 +17501,11 @@ async function backlinksRoutes(app, opts) {
17213
17501
  const limit = Math.min(Math.max(parseInt(request.query.limit ?? "50", 10) || 50, 1), 500);
17214
17502
  const offset = Math.max(parseInt(request.query.offset ?? "0", 10) || 0, 0);
17215
17503
  const excludeCrawlers = parseExcludeCrawlers(request.query.excludeCrawlers);
17216
- const baseDomainCondition = and14(
17504
+ const baseDomainCondition = and17(
17217
17505
  eq22(backlinkDomains.projectId, project.id),
17218
17506
  eq22(backlinkDomains.release, targetRelease)
17219
17507
  );
17220
- const domainCondition = excludeCrawlers ? and14(baseDomainCondition, backlinkCrawlerExclusionClause()) : baseDomainCondition;
17508
+ const domainCondition = excludeCrawlers ? and17(baseDomainCondition, backlinkCrawlerExclusionClause()) : baseDomainCondition;
17221
17509
  const totalRow = app.db.select({ count: sql9`count(*)` }).from(backlinkDomains).where(domainCondition).get();
17222
17510
  const rows = app.db.select({
17223
17511
  linkingDomain: backlinkDomains.linkingDomain,
@@ -17253,7 +17541,7 @@ async function backlinksRoutes(app, opts) {
17253
17541
 
17254
17542
  // ../api-routes/src/traffic.ts
17255
17543
  import crypto20 from "crypto";
17256
- import { and as and15, desc as desc12, eq as eq23, gte as gte2, lte as lte2, sql as sql10 } from "drizzle-orm";
17544
+ import { and as and18, desc as desc12, eq as eq23, gte as gte2, lte as lte2, sql as sql10 } from "drizzle-orm";
17257
17545
 
17258
17546
  // ../integration-cloud-run/src/auth.ts
17259
17547
  import crypto19 from "crypto";
@@ -18402,21 +18690,21 @@ async function runBackfillTask(options) {
18402
18690
  try {
18403
18691
  app.db.transaction((tx) => {
18404
18692
  tx.delete(crawlerEventsHourly).where(
18405
- and15(
18693
+ and18(
18406
18694
  eq23(crawlerEventsHourly.sourceId, sourceRow.id),
18407
18695
  gte2(crawlerEventsHourly.tsHour, windowStartIso),
18408
18696
  lte2(crawlerEventsHourly.tsHour, windowEndIso)
18409
18697
  )
18410
18698
  ).run();
18411
18699
  tx.delete(aiReferralEventsHourly).where(
18412
- and15(
18700
+ and18(
18413
18701
  eq23(aiReferralEventsHourly.sourceId, sourceRow.id),
18414
18702
  gte2(aiReferralEventsHourly.tsHour, windowStartIso),
18415
18703
  lte2(aiReferralEventsHourly.tsHour, windowEndIso)
18416
18704
  )
18417
18705
  ).run();
18418
18706
  tx.delete(rawEventSamples).where(
18419
- and15(
18707
+ and18(
18420
18708
  eq23(rawEventSamples.sourceId, sourceRow.id),
18421
18709
  gte2(rawEventSamples.ts, windowStartIso),
18422
18710
  lte2(rawEventSamples.ts, windowEndIso)
@@ -19280,25 +19568,25 @@ async function trafficRoutes(app, opts) {
19280
19568
  });
19281
19569
  function buildSourceDetail(projectId, row, since) {
19282
19570
  const crawlerTotals = app.db.select({ total: sql10`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
19283
- and15(
19571
+ and18(
19284
19572
  eq23(crawlerEventsHourly.sourceId, row.id),
19285
19573
  gte2(crawlerEventsHourly.tsHour, since)
19286
19574
  )
19287
19575
  ).get();
19288
19576
  const aiTotals = app.db.select({ total: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
19289
- and15(
19577
+ and18(
19290
19578
  eq23(aiReferralEventsHourly.sourceId, row.id),
19291
19579
  gte2(aiReferralEventsHourly.tsHour, since)
19292
19580
  )
19293
19581
  ).get();
19294
19582
  const sampleTotals = app.db.select({ total: sql10`COUNT(*)` }).from(rawEventSamples).where(
19295
- and15(
19583
+ and18(
19296
19584
  eq23(rawEventSamples.sourceId, row.id),
19297
19585
  gte2(rawEventSamples.ts, since)
19298
19586
  )
19299
19587
  ).get();
19300
19588
  const latestRun = app.db.select().from(runs).where(
19301
- and15(
19589
+ and18(
19302
19590
  eq23(runs.projectId, projectId),
19303
19591
  eq23(runs.kind, RunKinds["traffic-sync"]),
19304
19592
  eq23(runs.sourceId, row.id)
@@ -19392,7 +19680,7 @@ async function trafficRoutes(app, opts) {
19392
19680
  lte2(crawlerEventsHourly.tsHour, untilIso)
19393
19681
  ];
19394
19682
  if (sourceIdParam) crawlerFilters.push(eq23(crawlerEventsHourly.sourceId, sourceIdParam));
19395
- const crawlerWhere = and15(...crawlerFilters);
19683
+ const crawlerWhere = and18(...crawlerFilters);
19396
19684
  const total = app.db.select({ total: sql10`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(crawlerWhere).get();
19397
19685
  crawlerTotal = Number(total?.total ?? 0);
19398
19686
  const rows = app.db.select().from(crawlerEventsHourly).where(crawlerWhere).orderBy(desc12(crawlerEventsHourly.tsHour)).limit(limit).all();
@@ -19417,7 +19705,7 @@ async function trafficRoutes(app, opts) {
19417
19705
  lte2(aiReferralEventsHourly.tsHour, untilIso)
19418
19706
  ];
19419
19707
  if (sourceIdParam) aiFilters.push(eq23(aiReferralEventsHourly.sourceId, sourceIdParam));
19420
- const aiWhere = and15(...aiFilters);
19708
+ const aiWhere = and18(...aiFilters);
19421
19709
  const total = app.db.select({ total: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(aiWhere).get();
19422
19710
  aiReferralTotal = Number(total?.total ?? 0);
19423
19711
  const rows = app.db.select().from(aiReferralEventsHourly).where(aiWhere).orderBy(desc12(aiReferralEventsHourly.tsHour)).limit(limit).all();
@@ -20141,7 +20429,7 @@ var providersConfiguredCheck = {
20141
20429
  var PROVIDERS_CHECKS = [providersConfiguredCheck];
20142
20430
 
20143
20431
  // ../api-routes/src/doctor/checks/traffic-source.ts
20144
- import { and as and16, eq as eq24, gte as gte3, ne as ne3, sql as sql11 } from "drizzle-orm";
20432
+ import { and as and19, eq as eq24, gte as gte3, ne as ne4, sql as sql11 } from "drizzle-orm";
20145
20433
  var RECENT_DATA_WARN_DAYS = 7;
20146
20434
  var RECENT_DATA_FAIL_DAYS = 30;
20147
20435
  function skippedNoProject2() {
@@ -20155,9 +20443,9 @@ function skippedNoProject2() {
20155
20443
  function loadProbes(ctx) {
20156
20444
  if (!ctx.project) return [];
20157
20445
  const rows = ctx.db.select().from(trafficSources).where(
20158
- and16(
20446
+ and19(
20159
20447
  eq24(trafficSources.projectId, ctx.project.id),
20160
- ne3(trafficSources.status, TrafficSourceStatuses.archived)
20448
+ ne4(trafficSources.status, TrafficSourceStatuses.archived)
20161
20449
  )
20162
20450
  ).all();
20163
20451
  return rows.map((r) => ({
@@ -20236,7 +20524,7 @@ var recentDataCheck = {
20236
20524
  const failCutoff = new Date(now.getTime() - RECENT_DATA_FAIL_DAYS * 24 * 60 * 6e4).toISOString();
20237
20525
  const recentCrawlers = Number(
20238
20526
  ctx.db.select({ total: sql11`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
20239
- and16(
20527
+ and19(
20240
20528
  eq24(crawlerEventsHourly.projectId, ctx.project.id),
20241
20529
  gte3(crawlerEventsHourly.tsHour, warnCutoff)
20242
20530
  )
@@ -20244,7 +20532,7 @@ var recentDataCheck = {
20244
20532
  );
20245
20533
  const recentReferrals = Number(
20246
20534
  ctx.db.select({ total: sql11`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
20247
- and16(
20535
+ and19(
20248
20536
  eq24(aiReferralEventsHourly.projectId, ctx.project.id),
20249
20537
  gte3(aiReferralEventsHourly.tsHour, warnCutoff)
20250
20538
  )
@@ -20260,7 +20548,7 @@ var recentDataCheck = {
20260
20548
  }
20261
20549
  const olderCrawlers = Number(
20262
20550
  ctx.db.select({ total: sql11`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
20263
- and16(
20551
+ and19(
20264
20552
  eq24(crawlerEventsHourly.projectId, ctx.project.id),
20265
20553
  gte3(crawlerEventsHourly.tsHour, failCutoff)
20266
20554
  )
@@ -20268,7 +20556,7 @@ var recentDataCheck = {
20268
20556
  );
20269
20557
  const olderReferrals = Number(
20270
20558
  ctx.db.select({ total: sql11`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
20271
- and16(
20559
+ and19(
20272
20560
  eq24(aiReferralEventsHourly.projectId, ctx.project.id),
20273
20561
  gte3(aiReferralEventsHourly.tsHour, failCutoff)
20274
20562
  )
@@ -20452,9 +20740,6 @@ var ALL_CHECKS = [
20452
20740
  ...TRAFFIC_SOURCE_CHECKS,
20453
20741
  ...AGENT_CHECKS
20454
20742
  ];
20455
- var CHECK_BY_ID = Object.fromEntries(
20456
- ALL_CHECKS.map((check) => [check.id, check])
20457
- );
20458
20743
 
20459
20744
  // ../api-routes/src/doctor/runner.ts
20460
20745
  function matchesCheckId(checkId, filters) {
@@ -20567,7 +20852,7 @@ async function doctorRoutes(app, opts) {
20567
20852
 
20568
20853
  // ../api-routes/src/discovery/routes.ts
20569
20854
  import crypto21 from "crypto";
20570
- import { and as and17, desc as desc13, eq as eq25, gte as gte4, inArray as inArray9 } from "drizzle-orm";
20855
+ import { and as and20, desc as desc13, eq as eq25, gte as gte4, inArray as inArray9 } from "drizzle-orm";
20571
20856
  var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
20572
20857
  async function discoveryRoutes(app, opts) {
20573
20858
  app.post("/projects/:name/discover/run", async (request, reply) => {
@@ -20599,7 +20884,7 @@ async function discoveryRoutes(app, opts) {
20599
20884
  const now = (/* @__PURE__ */ new Date()).toISOString();
20600
20885
  const ageFloorIso = new Date(Date.now() - MAX_INFLIGHT_DISCOVERY_AGE_MS).toISOString();
20601
20886
  const decision = app.db.transaction((tx) => {
20602
- const existing = tx.select({ id: discoverySessions.id, runId: discoverySessions.runId }).from(discoverySessions).where(and17(
20887
+ const existing = tx.select({ id: discoverySessions.id, runId: discoverySessions.runId }).from(discoverySessions).where(and20(
20603
20888
  eq25(discoverySessions.projectId, project.id),
20604
20889
  eq25(discoverySessions.icpDescription, icpDescription),
20605
20890
  inArray9(discoverySessions.status, [
@@ -21847,7 +22132,7 @@ async function healthcheck2(config) {
21847
22132
  async function executeTrackedQuery2(input) {
21848
22133
  const model = input.config.model ?? DEFAULT_MODEL2;
21849
22134
  const client = new OpenAI({ apiKey: input.config.apiKey });
21850
- const webSearchTool = { type: "web_search_preview" };
22135
+ const webSearchTool = { type: "web_search" };
21851
22136
  if (input.location) {
21852
22137
  webSearchTool.user_location = {
21853
22138
  type: "approximate",
@@ -23922,7 +24207,7 @@ import crypto24 from "crypto";
23922
24207
  import fs8 from "fs";
23923
24208
  import path10 from "path";
23924
24209
  import os5 from "os";
23925
- import { and as and18, eq as eq27, inArray as inArray10, sql as sql12 } from "drizzle-orm";
24210
+ import { and as and21, eq as eq27, inArray as inArray10, sql as sql12 } from "drizzle-orm";
23926
24211
 
23927
24212
  // src/run-telemetry.ts
23928
24213
  import crypto23 from "crypto";
@@ -24305,7 +24590,7 @@ var JobRunner = class {
24305
24590
  throw new Error(`Run ${runId} is not executable from status '${existingRun.status}'`);
24306
24591
  }
24307
24592
  if (existingRun.status === "queued") {
24308
- this.db.update(runs).set({ status: "running", startedAt: now }).where(and18(eq27(runs.id, runId), eq27(runs.status, "queued"))).run();
24593
+ this.db.update(runs).set({ status: "running", startedAt: now }).where(and21(eq27(runs.id, runId), eq27(runs.status, "queued"))).run();
24309
24594
  }
24310
24595
  this.throwIfRunCancelled(runId);
24311
24596
  const project = this.db.select().from(projects).where(eq27(projects.id, projectId)).get();
@@ -24330,7 +24615,7 @@ var JobRunner = class {
24330
24615
  }
24331
24616
  log.info("run.dispatch", { runId, providerCount: activeProviders.length, providers: activeProviders.map((p) => p.adapter.name) });
24332
24617
  const scopedQueryNames = parseJsonColumn(existingRun.queries, null);
24333
- projectQueries = scopedQueryNames ? this.db.select().from(queries).where(and18(eq27(queries.projectId, projectId), inArray10(queries.query, scopedQueryNames))).all() : this.db.select().from(queries).where(eq27(queries.projectId, projectId)).all();
24618
+ projectQueries = scopedQueryNames ? this.db.select().from(queries).where(and21(eq27(queries.projectId, projectId), inArray10(queries.query, scopedQueryNames))).all() : this.db.select().from(queries).where(eq27(queries.projectId, projectId)).all();
24334
24619
  const projectCompetitors = this.db.select().from(competitors).where(eq27(competitors.projectId, projectId)).all();
24335
24620
  const competitorDomains = projectCompetitors.map((c) => c.domain);
24336
24621
  const allDomains = effectiveDomains({
@@ -24673,7 +24958,7 @@ function buildPhases(input) {
24673
24958
 
24674
24959
  // src/gsc-sync.ts
24675
24960
  import crypto25 from "crypto";
24676
- import { eq as eq28, and as and19, sql as sql13 } from "drizzle-orm";
24961
+ import { eq as eq28, and as and22, sql as sql13 } from "drizzle-orm";
24677
24962
  var log2 = createLogger("GscSync");
24678
24963
  function formatDate3(d) {
24679
24964
  return d.toISOString().split("T")[0];
@@ -24725,7 +25010,7 @@ async function executeGscSync(db, runId, projectId, opts) {
24725
25010
  });
24726
25011
  log2.info("fetch.complete", { runId, projectId, rowCount: rows.length });
24727
25012
  db.delete(gscSearchData).where(
24728
- and19(
25013
+ and22(
24729
25014
  eq28(gscSearchData.projectId, projectId),
24730
25015
  sql13`${gscSearchData.date} >= ${startDate}`,
24731
25016
  sql13`${gscSearchData.date} <= ${endDate}`
@@ -24814,7 +25099,7 @@ async function executeGscSync(db, runId, projectId, opts) {
24814
25099
  }
24815
25100
  }
24816
25101
  const snapshotDate = formatDate3(/* @__PURE__ */ new Date());
24817
- db.delete(gscCoverageSnapshots).where(and19(eq28(gscCoverageSnapshots.projectId, projectId), eq28(gscCoverageSnapshots.date, snapshotDate))).run();
25102
+ db.delete(gscCoverageSnapshots).where(and22(eq28(gscCoverageSnapshots.projectId, projectId), eq28(gscCoverageSnapshots.date, snapshotDate))).run();
24818
25103
  db.insert(gscCoverageSnapshots).values({
24819
25104
  id: crypto25.randomUUID(),
24820
25105
  projectId,
@@ -24837,7 +25122,7 @@ async function executeGscSync(db, runId, projectId, opts) {
24837
25122
 
24838
25123
  // src/gsc-inspect-sitemap.ts
24839
25124
  import crypto26 from "crypto";
24840
- import { eq as eq29, and as and20 } from "drizzle-orm";
25125
+ import { eq as eq29, and as and23 } from "drizzle-orm";
24841
25126
 
24842
25127
  // src/sitemap-parser.ts
24843
25128
  var log3 = createLogger("SitemapParser");
@@ -25055,7 +25340,7 @@ async function executeInspectSitemap(db, runId, projectId, opts) {
25055
25340
  }
25056
25341
  }
25057
25342
  const snapshotDate = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
25058
- db.delete(gscCoverageSnapshots).where(and20(eq29(gscCoverageSnapshots.projectId, projectId), eq29(gscCoverageSnapshots.date, snapshotDate))).run();
25343
+ db.delete(gscCoverageSnapshots).where(and23(eq29(gscCoverageSnapshots.projectId, projectId), eq29(gscCoverageSnapshots.date, snapshotDate))).run();
25059
25344
  db.insert(gscCoverageSnapshots).values({
25060
25345
  id: crypto26.randomUUID(),
25061
25346
  projectId,
@@ -25266,7 +25551,7 @@ async function executeBingInspectSitemap(db, runId, projectId, opts) {
25266
25551
  // src/commoncrawl-sync.ts
25267
25552
  import crypto28 from "crypto";
25268
25553
  import path11 from "path";
25269
- import { and as and21, eq as eq31, sql as sql14 } from "drizzle-orm";
25554
+ import { and as and24, eq as eq31, sql as sql14 } from "drizzle-orm";
25270
25555
  var log6 = createLogger("CommonCrawlSync");
25271
25556
  var INSERT_CHUNK_SIZE = 1e4;
25272
25557
  function defaultDeps() {
@@ -25457,7 +25742,7 @@ function computeSummary(rows) {
25457
25742
  // src/backlink-extract.ts
25458
25743
  import crypto29 from "crypto";
25459
25744
  import fs9 from "fs";
25460
- import { and as and22, desc as desc15, eq as eq32 } from "drizzle-orm";
25745
+ import { and as and25, desc as desc15, eq as eq32 } from "drizzle-orm";
25461
25746
  var log7 = createLogger("BacklinkExtract");
25462
25747
  function defaultDeps2() {
25463
25748
  return {
@@ -25503,7 +25788,7 @@ async function executeBacklinkExtract(db, runId, projectId, opts = {}) {
25503
25788
  const targetDomain = project.canonicalDomain;
25504
25789
  db.transaction((tx) => {
25505
25790
  tx.delete(backlinkDomains).where(
25506
- and22(eq32(backlinkDomains.projectId, projectId), eq32(backlinkDomains.release, release))
25791
+ and25(eq32(backlinkDomains.projectId, projectId), eq32(backlinkDomains.release, release))
25507
25792
  ).run();
25508
25793
  if (rows.length > 0) {
25509
25794
  const values = rows.map((r) => ({
@@ -25574,7 +25859,7 @@ function computeSummary2(rows) {
25574
25859
 
25575
25860
  // src/discovery-run.ts
25576
25861
  import crypto30 from "crypto";
25577
- import { and as and23, eq as eq33 } from "drizzle-orm";
25862
+ import { and as and26, eq as eq33 } from "drizzle-orm";
25578
25863
  var log8 = createLogger("DiscoveryRun");
25579
25864
  var DEFAULT_SEED_COUNT = 30;
25580
25865
  var QUERIES_PER_INTENT_BUCKET = 6;
@@ -25834,7 +26119,7 @@ function writeDiscoveryInsight(db, input) {
25834
26119
  totalProbes
25835
26120
  });
25836
26121
  db.transaction((tx) => {
25837
- tx.update(insights).set({ dismissed: true }).where(and23(
26122
+ tx.update(insights).set({ dismissed: true }).where(and26(
25838
26123
  eq33(insights.projectId, input.projectId),
25839
26124
  eq33(insights.type, "discovery.basket-divergence"),
25840
26125
  eq33(insights.dismissed, false)
@@ -25878,7 +26163,7 @@ function buildDiscoveryInsightTitle(input) {
25878
26163
  }
25879
26164
 
25880
26165
  // src/commands/backfill.ts
25881
- import { and as and24, eq as eq34, inArray as inArray11 } from "drizzle-orm";
26166
+ import { and as and27, eq as eq34, inArray as inArray11 } from "drizzle-orm";
25882
26167
  var SNAPSHOT_BATCH_SIZE = 500;
25883
26168
  async function backfillAnswerVisibilityCommand(opts) {
25884
26169
  const config = loadConfig();
@@ -25894,7 +26179,7 @@ async function backfillAnswerVisibilityCommand(opts) {
25894
26179
  let reparsed = 0;
25895
26180
  let providerErrors = 0;
25896
26181
  if (scopedProjects.length > 0) {
25897
- const runRows = projectFilter ? db.select({ id: runs.id, projectId: runs.projectId }).from(runs).where(and24(
26182
+ const runRows = projectFilter ? db.select({ id: runs.id, projectId: runs.projectId }).from(runs).where(and27(
25898
26183
  eq34(runs.kind, RunKinds["answer-visibility"]),
25899
26184
  inArray11(runs.projectId, scopedProjects.map((project) => project.id))
25900
26185
  )).all() : db.select({ id: runs.id, projectId: runs.projectId }).from(runs).where(eq34(runs.kind, RunKinds["answer-visibility"])).all();
@@ -26052,7 +26337,7 @@ function backfillNormalizedPaths(db, opts) {
26052
26337
  id: gaTrafficSnapshots.id,
26053
26338
  landingPage: gaTrafficSnapshots.landingPage,
26054
26339
  landingPageNormalized: gaTrafficSnapshots.landingPageNormalized
26055
- }).from(gaTrafficSnapshots).where(baseConditions.length > 0 ? and24(...baseConditions) : void 0).all();
26340
+ }).from(gaTrafficSnapshots).where(baseConditions.length > 0 ? and27(...baseConditions) : void 0).all();
26056
26341
  let updated = 0;
26057
26342
  let unchanged = 0;
26058
26343
  if (rows.length > 0) {
@@ -26124,7 +26409,7 @@ function backfillAiReferralPaths(db, opts) {
26124
26409
  id: gaAiReferrals.id,
26125
26410
  landingPage: gaAiReferrals.landingPage,
26126
26411
  landingPageNormalized: gaAiReferrals.landingPageNormalized
26127
- }).from(gaAiReferrals).where(baseConditions.length > 0 ? and24(...baseConditions) : void 0).all();
26412
+ }).from(gaAiReferrals).where(baseConditions.length > 0 ? and27(...baseConditions) : void 0).all();
26128
26413
  let updated = 0;
26129
26414
  let unchanged = 0;
26130
26415
  if (rows.length > 0) {
@@ -26192,7 +26477,7 @@ function backfillProjectAnswerMentions(db, projectId, opts) {
26192
26477
  const project = db.select().from(projects).where(eq34(projects.id, projectId)).get();
26193
26478
  if (!project) return { examined: 0, updated: 0, mentioned: 0 };
26194
26479
  const competitorDomains = db.select({ domain: competitors.domain }).from(competitors).where(eq34(competitors.projectId, projectId)).all().map((row) => row.domain);
26195
- const runRows = db.select({ id: runs.id }).from(runs).where(and24(eq34(runs.kind, RunKinds["answer-visibility"]), eq34(runs.projectId, projectId))).all();
26480
+ const runRows = db.select({ id: runs.id }).from(runs).where(and27(eq34(runs.kind, RunKinds["answer-visibility"]), eq34(runs.projectId, projectId))).all();
26196
26481
  const runIds = runRows.map((r) => r.id);
26197
26482
  let examined = 0;
26198
26483
  let updated = 0;
@@ -26343,7 +26628,7 @@ function readStoredGroundingSources(rawResponse) {
26343
26628
  return result;
26344
26629
  }
26345
26630
  async function backfillInsightsCommand(project, opts) {
26346
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-ADZRFCGO.js");
26631
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-TY7IPRST.js");
26347
26632
  const config = loadConfig();
26348
26633
  const db = createClient(config.database);
26349
26634
  migrate(db);
@@ -26492,7 +26777,7 @@ var ProviderRegistry = class {
26492
26777
 
26493
26778
  // src/scheduler.ts
26494
26779
  import cron from "node-cron";
26495
- import { and as and25, eq as eq35 } from "drizzle-orm";
26780
+ import { and as and28, eq as eq35 } from "drizzle-orm";
26496
26781
  var log9 = createLogger("Scheduler");
26497
26782
  function taskKey(projectId, kind) {
26498
26783
  return `${projectId}::${kind}`;
@@ -26537,7 +26822,7 @@ var Scheduler = class {
26537
26822
  this.stopTask(key, existing, "Stopped");
26538
26823
  this.tasks.delete(key);
26539
26824
  }
26540
- const schedule = this.db.select().from(schedules).where(and25(eq35(schedules.projectId, projectId), eq35(schedules.kind, kind))).get();
26825
+ const schedule = this.db.select().from(schedules).where(and28(eq35(schedules.projectId, projectId), eq35(schedules.kind, kind))).get();
26541
26826
  if (schedule && schedule.enabled === 1) {
26542
26827
  this.registerCronTask(schedule);
26543
26828
  }
@@ -26661,7 +26946,7 @@ var Scheduler = class {
26661
26946
  };
26662
26947
 
26663
26948
  // src/notifier.ts
26664
- import { eq as eq36, desc as desc16, and as and26, inArray as inArray12, or as or5 } from "drizzle-orm";
26949
+ import { eq as eq36, desc as desc16, and as and29, inArray as inArray12, or as or5 } from "drizzle-orm";
26665
26950
  import crypto31 from "crypto";
26666
26951
  var log10 = createLogger("Notifier");
26667
26952
  var Notifier = class {
@@ -26768,7 +27053,7 @@ var Notifier = class {
26768
27053
  computeTransitions(runId, projectId) {
26769
27054
  const thisRun = this.db.select().from(runs).where(eq36(runs.id, runId)).get();
26770
27055
  if (!thisRun) return [];
26771
- const groupSiblings = this.db.select().from(runs).where(and26(
27056
+ const groupSiblings = this.db.select().from(runs).where(and29(
26772
27057
  eq36(runs.projectId, projectId),
26773
27058
  eq36(runs.kind, thisRun.kind),
26774
27059
  eq36(runs.createdAt, thisRun.createdAt)
@@ -26794,7 +27079,7 @@ var Notifier = class {
26794
27079
  );
26795
27080
  const RECENT_FETCH_LIMIT = Math.max(8, locationCount * 4);
26796
27081
  const recentRuns = this.db.select().from(runs).where(
26797
- and26(
27082
+ and29(
26798
27083
  eq36(runs.projectId, projectId),
26799
27084
  eq36(runs.kind, thisRun.kind),
26800
27085
  or5(eq36(runs.status, "completed"), eq36(runs.status, "partial"))
@@ -26907,6 +27192,10 @@ var RunCoordinator = class {
26907
27192
  async onRunCompleted(runId, projectId) {
26908
27193
  const runRow = this.db.select().from(runs).where(eq37(runs.id, runId)).get();
26909
27194
  const kind = runRow?.kind ?? RunKinds["answer-visibility"];
27195
+ if (runRow?.trigger === RunTriggers.probe) {
27196
+ log11.info("probe.skip-side-effects", { runId, projectId, kind });
27197
+ return;
27198
+ }
26910
27199
  let insightCount = 0;
26911
27200
  let criticalOrHigh = 0;
26912
27201
  if (kind === RunKinds["answer-visibility"]) {
@@ -27333,7 +27622,7 @@ function resolveSessionProviderAndModel(config, opts) {
27333
27622
 
27334
27623
  // src/agent/memory-store.ts
27335
27624
  import crypto32 from "crypto";
27336
- import { and as and27, desc as desc17, eq as eq38, like as like2, sql as sql15 } from "drizzle-orm";
27625
+ import { and as and30, desc as desc17, eq as eq38, like as like2, sql as sql15 } from "drizzle-orm";
27337
27626
  var COMPACTION_KEY_PREFIX = "compaction:";
27338
27627
  var COMPACTION_NOTES_PER_SESSION = 3;
27339
27628
  function rowToDto2(row) {
@@ -27378,12 +27667,12 @@ function upsertMemoryEntry(db, args) {
27378
27667
  updatedAt: now
27379
27668
  }
27380
27669
  }).run();
27381
- const row = db.select().from(agentMemory).where(and27(eq38(agentMemory.projectId, args.projectId), eq38(agentMemory.key, args.key))).get();
27670
+ const row = db.select().from(agentMemory).where(and30(eq38(agentMemory.projectId, args.projectId), eq38(agentMemory.key, args.key))).get();
27382
27671
  if (!row) throw new Error("memory upsert produced no row");
27383
27672
  return rowToDto2(row);
27384
27673
  }
27385
27674
  function deleteMemoryEntry(db, projectId, key) {
27386
- const result = db.delete(agentMemory).where(and27(eq38(agentMemory.projectId, projectId), eq38(agentMemory.key, key))).run();
27675
+ const result = db.delete(agentMemory).where(and30(eq38(agentMemory.projectId, projectId), eq38(agentMemory.key, key))).run();
27387
27676
  const changes = result.changes ?? 0;
27388
27677
  return changes > 0;
27389
27678
  }
@@ -27412,7 +27701,7 @@ function writeCompactionNote(db, args) {
27412
27701
  }).run();
27413
27702
  const sessionPrefix = `${COMPACTION_KEY_PREFIX}${args.sessionId}:`;
27414
27703
  const existing = tx.select({ id: agentMemory.id, updatedAt: agentMemory.updatedAt }).from(agentMemory).where(
27415
- and27(
27704
+ and30(
27416
27705
  eq38(agentMemory.projectId, args.projectId),
27417
27706
  like2(agentMemory.key, `${sessionPrefix}%`)
27418
27707
  )
@@ -27421,7 +27710,7 @@ function writeCompactionNote(db, args) {
27421
27710
  if (stale.length > 0) {
27422
27711
  tx.delete(agentMemory).where(sql15`${agentMemory.id} IN (${sql15.join(stale.map((s) => sql15`${s}`), sql15`, `)})`).run();
27423
27712
  }
27424
- const row = tx.select().from(agentMemory).where(and27(eq38(agentMemory.projectId, args.projectId), eq38(agentMemory.key, key))).get();
27713
+ const row = tx.select().from(agentMemory).where(and30(eq38(agentMemory.projectId, args.projectId), eq38(agentMemory.key, key))).get();
27425
27714
  if (row) inserted = rowToDto2(row);
27426
27715
  });
27427
27716
  if (!inserted) throw new Error("compaction note write produced no row");