@ainyc/canonry 4.112.7 → 4.114.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/assets/assets/{BacklinksPage-AYTE7he1.js → BacklinksPage-pxm5QdkH.js} +1 -1
  2. package/assets/assets/{ChartPrimitives-J0xH87kk.js → ChartPrimitives-lKnj_JyP.js} +1 -1
  3. package/assets/assets/ProjectPage-38ZIpkmq.js +7 -0
  4. package/assets/assets/{RunRow-Duz6GoZ0.js → RunRow-BCinrp7o.js} +1 -1
  5. package/assets/assets/{RunsPage-DpocjSZ-.js → RunsPage-CRoqsHH6.js} +1 -1
  6. package/assets/assets/SettingsPage-BEJ39Z1y.js +1 -0
  7. package/assets/assets/{TrafficPage-B5c8opWF.js → TrafficPage-DwlIys8k.js} +1 -1
  8. package/assets/assets/{TrafficSourceDetailPage-D9JPwzH-.js → TrafficSourceDetailPage-BxZdMbPs.js} +1 -1
  9. package/assets/assets/{arrow-left-DMukIffh.js → arrow-left-Bh1K7Q5q.js} +1 -1
  10. package/assets/assets/{extract-error-message-CVln-Uf_.js → extract-error-message-CC-RB1fH.js} +1 -1
  11. package/assets/assets/index--YS3kkht.js +210 -0
  12. package/assets/assets/index-CReX5Jn9.css +1 -0
  13. package/assets/assets/{trash-2-BbhOWhnf.js → trash-2-uW1qyzpW.js} +1 -1
  14. package/assets/index.html +2 -2
  15. package/dist/{chunk-D5PEINWZ.js → chunk-3VSTTH4M.js} +303 -185
  16. package/dist/{chunk-K2XOEBSH.js → chunk-DUBZH5JW.js} +1 -1
  17. package/dist/{chunk-DBZLOLYT.js → chunk-VEUBAZRG.js} +8 -1
  18. package/dist/{chunk-FVELOZTK.js → chunk-WMWZW34J.js} +71 -9
  19. package/dist/cli.js +4 -4
  20. package/dist/index.d.ts +9 -0
  21. package/dist/index.js +4 -4
  22. package/dist/{intelligence-service-ZPY7NIKR.js → intelligence-service-I5EQ77KZ.js} +2 -2
  23. package/dist/mcp.js +2 -2
  24. package/package.json +9 -9
  25. package/assets/assets/ProjectPage-BcqfsS5X.js +0 -7
  26. package/assets/assets/SettingsPage-CboDfSRx.js +0 -1
  27. package/assets/assets/index-DNoISJxr.js +0 -210
  28. package/assets/assets/index-l-PAIV0A.css +0 -1
@@ -179,6 +179,7 @@ import {
179
179
  mapWithConcurrency,
180
180
  mentionStateFromAnswerMentioned,
181
181
  missingDependency,
182
+ normalizeIdTokens,
182
183
  normalizeProjectAliases,
183
184
  normalizeProjectDomain,
184
185
  normalizeQueryText,
@@ -237,6 +238,7 @@ import {
237
238
  snapshotReportSchema,
238
239
  snapshotRequestSchema,
239
240
  sourceBreakdownDtoSchema,
241
+ splitList,
240
242
  sumInfraHits,
241
243
  summarizeCheckResults,
242
244
  surfaceClassFromCompetitorType,
@@ -271,10 +273,10 @@ import {
271
273
  wordpressSchemaDeployResultDtoSchema,
272
274
  wordpressSchemaStatusResultDtoSchema,
273
275
  wordpressStatusDtoSchema
274
- } from "./chunk-DBZLOLYT.js";
276
+ } from "./chunk-VEUBAZRG.js";
275
277
 
276
278
  // src/intelligence-service.ts
277
- import { eq as eq38, desc as desc18, asc as asc6, and as and28, ne as ne5, or as or6, inArray as inArray14, gte as gte7, lte as lte4 } from "drizzle-orm";
279
+ import { eq as eq38, desc as desc18, asc as asc6, and as and29, ne as ne5, or as or6, inArray as inArray14, gte as gte7, lte as lte4 } from "drizzle-orm";
278
280
 
279
281
  // ../db/src/client.ts
280
282
  import { mkdirSync } from "fs";
@@ -5847,6 +5849,82 @@ function parseCookies(header) {
5847
5849
  return cookies;
5848
5850
  }, {});
5849
5851
  }
5852
+ function queryValue(request, key) {
5853
+ const raw = request.query?.[key];
5854
+ if (typeof raw === "string") return raw;
5855
+ if (Array.isArray(raw) && typeof raw[0] === "string") return raw[0];
5856
+ return void 0;
5857
+ }
5858
+ function requestEmbedProjectTabs(request, fallback) {
5859
+ const headerTabs = normalizeIdTokens(splitList(request.headers["x-canonry-embed-tabs"]));
5860
+ if (headerTabs) return headerTabs;
5861
+ return fallback && fallback.length > 0 ? [...fallback] : void 0;
5862
+ }
5863
+ function projectRouteRest(url) {
5864
+ const match = url.match(/\/projects\/[^/]+(?:\/([^?#]*))?$/);
5865
+ if (!match) return null;
5866
+ return match[1] ?? "";
5867
+ }
5868
+ function isGlobalAnswerVisibilityRunsList(request, url) {
5869
+ if (!url.endsWith("/runs")) return false;
5870
+ const kind = queryValue(request, "kind");
5871
+ return kind === RunKinds["answer-visibility"];
5872
+ }
5873
+ function isAnswerVisibilityRunsList(request, rest) {
5874
+ if (rest !== "runs") return false;
5875
+ const kind = queryValue(request, "kind");
5876
+ return kind === RunKinds["answer-visibility"];
5877
+ }
5878
+ function isAnswerVisibilityRunDetail(request, url) {
5879
+ const runMatch = url.match(/\/runs\/([^/?#]+)$/);
5880
+ if (!runMatch) return false;
5881
+ const run = request.server.db.select({ kind: runs.kind }).from(runs).where(eq(runs.id, decodeURIComponent(runMatch[1]))).get();
5882
+ return !run || run.kind === RunKinds["answer-visibility"];
5883
+ }
5884
+ function isProjectShellRead(request, url) {
5885
+ if (url.endsWith("/projects")) return true;
5886
+ if (isGlobalAnswerVisibilityRunsList(request, url)) return true;
5887
+ const rest = projectRouteRest(url);
5888
+ if (rest === null) return isAnswerVisibilityRunDetail(request, url);
5889
+ return rest === "" || isAnswerVisibilityRunsList(request, rest);
5890
+ }
5891
+ function isOverviewRead(url) {
5892
+ const rest = projectRouteRest(url);
5893
+ if (rest === null) return false;
5894
+ return (/* @__PURE__ */ new Set([
5895
+ "queries",
5896
+ "competitors",
5897
+ "timeline",
5898
+ "overview",
5899
+ "analytics/metrics",
5900
+ "google/gsc/coverage",
5901
+ "bing/coverage",
5902
+ "insights",
5903
+ "citations/visibility"
5904
+ ])).has(rest);
5905
+ }
5906
+ function isTechnicalAeoRead(url) {
5907
+ const rest = projectRouteRest(url);
5908
+ return rest === "technical-aeo" || rest === "technical-aeo/pages" || rest === "technical-aeo/trend";
5909
+ }
5910
+ function isReportRead(url) {
5911
+ const rest = projectRouteRest(url);
5912
+ return rest === "report" || rest === "report.html";
5913
+ }
5914
+ function enforceEmbedProjectTabs(request, configuredTabs) {
5915
+ const tabs = requestEmbedProjectTabs(request, configuredTabs);
5916
+ if (!tabs || tabs.length === 0) return;
5917
+ if (request.method === "OPTIONS") return;
5918
+ if (WRITE_METHODS.has(request.method)) {
5919
+ throw forbidden("This endpoint is not available in embed mode.");
5920
+ }
5921
+ const url = request.url.split("?")[0];
5922
+ if (isProjectShellRead(request, url)) return;
5923
+ if (tabs.includes("overview") && isOverviewRead(url)) return;
5924
+ if (tabs.includes("technical-aeo") && isTechnicalAeoRead(url)) return;
5925
+ if (tabs.includes("report") && isReportRead(url)) return;
5926
+ throw forbidden("This endpoint is not available for the configured embed tabs.");
5927
+ }
5850
5928
  async function authPlugin(app, opts = {}) {
5851
5929
  app.addHook("onRequest", async (request) => {
5852
5930
  const url = request.url.split("?")[0];
@@ -5884,6 +5962,7 @@ async function authPlugin(app, opts = {}) {
5884
5962
  if (isReadOnlyKey(scopes) && WRITE_METHODS.has(request.method)) {
5885
5963
  throw forbidden("This API key is read-only and cannot perform write operations.");
5886
5964
  }
5965
+ enforceEmbedProjectTabs(request, opts.embedProjectTabs);
5887
5966
  if (key.projectId) {
5888
5967
  const match = url.match(/\/projects\/([^/?#]+)/);
5889
5968
  if (match) {
@@ -6291,7 +6370,7 @@ function aliasArraysEqual(a, b) {
6291
6370
 
6292
6371
  // ../api-routes/src/queries.ts
6293
6372
  import crypto5 from "crypto";
6294
- import { eq as eq4, inArray, sql as sql4 } from "drizzle-orm";
6373
+ import { and, eq as eq4, inArray, sql as sql4 } from "drizzle-orm";
6295
6374
  function preserveSnapshotQueryText(tx, projectId, queryIds) {
6296
6375
  const candidates = queryIds && queryIds.length > 0 ? tx.select({ id: queries.id, text: queries.query }).from(queries).where(inArray(queries.id, queryIds)).all() : tx.select({ id: queries.id, text: queries.query }).from(queries).where(eq4(queries.projectId, projectId)).all();
6297
6376
  for (const q of candidates) {
@@ -6391,6 +6470,26 @@ async function queryRoutes(app, opts) {
6391
6470
  const rows = app.db.select().from(queries).where(eq4(queries.projectId, project.id)).all();
6392
6471
  return reply.send(rows.map((r) => ({ id: r.id, query: r.query, createdAt: r.createdAt })));
6393
6472
  });
6473
+ app.delete("/projects/:name/queries/:id", async (request, reply) => {
6474
+ const project = resolveProject(app.db, request.params.name);
6475
+ const query = app.db.select().from(queries).where(and(eq4(queries.projectId, project.id), eq4(queries.id, request.params.id))).get();
6476
+ if (!query) {
6477
+ throw notFound("Query", request.params.id);
6478
+ }
6479
+ app.db.transaction((tx) => {
6480
+ preserveSnapshotQueryText(tx, project.id, [query.id]);
6481
+ tx.delete(queries).where(eq4(queries.id, query.id)).run();
6482
+ writeAuditLog(tx, auditFromRequest(request, {
6483
+ projectId: project.id,
6484
+ actor: "api",
6485
+ action: "queries.deleted",
6486
+ entityType: "query",
6487
+ entityId: query.id,
6488
+ diff: { deleted: [query.query] }
6489
+ }));
6490
+ });
6491
+ return reply.status(204).send();
6492
+ });
6394
6493
  app.post("/projects/:name/queries", async (request, reply) => {
6395
6494
  const project = resolveProject(app.db, request.params.name);
6396
6495
  const body = request.body;
@@ -6730,12 +6829,12 @@ function parseCompetitorBatch(value) {
6730
6829
 
6731
6830
  // ../api-routes/src/runs.ts
6732
6831
  import crypto8 from "crypto";
6733
- import { and as and2, eq as eq7, asc, desc, or as or2, sql as sql5 } from "drizzle-orm";
6832
+ import { and as and3, eq as eq7, asc, desc, or as or2, sql as sql5 } from "drizzle-orm";
6734
6833
  import { gte } from "drizzle-orm";
6735
6834
 
6736
6835
  // ../api-routes/src/run-queue.ts
6737
6836
  import crypto7 from "crypto";
6738
- import { and, eq as eq6, or } from "drizzle-orm";
6837
+ import { and as and2, eq as eq6, or } from "drizzle-orm";
6739
6838
  function queueRunIfProjectIdle(db, params) {
6740
6839
  const createdAt = params.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
6741
6840
  const kind = params.kind ?? "answer-visibility";
@@ -6743,7 +6842,7 @@ function queueRunIfProjectIdle(db, params) {
6743
6842
  const runId = crypto7.randomUUID();
6744
6843
  return db.transaction((tx) => {
6745
6844
  const activeRun = tx.select().from(runs).where(
6746
- and(
6845
+ and2(
6747
6846
  eq6(runs.projectId, params.projectId),
6748
6847
  or(eq6(runs.status, "queued"), eq6(runs.status, "running"))
6749
6848
  )
@@ -6826,7 +6925,7 @@ async function runRoutes(app, opts) {
6826
6925
  throw validationError("No locations configured for this project");
6827
6926
  }
6828
6927
  const result = app.db.transaction((tx) => {
6829
- const activeRun = tx.select({ id: runs.id }).from(runs).where(and2(
6928
+ const activeRun = tx.select({ id: runs.id }).from(runs).where(and3(
6830
6929
  eq7(runs.projectId, project.id),
6831
6930
  or2(eq7(runs.status, "queued"), eq7(runs.status, "running"))
6832
6931
  )).get();
@@ -6899,15 +6998,15 @@ async function runRoutes(app, opts) {
6899
6998
  const parsedLimit = parseInt(request.query.limit ?? "", 10);
6900
6999
  const limit = Number.isNaN(parsedLimit) || parsedLimit <= 0 ? void 0 : parsedLimit;
6901
7000
  const kind = parseListKind(request.query.kind);
6902
- const where = kind ? and2(eq7(runs.projectId, project.id), eq7(runs.kind, kind)) : eq7(runs.projectId, project.id);
7001
+ const where = kind ? and3(eq7(runs.projectId, project.id), eq7(runs.kind, kind)) : eq7(runs.projectId, project.id);
6903
7002
  const rows = limit == null ? app.db.select().from(runs).where(where).orderBy(asc(runs.createdAt)).all() : app.db.select().from(runs).where(where).orderBy(desc(runs.createdAt)).limit(limit).all().reverse();
6904
7003
  return reply.send(rows.map(formatRun));
6905
7004
  });
6906
7005
  app.get("/projects/:name/runs/latest", async (request, reply) => {
6907
7006
  const project = resolveProject(app.db, request.params.name);
6908
- const countRow = app.db.select({ count: sql5`count(*)` }).from(runs).where(and2(eq7(runs.projectId, project.id), notProbeRun())).get();
7007
+ const countRow = app.db.select({ count: sql5`count(*)` }).from(runs).where(and3(eq7(runs.projectId, project.id), notProbeRun())).get();
6909
7008
  const totalRuns = countRow?.count ?? 0;
6910
- const latestRun = app.db.select().from(runs).where(and2(eq7(runs.projectId, project.id), notProbeRun())).orderBy(desc(runs.createdAt), desc(runs.id)).limit(1).get();
7009
+ const latestRun = app.db.select().from(runs).where(and3(eq7(runs.projectId, project.id), notProbeRun())).orderBy(desc(runs.createdAt), desc(runs.id)).limit(1).get();
6911
7010
  if (!latestRun) {
6912
7011
  return reply.send({ totalRuns: 0, run: null });
6913
7012
  }
@@ -6926,7 +7025,7 @@ async function runRoutes(app, opts) {
6926
7025
  if (kind) filters.push(eq7(runs.kind, kind));
6927
7026
  const scopedProjectId = request.apiKey?.projectId;
6928
7027
  if (scopedProjectId) filters.push(eq7(runs.projectId, scopedProjectId));
6929
- const rows = app.db.select().from(runs).where(and2(...filters)).orderBy(desc(runs.createdAt), desc(runs.id)).limit(limit).all();
7028
+ const rows = app.db.select().from(runs).where(and3(...filters)).orderBy(desc(runs.createdAt), desc(runs.id)).limit(limit).all();
6930
7029
  return reply.send(rows.map(formatRun));
6931
7030
  });
6932
7031
  app.post("/runs", async (request, reply) => {
@@ -7137,7 +7236,7 @@ function loadRunDetail(app, run) {
7137
7236
 
7138
7237
  // ../api-routes/src/apply.ts
7139
7238
  import crypto10 from "crypto";
7140
- import { and as and3, eq as eq8 } from "drizzle-orm";
7239
+ import { and as and4, eq as eq8 } from "drizzle-orm";
7141
7240
 
7142
7241
  // ../api-routes/src/schedule-utils.ts
7143
7242
  import { CronExpressionParser } from "cron-parser";
@@ -7580,7 +7679,7 @@ async function applyRoutes(app, opts) {
7580
7679
  });
7581
7680
  const AV_KIND = SchedulableRunKinds["answer-visibility"];
7582
7681
  if (resolvedSchedule) {
7583
- const existingSched = tx.select().from(schedules).where(and3(eq8(schedules.projectId, projectId), eq8(schedules.kind, AV_KIND))).get();
7682
+ const existingSched = tx.select().from(schedules).where(and4(eq8(schedules.projectId, projectId), eq8(schedules.kind, AV_KIND))).get();
7584
7683
  if (existingSched) {
7585
7684
  tx.update(schedules).set({
7586
7685
  cronExpr: resolvedSchedule.cronExpr,
@@ -7606,9 +7705,9 @@ async function applyRoutes(app, opts) {
7606
7705
  }
7607
7706
  scheduleAction = "upsert";
7608
7707
  } else if (deleteSchedule) {
7609
- const existingSched = tx.select().from(schedules).where(and3(eq8(schedules.projectId, projectId), eq8(schedules.kind, AV_KIND))).get();
7708
+ const existingSched = tx.select().from(schedules).where(and4(eq8(schedules.projectId, projectId), eq8(schedules.kind, AV_KIND))).get();
7610
7709
  if (existingSched) {
7611
- tx.delete(schedules).where(and3(eq8(schedules.projectId, projectId), eq8(schedules.kind, AV_KIND))).run();
7710
+ tx.delete(schedules).where(and4(eq8(schedules.projectId, projectId), eq8(schedules.kind, AV_KIND))).run();
7612
7711
  scheduleAction = "delete";
7613
7712
  }
7614
7713
  }
@@ -7692,7 +7791,7 @@ function normalizeCompetitorList2(domains) {
7692
7791
  }
7693
7792
 
7694
7793
  // ../api-routes/src/history.ts
7695
- import { and as and4, eq as eq9, desc as desc2, inArray as inArray2 } from "drizzle-orm";
7794
+ import { and as and5, eq as eq9, desc as desc2, inArray as inArray2 } from "drizzle-orm";
7696
7795
 
7697
7796
  // ../api-routes/src/notification-redaction.ts
7698
7797
  var REDACTED_URL = {
@@ -7750,7 +7849,7 @@ async function historyRoutes(app) {
7750
7849
  const project = resolveProject(app.db, request.params.name);
7751
7850
  const limit = parseInt(request.query.limit ?? "50", 10);
7752
7851
  const offset = parseInt(request.query.offset ?? "0", 10);
7753
- const projectRuns = app.db.select({ id: runs.id }).from(runs).where(and4(eq9(runs.projectId, project.id), notProbeRun())).all();
7852
+ const projectRuns = app.db.select({ id: runs.id }).from(runs).where(and5(eq9(runs.projectId, project.id), notProbeRun())).all();
7754
7853
  if (projectRuns.length === 0) {
7755
7854
  return reply.send({ snapshots: [], total: 0 });
7756
7855
  }
@@ -7799,7 +7898,7 @@ async function historyRoutes(app) {
7799
7898
  app.get("/projects/:name/timeline", async (request, reply) => {
7800
7899
  const project = resolveProject(app.db, request.params.name);
7801
7900
  const projectQueries = app.db.select().from(queries).where(eq9(queries.projectId, project.id)).all();
7802
- const projectRuns = app.db.select().from(runs).where(and4(eq9(runs.projectId, project.id), notProbeRun())).orderBy(runs.createdAt).all();
7901
+ const projectRuns = app.db.select().from(runs).where(and5(eq9(runs.projectId, project.id), notProbeRun())).orderBy(runs.createdAt).all();
7803
7902
  if (projectRuns.length === 0 || projectQueries.length === 0) {
7804
7903
  return reply.send([]);
7805
7904
  }
@@ -8010,13 +8109,13 @@ function formatAuditEntry(row) {
8010
8109
  }
8011
8110
 
8012
8111
  // ../api-routes/src/analytics.ts
8013
- import { and as and5, eq as eq10, desc as desc3, inArray as inArray3 } from "drizzle-orm";
8112
+ import { and as and6, eq as eq10, desc as desc3, inArray as inArray3 } from "drizzle-orm";
8014
8113
  async function analyticsRoutes(app) {
8015
8114
  app.get("/projects/:name/analytics/metrics", async (request, reply) => {
8016
8115
  const project = resolveProject(app.db, request.params.name);
8017
8116
  const window = parseWindow(request.query.window);
8018
8117
  const cutoff = windowCutoff(window);
8019
- 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);
8118
+ const projectRuns = app.db.select().from(runs).where(and6(eq10(runs.projectId, project.id), notProbeRun())).orderBy(runs.createdAt).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
8020
8119
  if (projectRuns.length === 0) {
8021
8120
  return reply.send({
8022
8121
  window,
@@ -8068,14 +8167,14 @@ async function analyticsRoutes(app) {
8068
8167
  const project = resolveProject(app.db, request.params.name);
8069
8168
  const window = parseWindow(request.query.window);
8070
8169
  const cutoff = windowCutoff(window);
8071
- 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");
8170
+ const completedRuns = app.db.select().from(runs).where(and6(eq10(runs.projectId, project.id), notProbeRun())).orderBy(desc3(runs.createdAt), desc3(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial");
8072
8171
  const latestGroup = groupRunsByCreatedAt(completedRuns)[0] ?? [];
8073
8172
  const latestGroupRunIds = latestGroup.map((r) => r.id);
8074
8173
  const latestRun = pickGroupRepresentative(latestGroup);
8075
8174
  if (!latestRun) {
8076
8175
  return reply.send({ cited: [], gap: [], uncited: [], mentionedQueries: [], mentionGap: [], notMentioned: [], runId: "", window });
8077
8176
  }
8078
- 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);
8177
+ const windowRuns = app.db.select().from(runs).where(and6(eq10(runs.projectId, project.id), notProbeRun())).orderBy(runs.createdAt).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
8079
8178
  const windowRunIds = windowRuns.map((r) => r.id);
8080
8179
  const runIdToCreatedAt = new Map(windowRuns.map((r) => [r.id, r.createdAt]));
8081
8180
  const consistencyMap = /* @__PURE__ */ new Map();
@@ -8206,7 +8305,7 @@ async function analyticsRoutes(app) {
8206
8305
  const mapped = surfaceClassFromCompetitorType(row.competitorType);
8207
8306
  if (mapped) storedSurfaceClasses.set(normalizeProjectDomain(row.domain), mapped);
8208
8307
  }
8209
- 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);
8308
+ const windowRuns = app.db.select().from(runs).where(and6(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);
8210
8309
  if (windowRuns.length === 0) {
8211
8310
  return reply.send({
8212
8311
  overall: [],
@@ -8471,7 +8570,7 @@ function buildCategoryCounts(counts2) {
8471
8570
  }
8472
8571
 
8473
8572
  // ../api-routes/src/intelligence.ts
8474
- import { eq as eq11, desc as desc4, and as and6, inArray as inArray4, like } from "drizzle-orm";
8573
+ import { eq as eq11, desc as desc4, and as and7, inArray as inArray4, like } from "drizzle-orm";
8475
8574
  var SEVERITY_RANK = { low: 0, medium: 1, high: 2, critical: 3 };
8476
8575
  function severitiesAtOrAbove(min) {
8477
8576
  const floor = SEVERITY_RANK[min];
@@ -8611,7 +8710,7 @@ async function intelligenceRoutes(app) {
8611
8710
  }
8612
8711
  limit = parsed;
8613
8712
  }
8614
- const rows = app.db.select().from(insights).where(conditions.length === 1 ? conditions[0] : and6(...conditions)).orderBy(desc4(insights.createdAt)).all();
8713
+ const rows = app.db.select().from(insights).where(conditions.length === 1 ? conditions[0] : and7(...conditions)).orderBy(desc4(insights.createdAt)).all();
8615
8714
  const showDismissed = request.query.dismissed === "true";
8616
8715
  let result = rows.filter((r) => showDismissed || !r.dismissed).map(mapInsightRow);
8617
8716
  if (limit !== void 0) result = result.slice(0, limit);
@@ -8636,7 +8735,7 @@ async function intelligenceRoutes(app) {
8636
8735
  });
8637
8736
  app.get("/projects/:name/health/latest", async (request, reply) => {
8638
8737
  const project = resolveProject(app.db, request.params.name);
8639
- const projectVisRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and6(
8738
+ const projectVisRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and7(
8640
8739
  eq11(runs.projectId, project.id),
8641
8740
  eq11(runs.kind, RunKinds["answer-visibility"]),
8642
8741
  inArray4(runs.status, [RunStatuses.completed, RunStatuses.partial]),
@@ -8647,7 +8746,7 @@ async function intelligenceRoutes(app) {
8647
8746
  const latestGroup = groupRunsByCreatedAt(projectVisRuns)[0] ?? [];
8648
8747
  const latestGroupRunIds = latestGroup.map((r) => r.id);
8649
8748
  if (latestGroupRunIds.length > 0) {
8650
- const groupRows = app.db.select().from(healthSnapshots).where(and6(
8749
+ const groupRows = app.db.select().from(healthSnapshots).where(and7(
8651
8750
  eq11(healthSnapshots.projectId, project.id),
8652
8751
  inArray4(healthSnapshots.runId, latestGroupRunIds)
8653
8752
  )).all();
@@ -8671,14 +8770,14 @@ async function intelligenceRoutes(app) {
8671
8770
  }
8672
8771
 
8673
8772
  // ../api-routes/src/report.ts
8674
- import { and as and10, desc as desc7, eq as eq15, gte as gte2, inArray as inArray6, lt, lte, ne as ne2, or as or3, sql as sql7 } from "drizzle-orm";
8773
+ import { and as and11, desc as desc7, eq as eq15, gte as gte2, inArray as inArray6, lt, lte, ne as ne2, or as or3, sql as sql7 } from "drizzle-orm";
8675
8774
 
8676
8775
  // ../api-routes/src/content.ts
8677
8776
  import crypto11 from "crypto";
8678
- import { and as and8, desc as desc6, eq as eq13 } from "drizzle-orm";
8777
+ import { and as and9, desc as desc6, eq as eq13 } from "drizzle-orm";
8679
8778
 
8680
8779
  // ../api-routes/src/content-data.ts
8681
- import { and as and7, eq as eq12, desc as desc5, inArray as inArray5 } from "drizzle-orm";
8780
+ import { and as and8, eq as eq12, desc as desc5, inArray as inArray5 } from "drizzle-orm";
8682
8781
  var RECENT_RUNS_WINDOW = 5;
8683
8782
  function loadOrchestratorInput(db, project, locationFilter = void 0) {
8684
8783
  const projectId = project.id;
@@ -8808,7 +8907,7 @@ function listCompetitorDomains(db, projectId) {
8808
8907
  }
8809
8908
  function listRecentAnswerVisibilityRunIds(db, projectId, limit, locationFilter) {
8810
8909
  const rows = db.select({ id: runs.id, location: runs.location }).from(runs).where(
8811
- and7(
8910
+ and8(
8812
8911
  eq12(runs.projectId, projectId),
8813
8912
  eq12(runs.kind, RunKinds["answer-visibility"]),
8814
8913
  // Queued/running/failed/cancelled runs may have partial or no
@@ -9179,7 +9278,7 @@ async function contentRoutes(app, opts = {}) {
9179
9278
  dismissedAt: now
9180
9279
  }
9181
9280
  }).run();
9182
- const row = app.db.select().from(contentTargetDismissals).where(and8(
9281
+ const row = app.db.select().from(contentTargetDismissals).where(and9(
9183
9282
  eq13(contentTargetDismissals.projectId, project.id),
9184
9283
  eq13(contentTargetDismissals.targetRef, targetRef)
9185
9284
  )).get();
@@ -9189,7 +9288,7 @@ async function contentRoutes(app, opts = {}) {
9189
9288
  app.delete("/projects/:name/content/dismissals/:targetRef", async (request, reply) => {
9190
9289
  const project = resolveProject(app.db, request.params.name);
9191
9290
  const { targetRef } = request.params;
9192
- const result = app.db.delete(contentTargetDismissals).where(and8(
9291
+ const result = app.db.delete(contentTargetDismissals).where(and9(
9193
9292
  eq13(contentTargetDismissals.projectId, project.id),
9194
9293
  eq13(contentTargetDismissals.targetRef, targetRef)
9195
9294
  )).run();
@@ -9200,7 +9299,7 @@ async function contentRoutes(app, opts = {}) {
9200
9299
  });
9201
9300
  app.get("/projects/:name/content/recommendations/:targetRef/analysis", async (request, reply) => {
9202
9301
  const project = resolveProject(app.db, request.params.name);
9203
- const row = app.db.select().from(recommendationExplanations).where(and8(
9302
+ const row = app.db.select().from(recommendationExplanations).where(and9(
9204
9303
  eq13(recommendationExplanations.projectId, project.id),
9205
9304
  eq13(recommendationExplanations.targetRef, request.params.targetRef)
9206
9305
  )).orderBy(desc6(recommendationExplanations.generatedAt)).limit(1).get();
@@ -9228,7 +9327,7 @@ async function contentRoutes(app, opts = {}) {
9228
9327
  throw notFound("contentRecommendation", targetRef);
9229
9328
  }
9230
9329
  if (!body.forceRefresh) {
9231
- const cached = app.db.select().from(recommendationExplanations).where(and8(
9330
+ const cached = app.db.select().from(recommendationExplanations).where(and9(
9232
9331
  eq13(recommendationExplanations.projectId, project.id),
9233
9332
  eq13(recommendationExplanations.targetRef, targetRef)
9234
9333
  )).orderBy(desc6(recommendationExplanations.generatedAt)).limit(1).get();
@@ -9267,7 +9366,7 @@ async function contentRoutes(app, opts = {}) {
9267
9366
  generatedAt: now
9268
9367
  }
9269
9368
  }).run();
9270
- const row = app.db.select().from(recommendationExplanations).where(and8(
9369
+ const row = app.db.select().from(recommendationExplanations).where(and9(
9271
9370
  eq13(recommendationExplanations.projectId, project.id),
9272
9371
  eq13(recommendationExplanations.targetRef, targetRef),
9273
9372
  eq13(recommendationExplanations.promptVersion, result.promptVersion)
@@ -9351,7 +9450,7 @@ async function contentRoutes(app, opts = {}) {
9351
9450
  generatedAt: now
9352
9451
  }
9353
9452
  }).run();
9354
- const row = app.db.select().from(recommendationBriefs).where(and8(
9453
+ const row = app.db.select().from(recommendationBriefs).where(and9(
9355
9454
  eq13(recommendationBriefs.projectId, project.id),
9356
9455
  eq13(recommendationBriefs.targetRef, targetRef),
9357
9456
  eq13(recommendationBriefs.promptVersion, result.promptVersion)
@@ -9381,7 +9480,7 @@ function lookupCachedBrief(db, projectId, targetRef, promptVersion) {
9381
9480
  if (promptVersion !== void 0) {
9382
9481
  conditions.push(eq13(recommendationBriefs.promptVersion, promptVersion));
9383
9482
  }
9384
- return db.select().from(recommendationBriefs).where(and8(...conditions)).orderBy(desc6(recommendationBriefs.generatedAt)).limit(1).get();
9483
+ return db.select().from(recommendationBriefs).where(and9(...conditions)).orderBy(desc6(recommendationBriefs.generatedAt)).limit(1).get();
9385
9484
  }
9386
9485
  function parseLimitParam(raw) {
9387
9486
  if (raw === void 0) return void 0;
@@ -9407,7 +9506,7 @@ function winnabilityClassRank(winnabilityClass) {
9407
9506
  }
9408
9507
 
9409
9508
  // ../api-routes/src/gsc-totals.ts
9410
- import { and as and9, asc as asc2, eq as eq14, sql as sql6 } from "drizzle-orm";
9509
+ import { and as and10, asc as asc2, eq as eq14, sql as sql6 } from "drizzle-orm";
9411
9510
  function readGscDailyTotals(db, projectId, startDate, endDate) {
9412
9511
  const rows = db.select({
9413
9512
  date: gscDailyTotals.date,
@@ -9415,7 +9514,7 @@ function readGscDailyTotals(db, projectId, startDate, endDate) {
9415
9514
  impressions: gscDailyTotals.impressions,
9416
9515
  position: gscDailyTotals.position
9417
9516
  }).from(gscDailyTotals).where(
9418
- and9(
9517
+ and10(
9419
9518
  eq14(gscDailyTotals.projectId, projectId),
9420
9519
  sql6`${gscDailyTotals.date} >= ${startDate}`,
9421
9520
  sql6`${gscDailyTotals.date} <= ${endDate}`
@@ -11846,7 +11945,7 @@ function buildGscSection(db, projectId, projectBrandNames, canonicalDomain, trac
11846
11945
  function buildGaSection(db, projectId, windowDays) {
11847
11946
  const gaWindowKey = GA_WINDOW_SUMMARY_KEYS[windowDays];
11848
11947
  const windowSummary = gaWindowKey ? db.select().from(gaTrafficWindowSummaries).where(
11849
- and10(
11948
+ and11(
11850
11949
  eq15(gaTrafficWindowSummaries.projectId, projectId),
11851
11950
  eq15(gaTrafficWindowSummaries.windowKey, gaWindowKey)
11852
11951
  )
@@ -12024,7 +12123,7 @@ function nonSubresourceReferralPathCondition() {
12024
12123
  }
12025
12124
  function buildServerActivity(db, projectId, windowDays) {
12026
12125
  const sourceRows = db.select({ id: trafficSources.id }).from(trafficSources).where(
12027
- and10(
12126
+ and11(
12028
12127
  eq15(trafficSources.projectId, projectId),
12029
12128
  ne2(trafficSources.status, TrafficSourceStatuses.archived)
12030
12129
  )
@@ -12040,7 +12139,7 @@ function buildServerActivity(db, projectId, windowDays) {
12040
12139
  const trendStart = new Date(trendStartMs).toISOString();
12041
12140
  const sumVerifiedCrawlers = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
12042
12141
  db.select({ total: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
12043
- and10(
12142
+ and11(
12044
12143
  eq15(crawlerEventsHourly.projectId, projectId),
12045
12144
  eq15(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
12046
12145
  gte2(crawlerEventsHourly.tsHour, windowStartIso),
@@ -12050,7 +12149,7 @@ function buildServerActivity(db, projectId, windowDays) {
12050
12149
  );
12051
12150
  const sumUnverifiedCrawlers = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
12052
12151
  db.select({ total: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
12053
- and10(
12152
+ and11(
12054
12153
  eq15(crawlerEventsHourly.projectId, projectId),
12055
12154
  ne2(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
12056
12155
  gte2(crawlerEventsHourly.tsHour, windowStartIso),
@@ -12060,7 +12159,7 @@ function buildServerActivity(db, projectId, windowDays) {
12060
12159
  );
12061
12160
  const sumReferrals = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
12062
12161
  db.select({ total: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
12063
- and10(
12162
+ and11(
12064
12163
  eq15(aiReferralEventsHourly.projectId, projectId),
12065
12164
  nonSubresourceReferralPathCondition(),
12066
12165
  gte2(aiReferralEventsHourly.tsHour, windowStartIso),
@@ -12070,7 +12169,7 @@ function buildServerActivity(db, projectId, windowDays) {
12070
12169
  );
12071
12170
  const sumUserFetches = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
12072
12171
  db.select({ total: sql7`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
12073
- and10(
12172
+ and11(
12074
12173
  eq15(aiUserFetchEventsHourly.projectId, projectId),
12075
12174
  gte2(aiUserFetchEventsHourly.tsHour, windowStartIso),
12076
12175
  exclusiveEnd ? lt(aiUserFetchEventsHourly.tsHour, windowEndIso) : lte(aiUserFetchEventsHourly.tsHour, windowEndIso)
@@ -12090,7 +12189,7 @@ function buildServerActivity(db, projectId, windowDays) {
12090
12189
  verificationStatus: crawlerEventsHourly.verificationStatus,
12091
12190
  hits: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
12092
12191
  }).from(crawlerEventsHourly).where(
12093
- and10(
12192
+ and11(
12094
12193
  eq15(crawlerEventsHourly.projectId, projectId),
12095
12194
  gte2(crawlerEventsHourly.tsHour, headlineStart),
12096
12195
  lte(crawlerEventsHourly.tsHour, headlineEnd)
@@ -12100,7 +12199,7 @@ function buildServerActivity(db, projectId, windowDays) {
12100
12199
  operator: crawlerEventsHourly.operator,
12101
12200
  hits: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
12102
12201
  }).from(crawlerEventsHourly).where(
12103
- and10(
12202
+ and11(
12104
12203
  eq15(crawlerEventsHourly.projectId, projectId),
12105
12204
  eq15(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
12106
12205
  gte2(crawlerEventsHourly.tsHour, priorStart),
@@ -12111,7 +12210,7 @@ function buildServerActivity(db, projectId, windowDays) {
12111
12210
  operator: aiReferralEventsHourly.operator,
12112
12211
  hits: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
12113
12212
  }).from(aiReferralEventsHourly).where(
12114
- and10(
12213
+ and11(
12115
12214
  eq15(aiReferralEventsHourly.projectId, projectId),
12116
12215
  nonSubresourceReferralPathCondition(),
12117
12216
  gte2(aiReferralEventsHourly.tsHour, headlineStart),
@@ -12122,7 +12221,7 @@ function buildServerActivity(db, projectId, windowDays) {
12122
12221
  operator: aiUserFetchEventsHourly.operator,
12123
12222
  hits: sql7`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
12124
12223
  }).from(aiUserFetchEventsHourly).where(
12125
- and10(
12224
+ and11(
12126
12225
  eq15(aiUserFetchEventsHourly.projectId, projectId),
12127
12226
  gte2(aiUserFetchEventsHourly.tsHour, headlineStart),
12128
12227
  lte(aiUserFetchEventsHourly.tsHour, headlineEnd)
@@ -12166,7 +12265,7 @@ function buildServerActivity(db, projectId, windowDays) {
12166
12265
  hits: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`,
12167
12266
  operators: sql7`COUNT(DISTINCT ${crawlerEventsHourly.operator})`
12168
12267
  }).from(crawlerEventsHourly).where(
12169
- and10(
12268
+ and11(
12170
12269
  eq15(crawlerEventsHourly.projectId, projectId),
12171
12270
  eq15(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
12172
12271
  gte2(crawlerEventsHourly.tsHour, headlineStart),
@@ -12183,7 +12282,7 @@ function buildServerActivity(db, projectId, windowDays) {
12183
12282
  arrivals: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
12184
12283
  landingPaths: sql7`COUNT(DISTINCT ${aiReferralEventsHourly.landingPathNormalized})`
12185
12284
  }).from(aiReferralEventsHourly).where(
12186
- and10(
12285
+ and11(
12187
12286
  eq15(aiReferralEventsHourly.projectId, projectId),
12188
12287
  nonSubresourceReferralPathCondition(),
12189
12288
  gte2(aiReferralEventsHourly.tsHour, headlineStart),
@@ -12200,7 +12299,7 @@ function buildServerActivity(db, projectId, windowDays) {
12200
12299
  arrivals: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
12201
12300
  products: sql7`COUNT(DISTINCT ${aiReferralEventsHourly.product})`
12202
12301
  }).from(aiReferralEventsHourly).where(
12203
- and10(
12302
+ and11(
12204
12303
  eq15(aiReferralEventsHourly.projectId, projectId),
12205
12304
  nonSubresourceReferralPathCondition(),
12206
12305
  gte2(aiReferralEventsHourly.tsHour, headlineStart),
@@ -12216,7 +12315,7 @@ function buildServerActivity(db, projectId, windowDays) {
12216
12315
  date: sql7`SUBSTR(${crawlerEventsHourly.tsHour}, 1, 10)`,
12217
12316
  hits: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
12218
12317
  }).from(crawlerEventsHourly).where(
12219
- and10(
12318
+ and11(
12220
12319
  eq15(crawlerEventsHourly.projectId, projectId),
12221
12320
  eq15(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
12222
12321
  gte2(crawlerEventsHourly.tsHour, trendStart),
@@ -12227,7 +12326,7 @@ function buildServerActivity(db, projectId, windowDays) {
12227
12326
  date: sql7`SUBSTR(${aiReferralEventsHourly.tsHour}, 1, 10)`,
12228
12327
  hits: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
12229
12328
  }).from(aiReferralEventsHourly).where(
12230
- and10(
12329
+ and11(
12231
12330
  eq15(aiReferralEventsHourly.projectId, projectId),
12232
12331
  nonSubresourceReferralPathCondition(),
12233
12332
  gte2(aiReferralEventsHourly.tsHour, trendStart),
@@ -12238,7 +12337,7 @@ function buildServerActivity(db, projectId, windowDays) {
12238
12337
  date: sql7`SUBSTR(${aiUserFetchEventsHourly.tsHour}, 1, 10)`,
12239
12338
  hits: sql7`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
12240
12339
  }).from(aiUserFetchEventsHourly).where(
12241
- and10(
12340
+ and11(
12242
12341
  eq15(aiUserFetchEventsHourly.projectId, projectId),
12243
12342
  gte2(aiUserFetchEventsHourly.tsHour, trendStart),
12244
12343
  lte(aiUserFetchEventsHourly.tsHour, headlineEnd)
@@ -12323,7 +12422,7 @@ function buildIndexingHealth(db, projectId) {
12323
12422
  return null;
12324
12423
  }
12325
12424
  function buildCitationsTrend(db, projectId, queryLookup, locationFilter) {
12326
- const visibilityRuns = db.select().from(runs).where(and10(eq15(runs.projectId, projectId), eq15(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter);
12425
+ const visibilityRuns = db.select().from(runs).where(and11(eq15(runs.projectId, projectId), eq15(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter);
12327
12426
  const totalQueries = queryLookup.byId.size;
12328
12427
  const points = [];
12329
12428
  for (const run of visibilityRuns) {
@@ -12371,7 +12470,7 @@ function buildCitationsTrend(db, projectId, queryLookup, locationFilter) {
12371
12470
  }
12372
12471
  function buildInsightList(db, projectId, locationFilter) {
12373
12472
  const recentRunIds = db.select({ id: runs.id, location: runs.location }).from(runs).where(
12374
- and10(
12473
+ and11(
12375
12474
  eq15(runs.projectId, projectId),
12376
12475
  eq15(runs.kind, RunKinds["answer-visibility"]),
12377
12476
  or3(eq15(runs.status, RunStatuses.completed), eq15(runs.status, RunStatuses.partial)),
@@ -12379,7 +12478,7 @@ function buildInsightList(db, projectId, locationFilter) {
12379
12478
  )
12380
12479
  ).orderBy(desc7(runs.createdAt)).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter).slice(0, INSIGHT_LOOKBACK_RUNS).map((r) => r.id);
12381
12480
  if (recentRunIds.length === 0) return [];
12382
- const rows = db.select().from(insights).where(and10(eq15(insights.projectId, projectId), inArray6(insights.runId, recentRunIds))).orderBy(desc7(insights.createdAt)).all();
12481
+ const rows = db.select().from(insights).where(and11(eq15(insights.projectId, projectId), inArray6(insights.runId, recentRunIds))).orderBy(desc7(insights.createdAt)).all();
12383
12482
  const severityRank = { critical: 0, high: 1, medium: 2, low: 3 };
12384
12483
  const flat = rows.filter((r) => !r.dismissed).map((r) => {
12385
12484
  const recommendation = r.recommendation;
@@ -12931,7 +13030,7 @@ function buildProjectReport(db, projectName, periodDays) {
12931
13030
  const project = resolveProject(db, projectName);
12932
13031
  const queryLookup = loadQueryLookup(db, project.id);
12933
13032
  const comparisonWindowDays = reportComparisonWindowDays(periodDays);
12934
- const allRuns = db.select().from(runs).where(and10(eq15(runs.projectId, project.id), notProbeRun())).orderBy(desc7(runs.createdAt), desc7(runs.id)).all();
13033
+ const allRuns = db.select().from(runs).where(and11(eq15(runs.projectId, project.id), notProbeRun())).orderBy(desc7(runs.createdAt), desc7(runs.id)).all();
12935
13034
  const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
12936
13035
  const completedVisRunGroups = groupRunsByCreatedAt(
12937
13036
  visibilityRuns.filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial)
@@ -13167,7 +13266,7 @@ async function reportRoutes(app) {
13167
13266
  }
13168
13267
 
13169
13268
  // ../api-routes/src/citations.ts
13170
- import { and as and11, eq as eq16, inArray as inArray7 } from "drizzle-orm";
13269
+ import { and as and12, eq as eq16, inArray as inArray7 } from "drizzle-orm";
13171
13270
  async function citationRoutes(app) {
13172
13271
  app.get("/projects/:name/citations/visibility", async (request, reply) => {
13173
13272
  const project = resolveProject(app.db, request.params.name);
@@ -13176,7 +13275,7 @@ async function citationRoutes(app) {
13176
13275
  if (projectQueries.length === 0) {
13177
13276
  return reply.send(emptyCitationVisibility("no-queries"));
13178
13277
  }
13179
- const projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and11(eq16(runs.projectId, project.id), notProbeRun())).all();
13278
+ const projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and12(eq16(runs.projectId, project.id), notProbeRun())).all();
13180
13279
  if (projectRuns.length === 0) {
13181
13280
  return reply.send(emptyCitationVisibility("no-runs-yet"));
13182
13281
  }
@@ -13332,7 +13431,7 @@ function normalizeDomain2(domain) {
13332
13431
  }
13333
13432
 
13334
13433
  // ../api-routes/src/visibility-stats.ts
13335
- import { and as and12, desc as desc8, eq as eq17, inArray as inArray8 } from "drizzle-orm";
13434
+ import { and as and13, desc as desc8, eq as eq17, inArray as inArray8 } from "drizzle-orm";
13336
13435
  function round42(value) {
13337
13436
  return Math.round(value * 1e4) / 1e4;
13338
13437
  }
@@ -13484,7 +13583,7 @@ async function visibilityStatsRoutes(app) {
13484
13583
  lastRuns = n;
13485
13584
  }
13486
13585
  const projectQueries = app.db.select({ id: queries.id, query: queries.query }).from(queries).where(eq17(queries.projectId, project.id)).all();
13487
- let projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(and12(eq17(runs.projectId, project.id), eq17(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc8(runs.createdAt)).all().filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial);
13586
+ let projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(and13(eq17(runs.projectId, project.id), eq17(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc8(runs.createdAt)).all().filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial);
13488
13587
  if (sinceMs !== null) projectRuns = projectRuns.filter((r) => Date.parse(r.createdAt) >= sinceMs);
13489
13588
  if (untilMs !== null) projectRuns = projectRuns.filter((r) => Date.parse(r.createdAt) <= untilMs);
13490
13589
  if (lastRuns !== null) projectRuns = projectRuns.slice(0, lastRuns);
@@ -13554,7 +13653,7 @@ async function visibilityStatsRoutes(app) {
13554
13653
  }
13555
13654
 
13556
13655
  // ../api-routes/src/composites.ts
13557
- import { eq as eq18, and as and13, desc as desc9, sql as sql8, like as like2, or as or4, inArray as inArray9 } from "drizzle-orm";
13656
+ import { eq as eq18, and as and14, desc as desc9, sql as sql8, like as like2, or as or4, inArray as inArray9 } from "drizzle-orm";
13558
13657
  var TOP_INSIGHT_LIMIT = 5;
13559
13658
  var SEARCH_HIT_HARD_LIMIT = 50;
13560
13659
  var SEARCH_SNIPPET_RADIUS = 80;
@@ -13572,7 +13671,7 @@ async function compositeRoutes(app) {
13572
13671
  const project = resolveProject(app.db, request.params.name);
13573
13672
  const filterLocation = (request.query.location ?? "").trim() || null;
13574
13673
  const sinceIso = parseSinceFilter(request.query.since);
13575
- const allRunsRaw = app.db.select().from(runs).where(and13(eq18(runs.projectId, project.id), notProbeRun())).orderBy(desc9(runs.createdAt), desc9(runs.id)).all();
13674
+ const allRunsRaw = app.db.select().from(runs).where(and14(eq18(runs.projectId, project.id), notProbeRun())).orderBy(desc9(runs.createdAt), desc9(runs.id)).all();
13576
13675
  const allRuns = allRunsRaw.filter((r) => runMatchesFilters(r, filterLocation, sinceIso));
13577
13676
  const totalRuns = allRuns.length;
13578
13677
  const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
@@ -13728,7 +13827,7 @@ async function compositeRoutes(app) {
13728
13827
  rawResponse: querySnapshots.rawResponse,
13729
13828
  createdAt: querySnapshots.createdAt
13730
13829
  }).from(querySnapshots).innerJoin(queries, eq18(querySnapshots.queryId, queries.id)).where(
13731
- and13(
13830
+ and14(
13732
13831
  eq18(queries.projectId, project.id),
13733
13832
  or4(
13734
13833
  sql8`${querySnapshots.answerText} LIKE ${pattern} ESCAPE '\\'`,
@@ -13739,7 +13838,7 @@ async function compositeRoutes(app) {
13739
13838
  )
13740
13839
  ).orderBy(desc9(querySnapshots.createdAt)).limit(limit + 1).all());
13741
13840
  const insightMatches = app.db.select().from(insights).where(
13742
- and13(
13841
+ and14(
13743
13842
  eq18(insights.projectId, project.id),
13744
13843
  or4(
13745
13844
  like2(insights.title, pattern),
@@ -13956,7 +14055,7 @@ function buildSuggestedQueriesFromGsc(app, projectId, trackedQueries) {
13956
14055
  // NULLIF guards the degenerate impressions=0 case (SQLite returns NULL,
13957
14056
  // which the JS coerces to 0 — caught by the impression floor anyway).
13958
14057
  avgPosition: sql8`COALESCE(SUM(${gscSearchData.position} * ${gscSearchData.impressions}) * 1.0 / NULLIF(SUM(${gscSearchData.impressions}), 0), 0)`
13959
- }).from(gscSearchData).where(and13(
14058
+ }).from(gscSearchData).where(and14(
13960
14059
  eq18(gscSearchData.projectId, projectId),
13961
14060
  sql8`${gscSearchData.date} >= ${cutoff}`,
13962
14061
  sql8`${gscSearchData.impressions} > 0`
@@ -14464,6 +14563,13 @@ var runIdParameter = {
14464
14563
  description: "Run ID.",
14465
14564
  schema: stringSchema
14466
14565
  };
14566
+ var queryIdParameter = {
14567
+ name: "id",
14568
+ in: "path",
14569
+ required: true,
14570
+ description: "Query ID.",
14571
+ schema: stringSchema
14572
+ };
14467
14573
  var notificationIdParameter = {
14468
14574
  name: "id",
14469
14575
  in: "path",
@@ -14870,6 +14976,17 @@ var routeCatalog = [
14870
14976
  400: errorResponse("Invalid query delete request.")
14871
14977
  }
14872
14978
  },
14979
+ {
14980
+ method: "delete",
14981
+ path: "/api/v1/projects/{name}/queries/{id}",
14982
+ summary: "Delete one query by ID",
14983
+ tags: ["queries"],
14984
+ parameters: [nameParameter, queryIdParameter],
14985
+ responses: {
14986
+ 204: { description: "Query deleted." },
14987
+ 404: errorResponse("Project or query not found.")
14988
+ }
14989
+ },
14873
14990
  {
14874
14991
  method: "post",
14875
14992
  path: "/api/v1/projects/{name}/queries",
@@ -18862,7 +18979,7 @@ async function telemetryRoutes(app, opts) {
18862
18979
 
18863
18980
  // ../api-routes/src/schedules.ts
18864
18981
  import crypto13 from "crypto";
18865
- import { and as and14, eq as eq20 } from "drizzle-orm";
18982
+ import { and as and15, eq as eq20 } from "drizzle-orm";
18866
18983
  function parseKindParam(raw) {
18867
18984
  if (raw === void 0 || raw === null || raw === "") return SchedulableRunKinds["answer-visibility"];
18868
18985
  const parsed = schedulableRunKindSchema.safeParse(raw);
@@ -18934,7 +19051,7 @@ async function scheduleRoutes(app, opts) {
18934
19051
  }
18935
19052
  const now = (/* @__PURE__ */ new Date()).toISOString();
18936
19053
  const enabledBool = enabled !== false;
18937
- const existing = app.db.select().from(schedules).where(and14(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
19054
+ const existing = app.db.select().from(schedules).where(and15(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
18938
19055
  if (existing) {
18939
19056
  app.db.update(schedules).set({
18940
19057
  cronExpr,
@@ -18968,13 +19085,13 @@ async function scheduleRoutes(app, opts) {
18968
19085
  diff: { kind, cronExpr, preset, timezone, providers, sourceId }
18969
19086
  });
18970
19087
  opts.onScheduleUpdated?.("upsert", project.id, kind);
18971
- const schedule = app.db.select().from(schedules).where(and14(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
19088
+ const schedule = app.db.select().from(schedules).where(and15(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
18972
19089
  return reply.status(existing ? 200 : 201).send(formatSchedule(schedule));
18973
19090
  });
18974
19091
  app.get("/projects/:name/schedule", async (request, reply) => {
18975
19092
  const project = resolveProject(app.db, request.params.name);
18976
19093
  const kind = parseKindParam(request.query?.kind);
18977
- const schedule = app.db.select().from(schedules).where(and14(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
19094
+ const schedule = app.db.select().from(schedules).where(and15(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
18978
19095
  if (!schedule) {
18979
19096
  throw notFound("Schedule", `${request.params.name} (kind=${kind})`);
18980
19097
  }
@@ -18983,7 +19100,7 @@ async function scheduleRoutes(app, opts) {
18983
19100
  app.delete("/projects/:name/schedule", async (request, reply) => {
18984
19101
  const project = resolveProject(app.db, request.params.name);
18985
19102
  const kind = parseKindParam(request.query?.kind);
18986
- const schedule = app.db.select().from(schedules).where(and14(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
19103
+ const schedule = app.db.select().from(schedules).where(and15(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
18987
19104
  if (!schedule) {
18988
19105
  throw notFound("Schedule", `${request.params.name} (kind=${kind})`);
18989
19106
  }
@@ -19140,7 +19257,7 @@ function formatNotification(row) {
19140
19257
 
19141
19258
  // ../api-routes/src/google.ts
19142
19259
  import crypto18 from "crypto";
19143
- import { eq as eq22, and as and15, desc as desc11, sql as sql9, inArray as inArray10 } from "drizzle-orm";
19260
+ import { eq as eq22, and as and16, desc as desc11, sql as sql9, inArray as inArray10 } from "drizzle-orm";
19144
19261
 
19145
19262
  // ../api-routes/src/gbp-summary.ts
19146
19263
  function computeMetricTotals(rows) {
@@ -21120,7 +21237,7 @@ async function googleRoutes(app, opts) {
21120
21237
  if (page) conditions.push(sql9`${gscSearchData.page} LIKE ${"%" + escapeLikePattern(page) + "%"} ESCAPE '\\'`);
21121
21238
  const limitVal = Math.max(parseInt(limit ?? "500", 10) || 0, 1);
21122
21239
  const offsetVal = Math.max(parseInt(offset ?? "0", 10) || 0, 0);
21123
- const rows = app.db.select().from(gscSearchData).where(and15(...conditions)).orderBy(desc11(gscSearchData.date)).limit(limitVal).offset(offsetVal).all();
21240
+ const rows = app.db.select().from(gscSearchData).where(and16(...conditions)).orderBy(desc11(gscSearchData.date)).limit(limitVal).offset(offsetVal).all();
21124
21241
  return rows.map((r) => ({
21125
21242
  date: r.date,
21126
21243
  query: r.query,
@@ -21148,7 +21265,7 @@ async function googleRoutes(app, opts) {
21148
21265
  date: gscSearchData.date,
21149
21266
  clicks: sql9`COALESCE(SUM(${gscSearchData.clicks}), 0)`,
21150
21267
  impressions: sql9`COALESCE(SUM(${gscSearchData.impressions}), 0)`
21151
- }).from(gscSearchData).where(and15(...conditions)).groupBy(gscSearchData.date).orderBy(gscSearchData.date).all();
21268
+ }).from(gscSearchData).where(and16(...conditions)).groupBy(gscSearchData.date).orderBy(gscSearchData.date).all();
21152
21269
  const daily = mergeGscDailyTotalsWithFallback(
21153
21270
  dailyTotals,
21154
21271
  dimensionedRows.map((r) => ({
@@ -21241,7 +21358,7 @@ async function googleRoutes(app, opts) {
21241
21358
  const { url, limit } = request.query;
21242
21359
  const conditions = [eq22(gscUrlInspections.projectId, project.id)];
21243
21360
  if (url) conditions.push(eq22(gscUrlInspections.url, url));
21244
- const rows = app.db.select().from(gscUrlInspections).where(and15(...conditions)).orderBy(desc11(gscUrlInspections.inspectedAt)).limit(parseInt(limit ?? "100", 10)).all();
21361
+ const rows = app.db.select().from(gscUrlInspections).where(and16(...conditions)).orderBy(desc11(gscUrlInspections.inspectedAt)).limit(parseInt(limit ?? "100", 10)).all();
21245
21362
  return rows.map((r) => ({
21246
21363
  id: r.id,
21247
21364
  url: r.url,
@@ -21736,7 +21853,7 @@ async function googleRoutes(app, opts) {
21736
21853
  app.db.transaction((tx) => {
21737
21854
  if (switching) clearGbpProjectData(tx, project.id);
21738
21855
  for (const remote of remoteLocations) {
21739
- const existing = tx.select().from(gbpLocations).where(and15(eq22(gbpLocations.projectId, project.id), eq22(gbpLocations.locationName, remote.name))).get();
21856
+ const existing = tx.select().from(gbpLocations).where(and16(eq22(gbpLocations.projectId, project.id), eq22(gbpLocations.locationName, remote.name))).get();
21740
21857
  const profile = buildLocationProfileFields(remote);
21741
21858
  if (existing) {
21742
21859
  tx.update(gbpLocations).set({
@@ -21833,7 +21950,7 @@ async function googleRoutes(app, opts) {
21833
21950
  throw validationError(parsed.error.issues[0]?.message ?? "Invalid selection request");
21834
21951
  }
21835
21952
  const { selected } = parsed.data;
21836
- const existing = app.db.select().from(gbpLocations).where(and15(eq22(gbpLocations.projectId, project.id), eq22(gbpLocations.locationName, locationName))).get();
21953
+ const existing = app.db.select().from(gbpLocations).where(and16(eq22(gbpLocations.projectId, project.id), eq22(gbpLocations.locationName, locationName))).get();
21837
21954
  if (!existing) throw notFound("GBP location", locationName);
21838
21955
  const now = (/* @__PURE__ */ new Date()).toISOString();
21839
21956
  app.db.transaction((tx) => {
@@ -21893,7 +22010,7 @@ async function googleRoutes(app, opts) {
21893
22010
  const conditions = [eq22(gbpDailyMetrics.projectId, project.id)];
21894
22011
  if (request.query.locationName) conditions.push(eq22(gbpDailyMetrics.locationName, request.query.locationName));
21895
22012
  if (request.query.metric) conditions.push(eq22(gbpDailyMetrics.metric, request.query.metric));
21896
- const rows = app.db.select().from(gbpDailyMetrics).where(and15(...conditions)).orderBy(desc11(gbpDailyMetrics.date)).all();
22013
+ const rows = app.db.select().from(gbpDailyMetrics).where(and16(...conditions)).orderBy(desc11(gbpDailyMetrics.date)).all();
21897
22014
  return {
21898
22015
  metrics: rows.map((r) => ({ locationName: r.locationName, date: r.date, metric: r.metric, value: r.value })),
21899
22016
  total: rows.length
@@ -21903,7 +22020,7 @@ async function googleRoutes(app, opts) {
21903
22020
  const project = resolveProject(app.db, request.params.name);
21904
22021
  const conditions = [eq22(gbpKeywordImpressions.projectId, project.id)];
21905
22022
  if (request.query.locationName) conditions.push(eq22(gbpKeywordImpressions.locationName, request.query.locationName));
21906
- const rows = app.db.select().from(gbpKeywordImpressions).where(and15(...conditions)).all();
22023
+ const rows = app.db.select().from(gbpKeywordImpressions).where(and16(...conditions)).all();
21907
22024
  rows.sort((a, b) => (b.valueCount ?? -1) - (a.valueCount ?? -1));
21908
22025
  const thresholded = rows.filter((r) => r.valueThreshold !== null).length;
21909
22026
  return {
@@ -21923,7 +22040,7 @@ async function googleRoutes(app, opts) {
21923
22040
  const project = resolveProject(app.db, request.params.name);
21924
22041
  const conditions = [eq22(gbpPlaceActions.projectId, project.id)];
21925
22042
  if (request.query.locationName) conditions.push(eq22(gbpPlaceActions.locationName, request.query.locationName));
21926
- const rows = app.db.select().from(gbpPlaceActions).where(and15(...conditions)).all();
22043
+ const rows = app.db.select().from(gbpPlaceActions).where(and16(...conditions)).all();
21927
22044
  return {
21928
22045
  placeActions: rows.map((r) => ({
21929
22046
  locationName: r.locationName,
@@ -21940,7 +22057,7 @@ async function googleRoutes(app, opts) {
21940
22057
  const project = resolveProject(app.db, request.params.name);
21941
22058
  const conditions = [eq22(gbpLodgingSnapshots.projectId, project.id)];
21942
22059
  if (request.query.locationName) conditions.push(eq22(gbpLodgingSnapshots.locationName, request.query.locationName));
21943
- const rows = app.db.select().from(gbpLodgingSnapshots).where(and15(...conditions)).orderBy(desc11(gbpLodgingSnapshots.syncedAt)).all();
22060
+ const rows = app.db.select().from(gbpLodgingSnapshots).where(and16(...conditions)).orderBy(desc11(gbpLodgingSnapshots.syncedAt)).all();
21944
22061
  const latestByLocation = /* @__PURE__ */ new Map();
21945
22062
  for (const row of rows) {
21946
22063
  if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
@@ -21957,7 +22074,7 @@ async function googleRoutes(app, opts) {
21957
22074
  const project = resolveProject(app.db, request.params.name);
21958
22075
  const conditions = [eq22(gbpAttributesSnapshots.projectId, project.id)];
21959
22076
  if (request.query.locationName) conditions.push(eq22(gbpAttributesSnapshots.locationName, request.query.locationName));
21960
- const rows = app.db.select().from(gbpAttributesSnapshots).where(and15(...conditions)).orderBy(desc11(gbpAttributesSnapshots.syncedAt)).all();
22077
+ const rows = app.db.select().from(gbpAttributesSnapshots).where(and16(...conditions)).orderBy(desc11(gbpAttributesSnapshots.syncedAt)).all();
21961
22078
  const latestByLocation = /* @__PURE__ */ new Map();
21962
22079
  for (const row of rows) {
21963
22080
  if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
@@ -21977,7 +22094,7 @@ async function googleRoutes(app, opts) {
21977
22094
  const project = resolveProject(app.db, request.params.name);
21978
22095
  const conditions = [eq22(gbpPlaceDetails.projectId, project.id)];
21979
22096
  if (request.query.locationName) conditions.push(eq22(gbpPlaceDetails.locationName, request.query.locationName));
21980
- const rows = app.db.select().from(gbpPlaceDetails).where(and15(...conditions)).orderBy(desc11(gbpPlaceDetails.syncedAt)).all();
22097
+ const rows = app.db.select().from(gbpPlaceDetails).where(and16(...conditions)).orderBy(desc11(gbpPlaceDetails.syncedAt)).all();
21981
22098
  const latestByLocation = /* @__PURE__ */ new Map();
21982
22099
  for (const row of rows) {
21983
22100
  if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
@@ -21996,7 +22113,7 @@ async function googleRoutes(app, opts) {
21996
22113
  app.get("/projects/:name/gbp/summary", async (request) => {
21997
22114
  const project = resolveProject(app.db, request.params.name);
21998
22115
  const locationName = request.query.locationName ?? null;
21999
- const locationNames = locationName ? [locationName] : app.db.select({ n: gbpLocations.locationName }).from(gbpLocations).where(and15(eq22(gbpLocations.projectId, project.id), eq22(gbpLocations.selected, true))).all().map((r) => r.n);
22116
+ const locationNames = locationName ? [locationName] : app.db.select({ n: gbpLocations.locationName }).from(gbpLocations).where(and16(eq22(gbpLocations.projectId, project.id), eq22(gbpLocations.selected, true))).all().map((r) => r.n);
22000
22117
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
22001
22118
  if (locationNames.length === 0) {
22002
22119
  return buildGbpSummary({
@@ -22010,10 +22127,10 @@ async function googleRoutes(app, opts) {
22010
22127
  locationProfiles: []
22011
22128
  });
22012
22129
  }
22013
- const metricRows = app.db.select().from(gbpDailyMetrics).where(and15(eq22(gbpDailyMetrics.projectId, project.id), inArray10(gbpDailyMetrics.locationName, locationNames))).all();
22014
- const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and15(eq22(gbpKeywordImpressions.projectId, project.id), inArray10(gbpKeywordImpressions.locationName, locationNames))).all();
22015
- const placeActionRows = app.db.select().from(gbpPlaceActions).where(and15(eq22(gbpPlaceActions.projectId, project.id), inArray10(gbpPlaceActions.locationName, locationNames))).all();
22016
- const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and15(eq22(gbpLodgingSnapshots.projectId, project.id), inArray10(gbpLodgingSnapshots.locationName, locationNames))).orderBy(desc11(gbpLodgingSnapshots.syncedAt)).all();
22130
+ const metricRows = app.db.select().from(gbpDailyMetrics).where(and16(eq22(gbpDailyMetrics.projectId, project.id), inArray10(gbpDailyMetrics.locationName, locationNames))).all();
22131
+ const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and16(eq22(gbpKeywordImpressions.projectId, project.id), inArray10(gbpKeywordImpressions.locationName, locationNames))).all();
22132
+ const placeActionRows = app.db.select().from(gbpPlaceActions).where(and16(eq22(gbpPlaceActions.projectId, project.id), inArray10(gbpPlaceActions.locationName, locationNames))).all();
22133
+ const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and16(eq22(gbpLodgingSnapshots.projectId, project.id), inArray10(gbpLodgingSnapshots.locationName, locationNames))).orderBy(desc11(gbpLodgingSnapshots.syncedAt)).all();
22017
22134
  const latestLodgingByLocation = /* @__PURE__ */ new Map();
22018
22135
  for (const row of lodgingRows) {
22019
22136
  if (!latestLodgingByLocation.has(row.locationName)) {
@@ -22027,7 +22144,7 @@ async function googleRoutes(app, opts) {
22027
22144
  regularHours: gbpLocations.regularHours,
22028
22145
  primaryPhone: gbpLocations.primaryPhone,
22029
22146
  openStatus: gbpLocations.openStatus
22030
- }).from(gbpLocations).where(and15(eq22(gbpLocations.projectId, project.id), inArray10(gbpLocations.locationName, locationNames))).all();
22147
+ }).from(gbpLocations).where(and16(eq22(gbpLocations.projectId, project.id), inArray10(gbpLocations.locationName, locationNames))).all();
22031
22148
  return buildGbpSummary({
22032
22149
  locationName,
22033
22150
  locationCount: locationNames.length,
@@ -22043,7 +22160,7 @@ async function googleRoutes(app, opts) {
22043
22160
 
22044
22161
  // ../api-routes/src/ads.ts
22045
22162
  import crypto19 from "crypto";
22046
- import { eq as eq23, and as and16, asc as asc3, gte as gte3, lte as lte2, inArray as inArray11 } from "drizzle-orm";
22163
+ import { eq as eq23, and as and17, asc as asc3, gte as gte3, lte as lte2, inArray as inArray11 } from "drizzle-orm";
22047
22164
  function statusDto(row) {
22048
22165
  if (!row) return { connected: false };
22049
22166
  return {
@@ -22159,7 +22276,7 @@ async function adsRoutes(app, opts) {
22159
22276
  if (!row) {
22160
22277
  throw validationError('No ads connection for this project. Run "canonry ads connect" first.');
22161
22278
  }
22162
- const inFlight = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and16(
22279
+ const inFlight = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and17(
22163
22280
  eq23(runs.projectId, project.id),
22164
22281
  eq23(runs.kind, RunKinds["ads-sync"]),
22165
22282
  inArray11(runs.status, [RunStatuses.queued, RunStatuses.running])
@@ -22244,7 +22361,7 @@ async function adsRoutes(app, opts) {
22244
22361
  if (entityId) conditions.push(eq23(adsInsightsDaily.entityId, entityId));
22245
22362
  if (from) conditions.push(gte3(adsInsightsDaily.date, from));
22246
22363
  if (to) conditions.push(lte2(adsInsightsDaily.date, to));
22247
- const rows = app.db.select().from(adsInsightsDaily).where(and16(...conditions)).orderBy(asc3(adsInsightsDaily.date)).all();
22364
+ const rows = app.db.select().from(adsInsightsDaily).where(and17(...conditions)).orderBy(asc3(adsInsightsDaily.date)).all();
22248
22365
  const dtoRows = rows.map((row) => ({
22249
22366
  level: row.level,
22250
22367
  entityId: row.entityId,
@@ -22266,7 +22383,7 @@ async function adsRoutes(app, opts) {
22266
22383
  const campaignCount = app.db.select().from(adsCampaigns).where(eq23(adsCampaigns.projectId, project.id)).all().length;
22267
22384
  const adGroupCount = app.db.select().from(adsAdGroups).where(eq23(adsAdGroups.projectId, project.id)).all().length;
22268
22385
  const adCount = app.db.select().from(adsAds).where(eq23(adsAds.projectId, project.id)).all().length;
22269
- const campaignInsights = app.db.select().from(adsInsightsDaily).where(and16(
22386
+ const campaignInsights = app.db.select().from(adsInsightsDaily).where(and17(
22270
22387
  eq23(adsInsightsDaily.projectId, project.id),
22271
22388
  eq23(adsInsightsDaily.level, "campaign")
22272
22389
  )).all();
@@ -22308,7 +22425,7 @@ async function adsRoutes(app, opts) {
22308
22425
 
22309
22426
  // ../api-routes/src/bing.ts
22310
22427
  import crypto20 from "crypto";
22311
- import { eq as eq24, and as and17, desc as desc12 } from "drizzle-orm";
22428
+ import { eq as eq24, and as and18, desc as desc12 } from "drizzle-orm";
22312
22429
 
22313
22430
  // ../integration-bing/src/constants.ts
22314
22431
  var BING_WMT_API_BASE = "https://ssl.bing.com/webmaster/api.svc/json";
@@ -22783,7 +22900,7 @@ async function bingRoutes(app, opts) {
22783
22900
  requireConnectionStore();
22784
22901
  const project = resolveProject(app.db, request.params.name);
22785
22902
  const { url, limit } = request.query;
22786
- const whereClause = url ? and17(eq24(bingUrlInspections.projectId, project.id), eq24(bingUrlInspections.url, url)) : eq24(bingUrlInspections.projectId, project.id);
22903
+ const whereClause = url ? and18(eq24(bingUrlInspections.projectId, project.id), eq24(bingUrlInspections.url, url)) : eq24(bingUrlInspections.projectId, project.id);
22787
22904
  const filtered = app.db.select().from(bingUrlInspections).where(whereClause).orderBy(desc12(bingUrlInspections.inspectedAt)).limit(Math.max(1, Math.min(parseInt(limit ?? "100", 10) || 100, 1e3))).all();
22788
22905
  return filtered.map((r) => ({
22789
22906
  id: r.id,
@@ -23015,7 +23132,7 @@ async function bingRoutes(app, opts) {
23015
23132
  import fs from "fs";
23016
23133
  import path from "path";
23017
23134
  import os from "os";
23018
- import { eq as eq25, and as and18 } from "drizzle-orm";
23135
+ import { eq as eq25, and as and19 } from "drizzle-orm";
23019
23136
  function getScreenshotDir() {
23020
23137
  return path.join(os.homedir(), ".canonry", "screenshots");
23021
23138
  }
@@ -23090,7 +23207,7 @@ async function cdpRoutes(app, opts) {
23090
23207
  async (request, reply) => {
23091
23208
  const project = resolveProject(app.db, request.params.name);
23092
23209
  const { runId } = request.params;
23093
- const run = app.db.select().from(runs).where(and18(eq25(runs.id, runId), eq25(runs.projectId, project.id))).get();
23210
+ const run = app.db.select().from(runs).where(and19(eq25(runs.id, runId), eq25(runs.projectId, project.id))).get();
23094
23211
  if (!run) {
23095
23212
  const err = notFound("Run", runId);
23096
23213
  return reply.code(err.statusCode).send(err.toJSON());
@@ -23187,7 +23304,7 @@ async function cdpRoutes(app, opts) {
23187
23304
 
23188
23305
  // ../api-routes/src/ga.ts
23189
23306
  import crypto21 from "crypto";
23190
- import { eq as eq26, desc as desc13, and as and19, sql as sql10 } from "drizzle-orm";
23307
+ import { eq as eq26, desc as desc13, and as and20, sql as sql10 } from "drizzle-orm";
23191
23308
  function gaLog(level, action, ctx) {
23192
23309
  const entry = { ts: (/* @__PURE__ */ new Date()).toISOString(), level, module: "GA4Routes", action, ...ctx };
23193
23310
  const stream = level === "error" ? process.stderr : process.stdout;
@@ -23482,7 +23599,7 @@ async function ga4Routes(app, opts) {
23482
23599
  app.db.transaction((tx) => {
23483
23600
  if (syncTraffic) {
23484
23601
  tx.delete(gaTrafficSnapshots).where(
23485
- and19(
23602
+ and20(
23486
23603
  eq26(gaTrafficSnapshots.projectId, project.id),
23487
23604
  sql10`${gaTrafficSnapshots.date} >= ${summary.periodStart}`,
23488
23605
  sql10`${gaTrafficSnapshots.date} <= ${summary.periodEnd}`
@@ -23506,7 +23623,7 @@ async function ga4Routes(app, opts) {
23506
23623
  }
23507
23624
  if (syncAi) {
23508
23625
  tx.delete(gaAiReferrals).where(
23509
- and19(
23626
+ and20(
23510
23627
  eq26(gaAiReferrals.projectId, project.id),
23511
23628
  sql10`${gaAiReferrals.date} >= ${summary.periodStart}`,
23512
23629
  sql10`${gaAiReferrals.date} <= ${summary.periodEnd}`
@@ -23532,7 +23649,7 @@ async function ga4Routes(app, opts) {
23532
23649
  }
23533
23650
  if (syncSocial) {
23534
23651
  tx.delete(gaSocialReferrals).where(
23535
- and19(
23652
+ and20(
23536
23653
  eq26(gaSocialReferrals.projectId, project.id),
23537
23654
  sql10`${gaSocialReferrals.date} >= ${summary.periodStart}`,
23538
23655
  sql10`${gaSocialReferrals.date} <= ${summary.periodEnd}`
@@ -23636,7 +23753,7 @@ async function ga4Routes(app, opts) {
23636
23753
  totalDirectSessions: gaTrafficWindowSummaries.totalDirectSessions,
23637
23754
  totalUsers: gaTrafficWindowSummaries.totalUsers
23638
23755
  }).from(gaTrafficWindowSummaries).where(
23639
- and19(
23756
+ and20(
23640
23757
  eq26(gaTrafficWindowSummaries.projectId, project.id),
23641
23758
  eq26(gaTrafficWindowSummaries.windowKey, window)
23642
23759
  )
@@ -23645,7 +23762,7 @@ async function ga4Routes(app, opts) {
23645
23762
  totalSessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)`,
23646
23763
  totalOrganicSessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)`,
23647
23764
  totalUsers: sql10`COALESCE(SUM(${gaTrafficSnapshots.users}), 0)`
23648
- }).from(gaTrafficSnapshots).where(and19(...snapshotConditions)).get() : null;
23765
+ }).from(gaTrafficSnapshots).where(and20(...snapshotConditions)).get() : null;
23649
23766
  const summaryRow = cutoffDate ? windowSummaryRow ?? snapshotTotalsRow : app.db.select({
23650
23767
  totalSessions: gaTrafficSummaries.totalSessions,
23651
23768
  totalOrganicSessions: gaTrafficSummaries.totalOrganicSessions,
@@ -23653,7 +23770,7 @@ async function ga4Routes(app, opts) {
23653
23770
  }).from(gaTrafficSummaries).where(eq26(gaTrafficSummaries.projectId, project.id)).get();
23654
23771
  const directTotalRow = windowSummaryRow ? { totalDirectSessions: windowSummaryRow.totalDirectSessions } : app.db.select({
23655
23772
  totalDirectSessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`
23656
- }).from(gaTrafficSnapshots).where(and19(...snapshotConditions)).get();
23773
+ }).from(gaTrafficSnapshots).where(and20(...snapshotConditions)).get();
23657
23774
  const summaryMeta = app.db.select({
23658
23775
  periodStart: gaTrafficSummaries.periodStart,
23659
23776
  periodEnd: gaTrafficSummaries.periodEnd
@@ -23664,14 +23781,14 @@ async function ga4Routes(app, opts) {
23664
23781
  organicSessions: sql10`SUM(${gaTrafficSnapshots.organicSessions})`,
23665
23782
  directSessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`,
23666
23783
  users: sql10`SUM(${gaTrafficSnapshots.users})`
23667
- }).from(gaTrafficSnapshots).where(and19(...snapshotConditions)).groupBy(sql10`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`).orderBy(sql10`SUM(${gaTrafficSnapshots.sessions}) DESC`).limit(limit).all();
23784
+ }).from(gaTrafficSnapshots).where(and20(...snapshotConditions)).groupBy(sql10`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`).orderBy(sql10`SUM(${gaTrafficSnapshots.sessions}) DESC`).limit(limit).all();
23668
23785
  const aiReferralRows = app.db.select({
23669
23786
  source: gaAiReferrals.source,
23670
23787
  medium: gaAiReferrals.medium,
23671
23788
  sourceDimension: gaAiReferrals.sourceDimension,
23672
23789
  sessions: sql10`SUM(${gaAiReferrals.sessions})`,
23673
23790
  users: sql10`SUM(${gaAiReferrals.users})`
23674
- }).from(gaAiReferrals).where(and19(...aiConditions)).groupBy(gaAiReferrals.source, gaAiReferrals.medium, gaAiReferrals.sourceDimension).all();
23791
+ }).from(gaAiReferrals).where(and20(...aiConditions)).groupBy(gaAiReferrals.source, gaAiReferrals.medium, gaAiReferrals.sourceDimension).all();
23675
23792
  const aiReferralLandingPageRows = app.db.select({
23676
23793
  source: gaAiReferrals.source,
23677
23794
  medium: gaAiReferrals.medium,
@@ -23679,7 +23796,7 @@ async function ga4Routes(app, opts) {
23679
23796
  landingPage: sql10`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`,
23680
23797
  sessions: sql10`SUM(${gaAiReferrals.sessions})`,
23681
23798
  users: sql10`SUM(${gaAiReferrals.users})`
23682
- }).from(gaAiReferrals).where(and19(...aiConditions)).groupBy(
23799
+ }).from(gaAiReferrals).where(and20(...aiConditions)).groupBy(
23683
23800
  gaAiReferrals.source,
23684
23801
  gaAiReferrals.medium,
23685
23802
  gaAiReferrals.sourceDimension,
@@ -23716,7 +23833,7 @@ async function ga4Routes(app, opts) {
23716
23833
  channelGroup: gaAiReferrals.channelGroup,
23717
23834
  sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)`,
23718
23835
  users: sql10`COALESCE(SUM(${gaAiReferrals.users}), 0)`
23719
- }).from(gaAiReferrals).where(and19(...aiConditions, eq26(gaAiReferrals.sourceDimension, "session"))).groupBy(gaAiReferrals.channelGroup).all();
23836
+ }).from(gaAiReferrals).where(and20(...aiConditions, eq26(gaAiReferrals.sourceDimension, "session"))).groupBy(gaAiReferrals.channelGroup).all();
23720
23837
  const aiSessionsByChannelGroup = /* @__PURE__ */ new Map();
23721
23838
  let aiBySessionUsers = 0;
23722
23839
  for (const row of aiBySessionRows) {
@@ -23730,11 +23847,11 @@ async function ga4Routes(app, opts) {
23730
23847
  channelGroup: gaSocialReferrals.channelGroup,
23731
23848
  sessions: sql10`SUM(${gaSocialReferrals.sessions})`,
23732
23849
  users: sql10`SUM(${gaSocialReferrals.users})`
23733
- }).from(gaSocialReferrals).where(and19(...socialConditions)).groupBy(gaSocialReferrals.source, gaSocialReferrals.medium, gaSocialReferrals.channelGroup).orderBy(sql10`SUM(${gaSocialReferrals.sessions}) DESC`).all();
23850
+ }).from(gaSocialReferrals).where(and20(...socialConditions)).groupBy(gaSocialReferrals.source, gaSocialReferrals.medium, gaSocialReferrals.channelGroup).orderBy(sql10`SUM(${gaSocialReferrals.sessions}) DESC`).all();
23734
23851
  const socialTotals = app.db.select({
23735
23852
  sessions: sql10`SUM(${gaSocialReferrals.sessions})`,
23736
23853
  users: sql10`SUM(${gaSocialReferrals.users})`
23737
- }).from(gaSocialReferrals).where(and19(...socialConditions)).get();
23854
+ }).from(gaSocialReferrals).where(and20(...socialConditions)).get();
23738
23855
  const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq26(gaTrafficSummaries.projectId, project.id)).orderBy(desc13(gaTrafficSummaries.syncedAt)).limit(1).get();
23739
23856
  const total = summaryRow?.totalSessions ?? 0;
23740
23857
  const totalDirectSessions = directTotalRow?.totalDirectSessions ?? 0;
@@ -23825,7 +23942,7 @@ async function ga4Routes(app, opts) {
23825
23942
  sourceDimension: gaAiReferrals.sourceDimension,
23826
23943
  sessions: sql10`SUM(${gaAiReferrals.sessions})`,
23827
23944
  users: sql10`SUM(${gaAiReferrals.users})`
23828
- }).from(gaAiReferrals).where(and19(...conditions)).groupBy(
23945
+ }).from(gaAiReferrals).where(and20(...conditions)).groupBy(
23829
23946
  gaAiReferrals.date,
23830
23947
  gaAiReferrals.source,
23831
23948
  gaAiReferrals.medium,
@@ -23847,7 +23964,7 @@ async function ga4Routes(app, opts) {
23847
23964
  channelGroup: gaSocialReferrals.channelGroup,
23848
23965
  sessions: gaSocialReferrals.sessions,
23849
23966
  users: gaSocialReferrals.users
23850
- }).from(gaSocialReferrals).where(and19(...conditions)).orderBy(gaSocialReferrals.date).all();
23967
+ }).from(gaSocialReferrals).where(and20(...conditions)).orderBy(gaSocialReferrals.date).all();
23851
23968
  return rows;
23852
23969
  });
23853
23970
  app.get("/projects/:name/ga/social-referral-trend", async (request, _reply) => {
@@ -23860,7 +23977,7 @@ async function ga4Routes(app, opts) {
23860
23977
  d.setDate(d.getDate() - n);
23861
23978
  return fmt(d);
23862
23979
  };
23863
- const sumSocial = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and19(
23980
+ const sumSocial = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and20(
23864
23981
  eq26(gaSocialReferrals.projectId, project.id),
23865
23982
  sql10`${gaSocialReferrals.date} >= ${from}`,
23866
23983
  sql10`${gaSocialReferrals.date} < ${to}`
@@ -23873,7 +23990,7 @@ async function ga4Routes(app, opts) {
23873
23990
  const sourceCurrent = app.db.select({
23874
23991
  source: gaSocialReferrals.source,
23875
23992
  sessions: sql10`SUM(${gaSocialReferrals.sessions})`
23876
- }).from(gaSocialReferrals).where(and19(
23993
+ }).from(gaSocialReferrals).where(and20(
23877
23994
  eq26(gaSocialReferrals.projectId, project.id),
23878
23995
  sql10`${gaSocialReferrals.date} >= ${daysAgo(7)}`,
23879
23996
  sql10`${gaSocialReferrals.date} < ${fmt(today)}`
@@ -23881,7 +23998,7 @@ async function ga4Routes(app, opts) {
23881
23998
  const sourcePrev = app.db.select({
23882
23999
  source: gaSocialReferrals.source,
23883
24000
  sessions: sql10`SUM(${gaSocialReferrals.sessions})`
23884
- }).from(gaSocialReferrals).where(and19(
24001
+ }).from(gaSocialReferrals).where(and20(
23885
24002
  eq26(gaSocialReferrals.projectId, project.id),
23886
24003
  sql10`${gaSocialReferrals.date} >= ${daysAgo(14)}`,
23887
24004
  sql10`${gaSocialReferrals.date} < ${daysAgo(7)}`
@@ -23923,16 +24040,16 @@ async function ga4Routes(app, opts) {
23923
24040
  return fmt(d);
23924
24041
  };
23925
24042
  const pct = (cur, prev) => prev === 0 ? null : Math.round((cur - prev) / prev * 100);
23926
- const sumTotal = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)` }).from(gaTrafficSnapshots).where(and19(eq26(gaTrafficSnapshots.projectId, project.id), sql10`${gaTrafficSnapshots.date} >= ${from}`, sql10`${gaTrafficSnapshots.date} < ${to}`)).get();
23927
- const sumOrganic = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)` }).from(gaTrafficSnapshots).where(and19(eq26(gaTrafficSnapshots.projectId, project.id), sql10`${gaTrafficSnapshots.date} >= ${from}`, sql10`${gaTrafficSnapshots.date} < ${to}`)).get();
23928
- const sumDirect = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)` }).from(gaTrafficSnapshots).where(and19(eq26(gaTrafficSnapshots.projectId, project.id), sql10`${gaTrafficSnapshots.date} >= ${from}`, sql10`${gaTrafficSnapshots.date} < ${to}`)).get();
23929
- const sumAi = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and19(
24043
+ const sumTotal = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)` }).from(gaTrafficSnapshots).where(and20(eq26(gaTrafficSnapshots.projectId, project.id), sql10`${gaTrafficSnapshots.date} >= ${from}`, sql10`${gaTrafficSnapshots.date} < ${to}`)).get();
24044
+ const sumOrganic = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)` }).from(gaTrafficSnapshots).where(and20(eq26(gaTrafficSnapshots.projectId, project.id), sql10`${gaTrafficSnapshots.date} >= ${from}`, sql10`${gaTrafficSnapshots.date} < ${to}`)).get();
24045
+ const sumDirect = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)` }).from(gaTrafficSnapshots).where(and20(eq26(gaTrafficSnapshots.projectId, project.id), sql10`${gaTrafficSnapshots.date} >= ${from}`, sql10`${gaTrafficSnapshots.date} < ${to}`)).get();
24046
+ const sumAi = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and20(
23930
24047
  eq26(gaAiReferrals.projectId, project.id),
23931
24048
  sql10`${gaAiReferrals.date} >= ${from}`,
23932
24049
  sql10`${gaAiReferrals.date} < ${to}`,
23933
24050
  eq26(gaAiReferrals.sourceDimension, "session")
23934
24051
  )).get();
23935
- const sumSocial = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and19(eq26(gaSocialReferrals.projectId, project.id), sql10`${gaSocialReferrals.date} >= ${from}`, sql10`${gaSocialReferrals.date} < ${to}`)).get();
24052
+ const sumSocial = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and20(eq26(gaSocialReferrals.projectId, project.id), sql10`${gaSocialReferrals.date} >= ${from}`, sql10`${gaSocialReferrals.date} < ${to}`)).get();
23936
24053
  const todayStr = fmt(today);
23937
24054
  const buildTrend = (sum) => {
23938
24055
  const c7 = sum(daysAgo(7), todayStr)?.sessions ?? 0;
@@ -23941,13 +24058,13 @@ async function ga4Routes(app, opts) {
23941
24058
  const p30 = sum(daysAgo(60), daysAgo(30))?.sessions ?? 0;
23942
24059
  return { sessions7d: c7, sessionsPrev7d: p7, trend7dPct: pct(c7, p7), sessions30d: c30, sessionsPrev30d: p30, trend30dPct: pct(c30, p30) };
23943
24060
  };
23944
- const aiSourceCurrent = app.db.select({ source: gaAiReferrals.source, sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and19(
24061
+ const aiSourceCurrent = app.db.select({ source: gaAiReferrals.source, sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and20(
23945
24062
  eq26(gaAiReferrals.projectId, project.id),
23946
24063
  sql10`${gaAiReferrals.date} >= ${daysAgo(7)}`,
23947
24064
  sql10`${gaAiReferrals.date} < ${todayStr}`,
23948
24065
  eq26(gaAiReferrals.sourceDimension, "session")
23949
24066
  )).groupBy(gaAiReferrals.source).all();
23950
- const aiSourcePrev = app.db.select({ source: gaAiReferrals.source, sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and19(
24067
+ const aiSourcePrev = app.db.select({ source: gaAiReferrals.source, sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and20(
23951
24068
  eq26(gaAiReferrals.projectId, project.id),
23952
24069
  sql10`${gaAiReferrals.date} >= ${daysAgo(14)}`,
23953
24070
  sql10`${gaAiReferrals.date} < ${daysAgo(7)}`,
@@ -23967,8 +24084,8 @@ async function ga4Routes(app, opts) {
23967
24084
  }
23968
24085
  return mover;
23969
24086
  };
23970
- const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions: sql10`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and19(eq26(gaSocialReferrals.projectId, project.id), sql10`${gaSocialReferrals.date} >= ${daysAgo(7)}`, sql10`${gaSocialReferrals.date} < ${todayStr}`)).groupBy(gaSocialReferrals.source).all();
23971
- const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions: sql10`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and19(eq26(gaSocialReferrals.projectId, project.id), sql10`${gaSocialReferrals.date} >= ${daysAgo(14)}`, sql10`${gaSocialReferrals.date} < ${daysAgo(7)}`)).groupBy(gaSocialReferrals.source).all();
24087
+ const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions: sql10`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and20(eq26(gaSocialReferrals.projectId, project.id), sql10`${gaSocialReferrals.date} >= ${daysAgo(7)}`, sql10`${gaSocialReferrals.date} < ${todayStr}`)).groupBy(gaSocialReferrals.source).all();
24088
+ const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions: sql10`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and20(eq26(gaSocialReferrals.projectId, project.id), sql10`${gaSocialReferrals.date} >= ${daysAgo(14)}`, sql10`${gaSocialReferrals.date} < ${daysAgo(7)}`)).groupBy(gaSocialReferrals.source).all();
23972
24089
  return {
23973
24090
  total: buildTrend(sumTotal),
23974
24091
  organic: buildTrend(sumOrganic),
@@ -23990,7 +24107,7 @@ async function ga4Routes(app, opts) {
23990
24107
  sessions: sql10`SUM(${gaTrafficSnapshots.sessions})`,
23991
24108
  organicSessions: sql10`SUM(${gaTrafficSnapshots.organicSessions})`,
23992
24109
  users: sql10`SUM(${gaTrafficSnapshots.users})`
23993
- }).from(gaTrafficSnapshots).where(and19(...conditions)).groupBy(gaTrafficSnapshots.date).orderBy(gaTrafficSnapshots.date).all();
24110
+ }).from(gaTrafficSnapshots).where(and20(...conditions)).groupBy(gaTrafficSnapshots.date).orderBy(gaTrafficSnapshots.date).all();
23994
24111
  return rows.map((r) => ({
23995
24112
  date: r.date,
23996
24113
  sessions: r.sessions ?? 0,
@@ -25654,7 +25771,7 @@ async function wordpressRoutes(app, opts) {
25654
25771
 
25655
25772
  // ../api-routes/src/backlinks.ts
25656
25773
  import crypto23 from "crypto";
25657
- import { and as and21, asc as asc4, desc as desc14, eq as eq27, sql as sql11 } from "drizzle-orm";
25774
+ import { and as and22, asc as asc4, desc as desc14, eq as eq27, sql as sql11 } from "drizzle-orm";
25658
25775
 
25659
25776
  // ../integration-commoncrawl/src/constants.ts
25660
25777
  import os2 from "os";
@@ -26057,7 +26174,7 @@ function pruneCachedRelease(release, opts = {}) {
26057
26174
  }
26058
26175
 
26059
26176
  // ../api-routes/src/backlinks-filter.ts
26060
- import { and as and20, ne as ne3, notLike } from "drizzle-orm";
26177
+ import { and as and21, ne as ne3, notLike } from "drizzle-orm";
26061
26178
  var BACKLINK_FILTER_PATTERNS = [
26062
26179
  "*.google.com",
26063
26180
  "*.googleusercontent.com",
@@ -26080,7 +26197,7 @@ function backlinkCrawlerExclusionClause() {
26080
26197
  conditions.push(ne3(backlinkDomains.linkingDomain, pattern));
26081
26198
  }
26082
26199
  }
26083
- const combined = and20(...conditions);
26200
+ const combined = and21(...conditions);
26084
26201
  if (!combined) throw new Error("BACKLINK_FILTER_PATTERNS is unexpectedly empty");
26085
26202
  return combined;
26086
26203
  }
@@ -26155,7 +26272,7 @@ function latestSummaryForProject(db, projectId, source, release) {
26155
26272
  eq27(backlinkSummaries.source, source)
26156
26273
  ];
26157
26274
  if (release) conditions.push(eq27(backlinkSummaries.release, release));
26158
- return db.select().from(backlinkSummaries).where(and21(...conditions)).orderBy(desc14(backlinkSummaries.queriedAt)).limit(1).get();
26275
+ return db.select().from(backlinkSummaries).where(and22(...conditions)).orderBy(desc14(backlinkSummaries.queriedAt)).limit(1).get();
26159
26276
  }
26160
26277
  function parseExcludeCrawlers(value) {
26161
26278
  if (!value) return false;
@@ -26163,12 +26280,12 @@ function parseExcludeCrawlers(value) {
26163
26280
  return lower === "1" || lower === "true" || lower === "yes";
26164
26281
  }
26165
26282
  function computeFilteredSummary(db, base) {
26166
- const baseDomainCondition = and21(
26283
+ const baseDomainCondition = and22(
26167
26284
  eq27(backlinkDomains.projectId, base.projectId),
26168
26285
  eq27(backlinkDomains.source, base.source),
26169
26286
  eq27(backlinkDomains.release, base.release)
26170
26287
  );
26171
- const filteredCondition = and21(baseDomainCondition, backlinkCrawlerExclusionClause());
26288
+ const filteredCondition = and22(baseDomainCondition, backlinkCrawlerExclusionClause());
26172
26289
  const unfilteredAgg = db.select({
26173
26290
  count: sql11`count(*)`,
26174
26291
  total: sql11`coalesce(sum(${backlinkDomains.numHosts}), 0)`
@@ -26198,10 +26315,10 @@ function computeFilteredSummary(db, base) {
26198
26315
  };
26199
26316
  }
26200
26317
  function buildSourceAvailability(db, projectId, source, connected, excludeCrawlers) {
26201
- const summary = db.select().from(backlinkSummaries).where(and21(eq27(backlinkSummaries.projectId, projectId), eq27(backlinkSummaries.source, source))).orderBy(desc14(backlinkSummaries.queriedAt)).limit(1).get();
26318
+ const summary = db.select().from(backlinkSummaries).where(and22(eq27(backlinkSummaries.projectId, projectId), eq27(backlinkSummaries.source, source))).orderBy(desc14(backlinkSummaries.queriedAt)).limit(1).get();
26202
26319
  let totalLinkingDomains = summary?.totalLinkingDomains ?? 0;
26203
26320
  if (summary && excludeCrawlers) {
26204
- const filtered = db.select({ count: sql11`count(*)` }).from(backlinkDomains).where(and21(
26321
+ const filtered = db.select({ count: sql11`count(*)` }).from(backlinkDomains).where(and22(
26205
26322
  eq27(backlinkDomains.projectId, projectId),
26206
26323
  eq27(backlinkDomains.source, source),
26207
26324
  eq27(backlinkDomains.release, summary.release),
@@ -26384,12 +26501,12 @@ async function backlinksRoutes(app, opts) {
26384
26501
  const limit = Math.min(Math.max(parseInt(request.query.limit ?? "50", 10) || 50, 1), 500);
26385
26502
  const offset = Math.max(parseInt(request.query.offset ?? "0", 10) || 0, 0);
26386
26503
  const excludeCrawlers = parseExcludeCrawlers(request.query.excludeCrawlers);
26387
- const baseDomainCondition = and21(
26504
+ const baseDomainCondition = and22(
26388
26505
  eq27(backlinkDomains.projectId, project.id),
26389
26506
  eq27(backlinkDomains.source, source),
26390
26507
  eq27(backlinkDomains.release, targetRelease)
26391
26508
  );
26392
- const domainCondition = excludeCrawlers ? and21(baseDomainCondition, backlinkCrawlerExclusionClause()) : baseDomainCondition;
26509
+ const domainCondition = excludeCrawlers ? and22(baseDomainCondition, backlinkCrawlerExclusionClause()) : baseDomainCondition;
26393
26510
  const totalRow = app.db.select({ count: sql11`count(*)` }).from(backlinkDomains).where(domainCondition).get();
26394
26511
  const rows = app.db.select({
26395
26512
  linkingDomain: backlinkDomains.linkingDomain,
@@ -26413,7 +26530,7 @@ async function backlinksRoutes(app, opts) {
26413
26530
  async (request, reply) => {
26414
26531
  const project = resolveProject(app.db, request.params.name);
26415
26532
  const source = parseSourceParam(request.query.source);
26416
- const rows = app.db.select().from(backlinkSummaries).where(and21(eq27(backlinkSummaries.projectId, project.id), eq27(backlinkSummaries.source, source))).orderBy(asc4(backlinkSummaries.queriedAt)).all();
26533
+ const rows = app.db.select().from(backlinkSummaries).where(and22(eq27(backlinkSummaries.projectId, project.id), eq27(backlinkSummaries.source, source))).orderBy(asc4(backlinkSummaries.queriedAt)).all();
26417
26534
  const response = rows.map((r) => ({
26418
26535
  release: r.release,
26419
26536
  totalLinkingDomains: r.totalLinkingDomains,
@@ -26469,7 +26586,7 @@ async function backlinksRoutes(app, opts) {
26469
26586
  // ../api-routes/src/traffic.ts
26470
26587
  import crypto25 from "crypto";
26471
26588
  import { Agent as UndiciAgent } from "undici";
26472
- import { and as and22, desc as desc15, eq as eq28, gte as gte4, lte as lte3, sql as sql12 } from "drizzle-orm";
26589
+ import { and as and23, desc as desc15, eq as eq28, gte as gte4, lte as lte3, sql as sql12 } from "drizzle-orm";
26473
26590
 
26474
26591
  // ../integration-cloud-run/src/auth.ts
26475
26592
  import crypto24 from "crypto";
@@ -30328,28 +30445,28 @@ async function runBackfillTask(options) {
30328
30445
  try {
30329
30446
  app.db.transaction((tx) => {
30330
30447
  tx.delete(crawlerEventsHourly).where(
30331
- and22(
30448
+ and23(
30332
30449
  eq28(crawlerEventsHourly.sourceId, sourceRow.id),
30333
30450
  gte4(crawlerEventsHourly.tsHour, windowStartIso),
30334
30451
  lte3(crawlerEventsHourly.tsHour, windowEndIso)
30335
30452
  )
30336
30453
  ).run();
30337
30454
  tx.delete(aiUserFetchEventsHourly).where(
30338
- and22(
30455
+ and23(
30339
30456
  eq28(aiUserFetchEventsHourly.sourceId, sourceRow.id),
30340
30457
  gte4(aiUserFetchEventsHourly.tsHour, windowStartIso),
30341
30458
  lte3(aiUserFetchEventsHourly.tsHour, windowEndIso)
30342
30459
  )
30343
30460
  ).run();
30344
30461
  tx.delete(aiReferralEventsHourly).where(
30345
- and22(
30462
+ and23(
30346
30463
  eq28(aiReferralEventsHourly.sourceId, sourceRow.id),
30347
30464
  gte4(aiReferralEventsHourly.tsHour, windowStartIso),
30348
30465
  lte3(aiReferralEventsHourly.tsHour, windowEndIso)
30349
30466
  )
30350
30467
  ).run();
30351
30468
  tx.delete(rawEventSamples).where(
30352
- and22(
30469
+ and23(
30353
30470
  eq28(rawEventSamples.sourceId, sourceRow.id),
30354
30471
  gte4(rawEventSamples.ts, windowStartIso),
30355
30472
  lte3(rawEventSamples.ts, windowEndIso)
@@ -30732,7 +30849,7 @@ async function trafficRoutes(app, opts) {
30732
30849
  row = tx.select().from(trafficSources).where(eq28(trafficSources.id, newId)).get();
30733
30850
  }
30734
30851
  const existingSchedule = tx.select().from(schedules).where(
30735
- and22(
30852
+ and23(
30736
30853
  eq28(schedules.projectId, project.id),
30737
30854
  eq28(schedules.kind, SchedulableRunKinds["traffic-sync"])
30738
30855
  )
@@ -31454,7 +31571,7 @@ async function trafficRoutes(app, opts) {
31454
31571
  pathNormalized: crawlerEventsHourly.pathNormalized,
31455
31572
  hits: sql12`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
31456
31573
  }).from(crawlerEventsHourly).where(
31457
- and22(
31574
+ and23(
31458
31575
  eq28(crawlerEventsHourly.sourceId, row.id),
31459
31576
  gte4(crawlerEventsHourly.tsHour, since)
31460
31577
  )
@@ -31464,25 +31581,25 @@ async function trafficRoutes(app, opts) {
31464
31581
  );
31465
31582
  const crawlerTotal = crawlerSegments.content + crawlerSegments.sitemap + crawlerSegments.robots + crawlerSegments.asset + crawlerSegments.other;
31466
31583
  const aiUserFetchTotals = app.db.select({ total: sql12`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
31467
- and22(
31584
+ and23(
31468
31585
  eq28(aiUserFetchEventsHourly.sourceId, row.id),
31469
31586
  gte4(aiUserFetchEventsHourly.tsHour, since)
31470
31587
  )
31471
31588
  ).get();
31472
31589
  const aiTotals = app.db.select({ total: sql12`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
31473
- and22(
31590
+ and23(
31474
31591
  eq28(aiReferralEventsHourly.sourceId, row.id),
31475
31592
  gte4(aiReferralEventsHourly.tsHour, since)
31476
31593
  )
31477
31594
  ).get();
31478
31595
  const sampleTotals = app.db.select({ total: sql12`COUNT(*)` }).from(rawEventSamples).where(
31479
- and22(
31596
+ and23(
31480
31597
  eq28(rawEventSamples.sourceId, row.id),
31481
31598
  gte4(rawEventSamples.ts, since)
31482
31599
  )
31483
31600
  ).get();
31484
31601
  const latestRun = app.db.select().from(runs).where(
31485
- and22(
31602
+ and23(
31486
31603
  eq28(runs.projectId, projectId),
31487
31604
  eq28(runs.kind, RunKinds["traffic-sync"]),
31488
31605
  eq28(runs.sourceId, row.id)
@@ -31516,7 +31633,7 @@ async function trafficRoutes(app, opts) {
31516
31633
  "`advanceToNow` must be `true`. There is no implicit reset."
31517
31634
  );
31518
31635
  }
31519
- const sourceRow = app.db.select().from(trafficSources).where(and22(eq28(trafficSources.projectId, project.id), eq28(trafficSources.id, request.params.id))).get();
31636
+ const sourceRow = app.db.select().from(trafficSources).where(and23(eq28(trafficSources.projectId, project.id), eq28(trafficSources.id, request.params.id))).get();
31520
31637
  if (!sourceRow) {
31521
31638
  throw notFound("traffic source", request.params.id);
31522
31639
  }
@@ -31621,7 +31738,7 @@ async function trafficRoutes(app, opts) {
31621
31738
  lte3(crawlerEventsHourly.tsHour, untilIso)
31622
31739
  ];
31623
31740
  if (sourceIdParam) crawlerFilters.push(eq28(crawlerEventsHourly.sourceId, sourceIdParam));
31624
- const crawlerWhere = and22(...crawlerFilters);
31741
+ const crawlerWhere = and23(...crawlerFilters);
31625
31742
  const pathTotals = app.db.select({
31626
31743
  pathNormalized: crawlerEventsHourly.pathNormalized,
31627
31744
  hits: sql12`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
@@ -31653,7 +31770,7 @@ async function trafficRoutes(app, opts) {
31653
31770
  lte3(aiUserFetchEventsHourly.tsHour, untilIso)
31654
31771
  ];
31655
31772
  if (sourceIdParam) userFetchFilters.push(eq28(aiUserFetchEventsHourly.sourceId, sourceIdParam));
31656
- const userFetchWhere = and22(...userFetchFilters);
31773
+ const userFetchWhere = and23(...userFetchFilters);
31657
31774
  const total = app.db.select({ total: sql12`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(userFetchWhere).get();
31658
31775
  aiUserFetchTotal = Number(total?.total ?? 0);
31659
31776
  const rows = app.db.select().from(aiUserFetchEventsHourly).where(userFetchWhere).orderBy(desc15(aiUserFetchEventsHourly.tsHour)).limit(limit).all();
@@ -31678,7 +31795,7 @@ async function trafficRoutes(app, opts) {
31678
31795
  lte3(aiReferralEventsHourly.tsHour, untilIso)
31679
31796
  ];
31680
31797
  if (sourceIdParam) aiFilters.push(eq28(aiReferralEventsHourly.sourceId, sourceIdParam));
31681
- const aiWhere = and22(...aiFilters);
31798
+ const aiWhere = and23(...aiFilters);
31682
31799
  const total = app.db.select({ total: sql12`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(aiWhere).get();
31683
31800
  aiReferralTotal = Number(total?.total ?? 0);
31684
31801
  const rows = app.db.select().from(aiReferralEventsHourly).where(aiWhere).orderBy(desc15(aiReferralEventsHourly.tsHour)).limit(limit).all();
@@ -31885,7 +32002,7 @@ function readInstalledManifest(skillDir) {
31885
32002
  var AGENT_CHECKS = [skillsInstalledCheck, skillsCurrentCheck];
31886
32003
 
31887
32004
  // ../api-routes/src/doctor/checks/backlinks.ts
31888
- import { and as and23, eq as eq29 } from "drizzle-orm";
32005
+ import { and as and24, eq as eq29 } from "drizzle-orm";
31889
32006
  function skippedNoProject() {
31890
32007
  return {
31891
32008
  status: CheckStatuses.skipped,
@@ -31917,7 +32034,7 @@ var BACKLINKS_CHECKS = [
31917
32034
  details: { commoncrawl: ccConnected, bingWebmaster: bingConnected }
31918
32035
  };
31919
32036
  }
31920
- const ccHasData = ccConnected ? !!ctx.db.select({ id: backlinkSummaries.id }).from(backlinkSummaries).where(and23(
32037
+ const ccHasData = ccConnected ? !!ctx.db.select({ id: backlinkSummaries.id }).from(backlinkSummaries).where(and24(
31921
32038
  eq29(backlinkSummaries.projectId, ctx.project.id),
31922
32039
  eq29(backlinkSummaries.source, BacklinkSources.commoncrawl)
31923
32040
  )).limit(1).get() : false;
@@ -32442,7 +32559,7 @@ var ga4ConnectionCheck = {
32442
32559
  var GA_AUTH_CHECKS = [ga4ConnectionCheck];
32443
32560
 
32444
32561
  // ../api-routes/src/doctor/checks/gbp-auth.ts
32445
- import { and as and24, eq as eq32 } from "drizzle-orm";
32562
+ import { and as and25, eq as eq32 } from "drizzle-orm";
32446
32563
  var RECENT_SYNC_WARN_DAYS2 = 7;
32447
32564
  var RECENT_SYNC_FAIL_DAYS2 = 30;
32448
32565
  function skippedNoProject3() {
@@ -32675,7 +32792,7 @@ var recentSyncCheck = {
32675
32792
  title: "GBP recent sync",
32676
32793
  run: (ctx) => {
32677
32794
  if (!ctx.project) return skippedNoProject3();
32678
- const selected = ctx.db.select({ locationName: gbpLocations.locationName, syncedAt: gbpLocations.syncedAt }).from(gbpLocations).where(and24(eq32(gbpLocations.projectId, ctx.project.id), eq32(gbpLocations.selected, true))).all();
32795
+ const selected = ctx.db.select({ locationName: gbpLocations.locationName, syncedAt: gbpLocations.syncedAt }).from(gbpLocations).where(and25(eq32(gbpLocations.projectId, ctx.project.id), eq32(gbpLocations.selected, true))).all();
32679
32796
  if (selected.length === 0) {
32680
32797
  return {
32681
32798
  status: CheckStatuses.skipped,
@@ -33277,7 +33394,7 @@ var RUNTIME_STATE_CHECKS = [
33277
33394
  ];
33278
33395
 
33279
33396
  // ../api-routes/src/doctor/checks/traffic-source.ts
33280
- import { and as and25, eq as eq34, gte as gte5, ne as ne4, sql as sql13 } from "drizzle-orm";
33397
+ import { and as and26, eq as eq34, gte as gte5, ne as ne4, sql as sql13 } from "drizzle-orm";
33281
33398
  var RECENT_DATA_WARN_DAYS = 7;
33282
33399
  var RECENT_DATA_FAIL_DAYS = 30;
33283
33400
  function skippedNoProject5() {
@@ -33291,7 +33408,7 @@ function skippedNoProject5() {
33291
33408
  function loadProbes(ctx) {
33292
33409
  if (!ctx.project) return [];
33293
33410
  const rows = ctx.db.select().from(trafficSources).where(
33294
- and25(
33411
+ and26(
33295
33412
  eq34(trafficSources.projectId, ctx.project.id),
33296
33413
  ne4(trafficSources.status, TrafficSourceStatuses.archived)
33297
33414
  )
@@ -33372,7 +33489,7 @@ var recentDataCheck = {
33372
33489
  const failCutoff = new Date(now.getTime() - RECENT_DATA_FAIL_DAYS * 24 * 60 * 6e4).toISOString();
33373
33490
  const recentCrawlers = Number(
33374
33491
  ctx.db.select({ total: sql13`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
33375
- and25(
33492
+ and26(
33376
33493
  eq34(crawlerEventsHourly.projectId, ctx.project.id),
33377
33494
  gte5(crawlerEventsHourly.tsHour, warnCutoff)
33378
33495
  )
@@ -33380,7 +33497,7 @@ var recentDataCheck = {
33380
33497
  );
33381
33498
  const recentReferrals = Number(
33382
33499
  ctx.db.select({ total: sql13`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
33383
- and25(
33500
+ and26(
33384
33501
  eq34(aiReferralEventsHourly.projectId, ctx.project.id),
33385
33502
  gte5(aiReferralEventsHourly.tsHour, warnCutoff)
33386
33503
  )
@@ -33396,7 +33513,7 @@ var recentDataCheck = {
33396
33513
  }
33397
33514
  const olderCrawlers = Number(
33398
33515
  ctx.db.select({ total: sql13`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
33399
- and25(
33516
+ and26(
33400
33517
  eq34(crawlerEventsHourly.projectId, ctx.project.id),
33401
33518
  gte5(crawlerEventsHourly.tsHour, failCutoff)
33402
33519
  )
@@ -33404,7 +33521,7 @@ var recentDataCheck = {
33404
33521
  );
33405
33522
  const olderReferrals = Number(
33406
33523
  ctx.db.select({ total: sql13`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
33407
- and25(
33524
+ and26(
33408
33525
  eq34(aiReferralEventsHourly.projectId, ctx.project.id),
33409
33526
  gte5(aiReferralEventsHourly.tsHour, failCutoff)
33410
33527
  )
@@ -33821,7 +33938,7 @@ async function doctorRoutes(app, opts) {
33821
33938
 
33822
33939
  // ../api-routes/src/discovery/routes.ts
33823
33940
  import crypto27 from "crypto";
33824
- import { and as and26, desc as desc16, eq as eq35, gte as gte6, inArray as inArray12, isNull, or as or5 } from "drizzle-orm";
33941
+ import { and as and27, desc as desc16, eq as eq35, gte as gte6, inArray as inArray12, isNull, or as or5 } from "drizzle-orm";
33825
33942
  var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
33826
33943
  async function discoveryRoutes(app, opts) {
33827
33944
  app.post("/projects/:name/discover/run", async (request, reply) => {
@@ -33855,7 +33972,7 @@ async function discoveryRoutes(app, opts) {
33855
33972
  const now = (/* @__PURE__ */ new Date()).toISOString();
33856
33973
  const ageFloorIso = new Date(Date.now() - MAX_INFLIGHT_DISCOVERY_AGE_MS).toISOString();
33857
33974
  const decision = app.db.transaction((tx) => {
33858
- const existing = tx.select({ id: discoverySessions.id, runId: discoverySessions.runId }).from(discoverySessions).where(and26(
33975
+ const existing = tx.select({ id: discoverySessions.id, runId: discoverySessions.runId }).from(discoverySessions).where(and27(
33859
33976
  eq35(discoverySessions.projectId, project.id),
33860
33977
  eq35(discoverySessions.icpDescription, icpDescription),
33861
33978
  // Buyer is part of session identity: it changes the seed prompt's
@@ -34501,7 +34618,7 @@ function dedupeStrings(input) {
34501
34618
 
34502
34619
  // ../api-routes/src/technical-aeo.ts
34503
34620
  import crypto29 from "crypto";
34504
- import { and as and27, asc as asc5, count, desc as desc17, eq as eq37, inArray as inArray13 } from "drizzle-orm";
34621
+ import { and as and28, asc as asc5, count, desc as desc17, eq as eq37, inArray as inArray13 } from "drizzle-orm";
34505
34622
  var SURFACEABLE_STATUSES = [RunStatuses.completed, RunStatuses.partial];
34506
34623
  function emptyScore(projectName) {
34507
34624
  return {
@@ -34533,7 +34650,7 @@ function parsePositiveInt(value, fallback, max) {
34533
34650
  async function technicalAeoRoutes(app, opts) {
34534
34651
  app.get("/projects/:name/technical-aeo", async (request) => {
34535
34652
  const project = resolveProject(app.db, request.params.name);
34536
- const rows = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(and27(
34653
+ const rows = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(and28(
34537
34654
  eq37(siteAuditSnapshots.projectId, project.id),
34538
34655
  eq37(runs.kind, RunKinds["site-audit"]),
34539
34656
  inArray13(runs.status, SURFACEABLE_STATUSES),
@@ -34568,7 +34685,7 @@ async function technicalAeoRoutes(app, opts) {
34568
34685
  });
34569
34686
  app.get("/projects/:name/technical-aeo/pages", async (request) => {
34570
34687
  const project = resolveProject(app.db, request.params.name);
34571
- const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(and27(
34688
+ const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(and28(
34572
34689
  eq37(siteAuditSnapshots.projectId, project.id),
34573
34690
  eq37(runs.kind, RunKinds["site-audit"]),
34574
34691
  inArray13(runs.status, SURFACEABLE_STATUSES),
@@ -34580,7 +34697,7 @@ async function technicalAeoRoutes(app, opts) {
34580
34697
  const statusFilter = request.query.status === "success" || request.query.status === "error" ? request.query.status : null;
34581
34698
  const conds = [eq37(siteAuditPages.runId, latest.runId)];
34582
34699
  if (statusFilter) conds.push(eq37(siteAuditPages.status, statusFilter));
34583
- const where = and27(...conds);
34700
+ const where = and28(...conds);
34584
34701
  const totalRow = app.db.select({ value: count() }).from(siteAuditPages).where(where).get();
34585
34702
  const total = totalRow?.value ?? 0;
34586
34703
  const limit = parsePositiveInt(request.query.limit, 100, 500);
@@ -34604,7 +34721,7 @@ async function technicalAeoRoutes(app, opts) {
34604
34721
  auditedAt: siteAuditSnapshots.auditedAt,
34605
34722
  aggregateScore: siteAuditSnapshots.aggregateScore,
34606
34723
  pagesAudited: siteAuditSnapshots.pagesAudited
34607
- }).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(and27(
34724
+ }).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(and28(
34608
34725
  eq37(siteAuditSnapshots.projectId, project.id),
34609
34726
  eq37(runs.kind, RunKinds["site-audit"]),
34610
34727
  inArray13(runs.status, SURFACEABLE_STATUSES),
@@ -34618,7 +34735,7 @@ async function technicalAeoRoutes(app, opts) {
34618
34735
  if (!parsed.success) {
34619
34736
  throw validationError(parsed.error.issues[0]?.message ?? "Invalid site-audit request");
34620
34737
  }
34621
- const existing = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and27(
34738
+ const existing = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and28(
34622
34739
  eq37(runs.projectId, project.id),
34623
34740
  eq37(runs.kind, RunKinds["site-audit"]),
34624
34741
  inArray13(runs.status, [RunStatuses.queued, RunStatuses.running])
@@ -34687,7 +34804,8 @@ async function apiRoutes(app, opts) {
34687
34804
  if (!opts.skipAuth) {
34688
34805
  await authPlugin(api, {
34689
34806
  sessionCookieName: opts.sessionCookieName,
34690
- resolveSessionApiKeyId: opts.resolveSessionApiKeyId
34807
+ resolveSessionApiKeyId: opts.resolveSessionApiKeyId,
34808
+ embedProjectTabs: opts.embedProjectTabs
34691
34809
  });
34692
34810
  }
34693
34811
  await api.register(openApiRoutes, { ...opts.openApiInfo, routePrefix: opts.routePrefix });
@@ -35211,7 +35329,7 @@ var IntelligenceService = class {
35211
35329
  */
35212
35330
  analyzeAndPersist(runId, projectId) {
35213
35331
  const recentRuns = this.db.select().from(runs).where(
35214
- and28(
35332
+ and29(
35215
35333
  eq38(runs.projectId, projectId),
35216
35334
  or6(eq38(runs.status, "completed"), eq38(runs.status, "partial")),
35217
35335
  // Defensive: RunCoordinator already skips probes before this is
@@ -35303,7 +35421,7 @@ var IntelligenceService = class {
35303
35421
  }
35304
35422
  const windowStart = runRow.startedAt ?? runRow.createdAt;
35305
35423
  const windowEnd = runRow.finishedAt ?? (/* @__PURE__ */ new Date()).toISOString();
35306
- const selected = this.db.select().from(gbpLocations).where(and28(
35424
+ const selected = this.db.select().from(gbpLocations).where(and29(
35307
35425
  eq38(gbpLocations.projectId, projectId),
35308
35426
  eq38(gbpLocations.selected, true),
35309
35427
  gte7(gbpLocations.syncedAt, windowStart),
@@ -35340,12 +35458,12 @@ var IntelligenceService = class {
35340
35458
  }
35341
35459
  /** Build the per-location signal bundle the GBP analyzer consumes. */
35342
35460
  buildGbpLocationSignals(projectId, locationName, displayName, fallbackDate) {
35343
- const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(and28(eq38(gbpDailyMetrics.projectId, projectId), eq38(gbpDailyMetrics.locationName, locationName))).all();
35344
- const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(and28(eq38(gbpPlaceActions.projectId, projectId), eq38(gbpPlaceActions.locationName, locationName))).all();
35345
- const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and28(eq38(gbpLodgingSnapshots.projectId, projectId), eq38(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc18(gbpLodgingSnapshots.syncedAt)).limit(1).get();
35346
- const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(and28(eq38(gbpLocations.projectId, projectId), eq38(gbpLocations.locationName, locationName))).get();
35461
+ const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(and29(eq38(gbpDailyMetrics.projectId, projectId), eq38(gbpDailyMetrics.locationName, locationName))).all();
35462
+ const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(and29(eq38(gbpPlaceActions.projectId, projectId), eq38(gbpPlaceActions.locationName, locationName))).all();
35463
+ const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and29(eq38(gbpLodgingSnapshots.projectId, projectId), eq38(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc18(gbpLodgingSnapshots.syncedAt)).limit(1).get();
35464
+ const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(and29(eq38(gbpLocations.projectId, projectId), eq38(gbpLocations.locationName, locationName))).get();
35347
35465
  const descriptionMissing = !(ownerRow?.description ?? "").trim();
35348
- const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and28(eq38(gbpPlaceDetails.projectId, projectId), eq38(gbpPlaceDetails.locationName, locationName))).orderBy(desc18(gbpPlaceDetails.syncedAt)).limit(1).get();
35466
+ const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and29(eq38(gbpPlaceDetails.projectId, projectId), eq38(gbpPlaceDetails.locationName, locationName))).orderBy(desc18(gbpPlaceDetails.syncedAt)).limit(1).get();
35349
35467
  const placesAmenities = placeRow ? extractPlaceAmenities(placeRow.attributes) : [];
35350
35468
  const summary = buildGbpSummary({
35351
35469
  locationName,
@@ -35381,7 +35499,7 @@ var IntelligenceService = class {
35381
35499
  /** Build the month-over-month keyword series for a location from the
35382
35500
  * accumulating gbp_keyword_monthly table (latest complete month vs prior). */
35383
35501
  buildGbpKeywordTrend(projectId, locationName) {
35384
- const rows = this.db.select({ month: gbpKeywordMonthly.month, keyword: gbpKeywordMonthly.keyword, valueCount: gbpKeywordMonthly.valueCount }).from(gbpKeywordMonthly).where(and28(eq38(gbpKeywordMonthly.projectId, projectId), eq38(gbpKeywordMonthly.locationName, locationName))).all();
35502
+ const rows = this.db.select({ month: gbpKeywordMonthly.month, keyword: gbpKeywordMonthly.keyword, valueCount: gbpKeywordMonthly.valueCount }).from(gbpKeywordMonthly).where(and29(eq38(gbpKeywordMonthly.projectId, projectId), eq38(gbpKeywordMonthly.locationName, locationName))).all();
35385
35503
  if (rows.length === 0) return { recentMonth: null, priorMonth: null, points: [] };
35386
35504
  const months = [...new Set(rows.map((r) => r.month))].sort().reverse();
35387
35505
  const recentMonth = months[0] ?? null;
@@ -35412,7 +35530,7 @@ var IntelligenceService = class {
35412
35530
  */
35413
35531
  persistGbpInsights(runId, projectId, gbpInsights, coveredLocationNames) {
35414
35532
  const covered = new Set(coveredLocationNames);
35415
- const existing = this.db.select({ id: insights.id, dismissed: insights.dismissed }).from(insights).where(and28(eq38(insights.projectId, projectId), eq38(insights.provider, GBP_INSIGHT_PROVIDER))).all();
35533
+ const existing = this.db.select({ id: insights.id, dismissed: insights.dismissed }).from(insights).where(and29(eq38(insights.projectId, projectId), eq38(insights.provider, GBP_INSIGHT_PROVIDER))).all();
35416
35534
  const staleIds = [];
35417
35535
  const dismissedSlots = /* @__PURE__ */ new Set();
35418
35536
  for (const row of existing) {
@@ -35514,7 +35632,7 @@ var IntelligenceService = class {
35514
35632
  sinceTimestamp = parsed;
35515
35633
  }
35516
35634
  const allRuns = this.db.select().from(runs).where(
35517
- and28(
35635
+ and29(
35518
35636
  eq38(runs.projectId, project.id),
35519
35637
  or6(eq38(runs.status, "completed"), eq38(runs.status, "partial")),
35520
35638
  // Backfill must not replay probe runs as if they were real sweeps.
@@ -35691,7 +35809,7 @@ var IntelligenceService = class {
35691
35809
  );
35692
35810
  const ROWS_PER_GROUP_BUDGET = Math.max(2, locationCount);
35693
35811
  const recentRunRows = this.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
35694
- and28(
35812
+ and29(
35695
35813
  eq38(runs.projectId, projectId),
35696
35814
  eq38(runs.kind, RunKinds["answer-visibility"]),
35697
35815
  or6(eq38(runs.status, "completed"), eq38(runs.status, "partial")),
@@ -35714,7 +35832,7 @@ var IntelligenceService = class {
35714
35832
  const haveHistory = recentRunIds.length > 0;
35715
35833
  const priorRegressionsByPair = /* @__PURE__ */ new Map();
35716
35834
  if (haveHistory) {
35717
- const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and28(eq38(insights.type, "regression"), inArray14(insights.runId, recentRunIds))).all();
35835
+ const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and29(eq38(insights.type, "regression"), inArray14(insights.runId, recentRunIds))).all();
35718
35836
  const regressionGroups = /* @__PURE__ */ new Map();
35719
35837
  for (const row of priorRows) {
35720
35838
  if (!row.runId) continue;