@canonry/canonry 7.5.1 → 7.6.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 (29) hide show
  1. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +8 -0
  2. package/assets/assets/{AuditHistoryPanel-B5aLMnWE.js → AuditHistoryPanel-DZbPVuDn.js} +1 -1
  3. package/assets/assets/{BacklinksPage-Biq1jrqe.js → BacklinksPage-6iPxcQdF.js} +1 -1
  4. package/assets/assets/{HistoryPage-CGGkAgnz.js → HistoryPage-DQ4gqs5s.js} +1 -1
  5. package/assets/assets/{MeasurementPropertyPage-BwyWGGBg.js → MeasurementPropertyPage-X4EGa3a5.js} +1 -1
  6. package/assets/assets/{ProjectPage-DEnKyD3e.js → ProjectPage-qvbLROZz.js} +1 -1
  7. package/assets/assets/{RunsPage-DNBn0Rau.js → RunsPage-DBfy79uf.js} +1 -1
  8. package/assets/assets/{SettingsPage-D3m-BLuf.js → SettingsPage-BlNafKGd.js} +1 -1
  9. package/assets/assets/{SiteHealthSection-CPMu1l-l.js → SiteHealthSection-79l2PnfR.js} +3 -3
  10. package/assets/assets/{TrafficPage-BCK_V__i.js → TrafficPage-CPZWDxjp.js} +1 -1
  11. package/assets/assets/{TrafficSourceDetailPage-DaCehUm8.js → TrafficSourceDetailPage-BIhpWiRg.js} +1 -1
  12. package/assets/assets/{extract-error-message-CqBLzzuR.js → extract-error-message-C9XX_kMH.js} +1 -1
  13. package/assets/assets/{index-C2X_UARl.js → index-CUQtRdIf.js} +20 -20
  14. package/assets/assets/{react-sigma_core.esm.min-BvO4SZKT.js → react-sigma_core.esm.min-FTRP6jVQ.js} +1 -1
  15. package/assets/assets/{v2-overview-adapter-CgDChBa5.js → v2-overview-adapter-DEuH0zoM.js} +1 -1
  16. package/assets/index.html +1 -1
  17. package/dist/{chunk-56YOI7QX.js → chunk-7FJZCG7A.js} +2 -2
  18. package/dist/{chunk-VVEMJCC6.js → chunk-B7IT47FE.js} +4 -2
  19. package/dist/{chunk-HAWCV4SU.js → chunk-BLHPFAR6.js} +22 -10
  20. package/dist/{chunk-JTQ4KFIR.js → chunk-FRSGZYQZ.js} +427 -277
  21. package/dist/{chunk-KJIXDPYH.js → chunk-HXAGDOYV.js} +3 -3
  22. package/dist/{chunk-Y7K5NMNV.js → chunk-P72CWNTU.js} +2 -2
  23. package/dist/{chunk-RVM6QJQT.js → chunk-WO7XJJHH.js} +5508 -5464
  24. package/dist/cli.js +24 -12
  25. package/dist/{demo-server-V3DDLXND.js → demo-server-Z7NM6DJT.js} +4 -4
  26. package/dist/index.js +6 -6
  27. package/dist/{intelligence-service-MZVPWIXL.js → intelligence-service-P7AOOXLZ.js} +2 -2
  28. package/dist/mcp.js +4 -4
  29. package/package.json +8 -8
@@ -105,6 +105,8 @@ import {
105
105
  POOLED_RUN_ID_LIMIT,
106
106
  PROJECTS_WRITE_SCOPE,
107
107
  PROJECT_OVERVIEW_QUERY_CLASS_SCOPE,
108
+ PROVIDER_ACCOUNT_FAILURE_STREAK,
109
+ PROVIDER_ACCOUNT_RETRY_HOURS,
108
110
  ProviderDispatchModes,
109
111
  READ_ONLY_SCOPE,
110
112
  RESEARCH_RUN_SCOPE,
@@ -447,6 +449,7 @@ import {
447
449
  isBrowserProvider,
448
450
  isLocationRedirectStatus,
449
451
  isNegativeReviewRating,
452
+ isProviderAccountFailure,
450
453
  isReadOnlyKey,
451
454
  isRetryableHttpError,
452
455
  isStrictSemver,
@@ -615,6 +618,7 @@ import {
615
618
  providerDispatchModeSchema,
616
619
  providerError,
617
620
  providerSummaryEntryDtoSchema,
621
+ providersFailing,
618
622
  queryDtoSchema,
619
623
  queryGenerateRequestSchema,
620
624
  queryTrackingCommitRequestSchema,
@@ -796,10 +800,10 @@ import {
796
800
  wordpressSchemaDeployResultDtoSchema,
797
801
  wordpressSchemaStatusResultDtoSchema,
798
802
  wordpressStatusDtoSchema
799
- } from "./chunk-RVM6QJQT.js";
803
+ } from "./chunk-WO7XJJHH.js";
800
804
 
801
805
  // src/intelligence-service.ts
802
- import { eq as eq84, desc as desc37, asc as asc15, and as and71, ne as ne15, or as or20, inArray as inArray33, gte as gte22, lte as lte20, isNull as isNull16, sql as sql31, exists as exists2 } from "drizzle-orm";
806
+ import { eq as eq84, desc as desc38, asc as asc15, and as and71, ne as ne15, or as or20, inArray as inArray34, gte as gte22, lte as lte20, isNull as isNull16, sql as sql31, exists as exists2 } from "drizzle-orm";
803
807
 
804
808
  // ../db/src/client.ts
805
809
  import { mkdirSync } from "fs";
@@ -1210,6 +1214,9 @@ var runs = sqliteTable("runs", {
1210
1214
  index("idx_runs_status").on(table.status),
1211
1215
  index("idx_runs_source").on(table.sourceId),
1212
1216
  index("idx_runs_measurement_plan").on(table.projectId, table.measurementPlanVersionId, table.createdAt),
1217
+ // A project's newest runs of one kind: run admission reads ten of them on
1218
+ // every queue (`providerAccountRefusal`), as does the failure-streak count.
1219
+ index("idx_runs_project_kind_created").on(table.projectId, table.kind, table.createdAt),
1213
1220
  foreignKey({
1214
1221
  name: "runs_measurement_plan_version_fk",
1215
1222
  columns: [table.projectId, table.measurementPlanVersionId],
@@ -8165,6 +8172,15 @@ var MIGRATION_VERSIONS = [
8165
8172
  statements: [
8166
8173
  `ALTER TABLE projects ADD COLUMN site_audit_max_pages INTEGER`
8167
8174
  ]
8175
+ },
8176
+ {
8177
+ // Run admission reads a project's ten newest runs of one kind on every
8178
+ // queue; without this it sorted every run the project ever had.
8179
+ version: 170,
8180
+ name: "runs-project-kind-created-index",
8181
+ statements: [
8182
+ `CREATE INDEX IF NOT EXISTS idx_runs_project_kind_created ON runs(project_id, kind, created_at)`
8183
+ ]
8168
8184
  }
8169
8185
  ];
8170
8186
  var AERO_LEDGER_REBUILDS = [
@@ -15288,7 +15304,7 @@ function pruneProviderDispatchModes(modes, providers, revisionProviders) {
15288
15304
 
15289
15305
  // ../api-routes/src/run-queue.ts
15290
15306
  import crypto10 from "crypto";
15291
- import { and as and10, eq as eq16, or as or4 } from "drizzle-orm";
15307
+ import { and as and10, desc as desc7, eq as eq16, gt as gt3, inArray as inArray6, or as or4 } from "drizzle-orm";
15292
15308
 
15293
15309
  // ../api-routes/src/measurement-report-adapter.ts
15294
15310
  import { and as and8, desc as desc5, eq as eq14, gte as gte2, inArray as inArray5, isNull as isNull4, lt as lt4, lte as lte5, ne as ne4 } from "drizzle-orm";
@@ -16907,6 +16923,92 @@ function resolveQueueDispatch(tx, params, stamp) {
16907
16923
  }
16908
16924
  return resolution;
16909
16925
  }
16926
+ function providersARunWouldCall(roster, runnable) {
16927
+ const listed = normalizeProviders(roster);
16928
+ if (runnable == null) return listed;
16929
+ const available = new Set(normalizeProviders(runnable));
16930
+ return listed.filter((provider) => available.has(provider));
16931
+ }
16932
+ var PROVIDER_ACCOUNT_LOOKBACK = PROVIDER_ACCOUNT_FAILURE_STREAK * 5;
16933
+ function providerSettingsChangeCouldFix(action, diff) {
16934
+ if (action === "provider.created") return true;
16935
+ try {
16936
+ const parsed = JSON.parse(diff ?? "null");
16937
+ if (!parsed) return false;
16938
+ if (parsed.apiKeyRotated) return true;
16939
+ const before = parsed.before ?? {};
16940
+ const after = parsed.after ?? {};
16941
+ return before.configured !== after.configured || before.model !== after.model || before.baseUrl !== after.baseUrl;
16942
+ } catch {
16943
+ return false;
16944
+ }
16945
+ }
16946
+ function providerAccountRefusal(db, params) {
16947
+ if (params.force || params.trigger === RunTriggers.probe) return null;
16948
+ const recent = db.select({
16949
+ id: runs.id,
16950
+ status: runs.status,
16951
+ error: runs.error,
16952
+ createdAt: runs.createdAt,
16953
+ finishedAt: runs.finishedAt
16954
+ }).from(runs).where(and10(
16955
+ eq16(runs.projectId, params.projectId),
16956
+ eq16(runs.kind, RunKinds["answer-visibility"]),
16957
+ inArray6(runs.status, [RunStatuses.completed, RunStatuses.partial, RunStatuses.failed, RunStatuses.cancelled])
16958
+ )).orderBy(desc7(runs.createdAt), desc7(runs.id)).limit(PROVIDER_ACCOUNT_LOOKBACK).all().map((run) => ({ ...run, providers: parseRunError(run.error)?.providers ?? {} }));
16959
+ const withAccountFailure = recent.filter((run) => Object.values(run.providers).some((entry) => isProviderAccountFailure(entry.code)));
16960
+ if (withAccountFailure.length < PROVIDER_ACCOUNT_FAILURE_STREAK) return null;
16961
+ const calling = normalizeProviders(params.providers());
16962
+ if (calling.length === 0) return null;
16963
+ const answered2 = (runId, provider) => db.select({ id: querySnapshots.id }).from(querySnapshots).where(and10(eq16(querySnapshots.runId, runId), eq16(querySnapshots.provider, provider))).limit(1).get() !== void 0;
16964
+ const streaks = /* @__PURE__ */ new Map();
16965
+ for (const provider of calling) {
16966
+ let count4 = 0;
16967
+ let newest2 = null;
16968
+ let oldest = null;
16969
+ let code = null;
16970
+ for (const run of recent) {
16971
+ const entry = run.providers[provider];
16972
+ if (!entry) {
16973
+ if (run.status !== RunStatuses.failed && answered2(run.id, provider)) return null;
16974
+ continue;
16975
+ }
16976
+ if (!isProviderAccountFailure(entry.code)) return null;
16977
+ newest2 ??= run;
16978
+ code ??= entry.code;
16979
+ oldest = run;
16980
+ count4 += 1;
16981
+ if (count4 === PROVIDER_ACCOUNT_FAILURE_STREAK) break;
16982
+ }
16983
+ if (count4 < PROVIDER_ACCOUNT_FAILURE_STREAK) return null;
16984
+ streaks.set(provider, { newest: newest2, oldest, code });
16985
+ }
16986
+ const finished = (run) => Date.parse(run.finishedAt ?? run.createdAt);
16987
+ const newest = [...streaks.values()].map((streak) => streak.newest).sort((a, b) => finished(b) - finished(a))[0];
16988
+ const retryAfterMs = finished(newest) + PROVIDER_ACCOUNT_RETRY_HOURS * 36e5;
16989
+ if (Date.parse(params.now) >= retryAfterMs) return null;
16990
+ const since = [...streaks.values()].map((streak) => streak.oldest.createdAt).sort()[0];
16991
+ const settingsChanges = db.select({ entityId: auditLog.entityId, action: auditLog.action, diff: auditLog.diff, createdAt: auditLog.createdAt }).from(auditLog).where(and10(eq16(auditLog.entityType, "provider"), inArray6(auditLog.entityId, calling), gt3(auditLog.createdAt, since))).all();
16992
+ const fixedSince = settingsChanges.some((change) => {
16993
+ const streak = streaks.get(change.entityId ?? "");
16994
+ return streak !== void 0 && change.createdAt > streak.oldest.createdAt && providerSettingsChangeCouldFix(change.action, change.diff);
16995
+ });
16996
+ if (fixedSince) return null;
16997
+ return {
16998
+ consecutiveRuns: PROVIDER_ACCOUNT_FAILURE_STREAK,
16999
+ latestRunId: newest.id,
17000
+ since,
17001
+ retryAfter: new Date(retryAfterMs).toISOString(),
17002
+ providers: Object.fromEntries(calling.map((provider) => [provider, streaks.get(provider).code]))
17003
+ };
17004
+ }
17005
+ function providersFailingError(projectName, failures) {
17006
+ const named = Object.entries(failures.providers).map(([provider, code]) => `${provider} (${code})`).join(", ");
17007
+ return providersFailing(
17008
+ `Not starting a run for '${projectName}': every provider it would call failed on its account (a rejected key, denied access, or no credit left) in each of its last ${failures.consecutiveRuns} runs: ${named}. Fix it in the provider's console or settings. Saving a new key, model or endpoint for the provider (canonry settings provider <name>) lets the next run through; otherwise one run is let through after ${failures.retryAfter}. Pass force (canonry run --force) to run now.`,
17009
+ { projectName, ...failures }
17010
+ );
17011
+ }
16910
17012
  function queueRunIfProjectIdle(db, params) {
16911
17013
  const createdAt = params.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
16912
17014
  const kind = params.kind ?? "answer-visibility";
@@ -16947,6 +17049,17 @@ function queueRunIfProjectIdle(db, params) {
16947
17049
  }
16948
17050
  const current = activeRun();
16949
17051
  if (current) return { conflict: true, activeRunId: current.id };
17052
+ const refused = kind === RunKinds["answer-visibility"] ? providerAccountRefusal(tx, {
17053
+ projectId: params.projectId,
17054
+ trigger: stamp?.scope ? RunTriggers.probe : trigger,
17055
+ force: params.force ?? false,
17056
+ now: createdAt,
17057
+ providers: () => providersARunWouldCall(
17058
+ stamp?.identity.providers ?? providerRoster(tx, params),
17059
+ params.runnableProviders
17060
+ )
17061
+ }) : null;
17062
+ if (refused) return { conflict: false, refused };
16950
17063
  const scoped = params.queries != null || stamp?.scope != null;
16951
17064
  const basket = scoped ? null : ensureCurrentQueryBasketRevision(tx, params.projectId, createdAt);
16952
17065
  tx.insert(runs).values({
@@ -16978,7 +17091,7 @@ function queueRunIfProjectIdle(db, params) {
16978
17091
  }
16979
17092
 
16980
17093
  // ../api-routes/src/provider-batches.ts
16981
- import { and as and11, asc as asc2, eq as eq17, inArray as inArray6 } from "drizzle-orm";
17094
+ import { and as and11, asc as asc2, eq as eq17, inArray as inArray7 } from "drizzle-orm";
16982
17095
  function formatProviderBatchSummary(row) {
16983
17096
  return {
16984
17097
  id: row.id,
@@ -17001,10 +17114,10 @@ function runHadProviderBatch(db, runId) {
17001
17114
  return db.select({ id: providerBatches.id }).from(providerBatches).where(eq17(providerBatches.runId, runId)).limit(1).get() !== void 0;
17002
17115
  }
17003
17116
  function hasOutstandingProviderBatch(db, runId) {
17004
- return db.select({ id: providerBatches.id }).from(providerBatches).where(and11(eq17(providerBatches.runId, runId), inArray6(providerBatches.status, [...OUTSTANDING_PROVIDER_BATCH_STATUSES]))).limit(1).get() !== void 0;
17117
+ return db.select({ id: providerBatches.id }).from(providerBatches).where(and11(eq17(providerBatches.runId, runId), inArray7(providerBatches.status, [...OUTSTANDING_PROVIDER_BATCH_STATUSES]))).limit(1).get() !== void 0;
17005
17118
  }
17006
17119
  function readProjectRunsWithOutstandingProviderBatch(db, projectId) {
17007
- return db.selectDistinct({ runId: providerBatches.runId }).from(providerBatches).where(and11(eq17(providerBatches.projectId, projectId), inArray6(providerBatches.status, [...OUTSTANDING_PROVIDER_BATCH_STATUSES]))).orderBy(asc2(providerBatches.runId)).all().map((row) => row.runId);
17120
+ return db.selectDistinct({ runId: providerBatches.runId }).from(providerBatches).where(and11(eq17(providerBatches.projectId, projectId), inArray7(providerBatches.status, [...OUTSTANDING_PROVIDER_BATCH_STATUSES]))).orderBy(asc2(providerBatches.runId)).all().map((row) => row.runId);
17008
17121
  }
17009
17122
 
17010
17123
  // ../api-routes/src/projects.ts
@@ -17571,13 +17684,13 @@ function aliasArraysEqual(a, b) {
17571
17684
 
17572
17685
  // ../api-routes/src/queries.ts
17573
17686
  import crypto13 from "crypto";
17574
- import { and as and14, eq as eq20, inArray as inArray8, sql as sql8 } from "drizzle-orm";
17687
+ import { and as and14, eq as eq20, inArray as inArray9, sql as sql8 } from "drizzle-orm";
17575
17688
 
17576
17689
  // ../api-routes/src/query-replace.ts
17577
17690
  import crypto12 from "crypto";
17578
- import { and as and13, eq as eq19, inArray as inArray7, isNull as isNull5 } from "drizzle-orm";
17691
+ import { and as and13, eq as eq19, inArray as inArray8, isNull as isNull5 } from "drizzle-orm";
17579
17692
  function preserveSnapshotQueryText(tx, projectId, queryIds) {
17580
- const candidates = queryIds && queryIds.length > 0 ? tx.select({ id: queries.id, text: queries.query }).from(queries).where(and13(eq19(queries.projectId, projectId), inArray7(queries.id, queryIds))).all() : tx.select({ id: queries.id, text: queries.query }).from(queries).where(eq19(queries.projectId, projectId)).all();
17693
+ const candidates = queryIds && queryIds.length > 0 ? tx.select({ id: queries.id, text: queries.query }).from(queries).where(and13(eq19(queries.projectId, projectId), inArray8(queries.id, queryIds))).all() : tx.select({ id: queries.id, text: queries.query }).from(queries).where(eq19(queries.projectId, projectId)).all();
17581
17694
  for (const q of candidates) {
17582
17695
  tx.update(querySnapshots).set({ queryText: q.text }).where(and13(eq19(querySnapshots.queryId, q.id), isNull5(querySnapshots.queryText))).run();
17583
17696
  }
@@ -17640,7 +17753,7 @@ function assertNoActivePlanlessSweep(tx, scope) {
17640
17753
  const activeRun = tx.select({ id: runs.id }).from(runs).where(and13(
17641
17754
  eq19(runs.projectId, scope.projectId),
17642
17755
  eq19(runs.kind, RunKinds["answer-visibility"]),
17643
- inArray7(runs.status, [RunStatuses.queued, RunStatuses.running]),
17756
+ inArray8(runs.status, [RunStatuses.queued, RunStatuses.running]),
17644
17757
  isNull5(runs.measurementPlanVersionId)
17645
17758
  )).get();
17646
17759
  if (activeRun) throw runInProgress(scope.projectName, RunKinds["answer-visibility"], activeRun.id);
@@ -17693,11 +17806,11 @@ function replaceProjectQueries(tx, projectId, incomingTexts, now) {
17693
17806
  for (const dup of diff.duplicates) {
17694
17807
  tx.update(querySnapshots).set({ queryId: dup.keptId }).where(eq19(querySnapshots.queryId, dup.id)).run();
17695
17808
  }
17696
- tx.delete(queries).where(inArray7(queries.id, diff.duplicates.map((d) => d.id))).run();
17809
+ tx.delete(queries).where(inArray8(queries.id, diff.duplicates.map((d) => d.id))).run();
17697
17810
  }
17698
17811
  if (diff.removed.length > 0) {
17699
17812
  const removedIds = diff.removed.map((r) => r.id);
17700
- tx.delete(queries).where(inArray7(queries.id, removedIds)).run();
17813
+ tx.delete(queries).where(inArray8(queries.id, removedIds)).run();
17701
17814
  }
17702
17815
  for (const keptRow of diff.kept) {
17703
17816
  if (keptRow.currentText !== keptRow.incomingText) {
@@ -17792,9 +17905,9 @@ async function queryRoutes(app, opts) {
17792
17905
  let snapshotsDetached = 0;
17793
17906
  let affectedQueries = 0;
17794
17907
  if (removedIds.length > 0) {
17795
- const snapshotCount = app.db.select({ n: sql8`count(*)` }).from(querySnapshots).where(inArray8(querySnapshots.queryId, removedIds)).get();
17908
+ const snapshotCount = app.db.select({ n: sql8`count(*)` }).from(querySnapshots).where(inArray9(querySnapshots.queryId, removedIds)).get();
17796
17909
  snapshotsDetached = snapshotCount?.n ?? 0;
17797
- const distinctAffected = app.db.select({ n: sql8`count(distinct ${querySnapshots.queryId})` }).from(querySnapshots).where(inArray8(querySnapshots.queryId, removedIds)).get();
17910
+ const distinctAffected = app.db.select({ n: sql8`count(distinct ${querySnapshots.queryId})` }).from(querySnapshots).where(inArray9(querySnapshots.queryId, removedIds)).get();
17798
17911
  affectedQueries = distinctAffected?.n ?? 0;
17799
17912
  }
17800
17913
  return reply.send({
@@ -18244,7 +18357,7 @@ function parseBody(schema, value, message) {
18244
18357
  }
18245
18358
 
18246
18359
  // ../api-routes/src/competitor-landscape.ts
18247
- import { and as and17, desc as desc7, eq as eq24, gte as gte3, inArray as inArray9, isNull as isNull6 } from "drizzle-orm";
18360
+ import { and as and17, desc as desc8, eq as eq24, gte as gte3, inArray as inArray10, isNull as isNull6 } from "drizzle-orm";
18248
18361
 
18249
18362
  // ../api-routes/src/mention-share-inputs.ts
18250
18363
  import { eq as eq22 } from "drizzle-orm";
@@ -19057,11 +19170,11 @@ function latestSweepRuns(db, projectId) {
19057
19170
  const candidates = db.select().from(runs).where(and17(
19058
19171
  eq24(runs.projectId, projectId),
19059
19172
  eq24(runs.kind, RunKinds["answer-visibility"]),
19060
- inArray9(runs.status, [RunStatuses.completed, RunStatuses.partial]),
19173
+ inArray10(runs.status, [RunStatuses.completed, RunStatuses.partial]),
19061
19174
  notProbeRun(),
19062
19175
  // A scoped spot check is never the latest sweep.
19063
19176
  isNull6(runs.measurementScope)
19064
- )).orderBy(desc7(runs.createdAt), desc7(runs.id)).all();
19177
+ )).orderBy(desc8(runs.createdAt), desc8(runs.id)).all();
19065
19178
  for (const group of groupRunsByCreatedAt(candidates)) {
19066
19179
  const whole = group.filter((run) => measurementRunCompleteness(db, run.id).complete);
19067
19180
  if (whole.length > 0) return whole;
@@ -19086,8 +19199,8 @@ function readCompetitorLandscape(app, projectName, query, selection) {
19086
19199
  const candidateRuns = app.db.select().from(runs).where(and17(
19087
19200
  eq24(runs.projectId, project.id),
19088
19201
  eq24(runs.kind, RunKinds["answer-visibility"]),
19089
- selection ? inArray9(runs.id, [...selection.runIds]) : void 0,
19090
- latestRunIds ? inArray9(runs.id, latestRunIds) : filters.runId ? eq24(runs.id, filters.runId) : void 0,
19202
+ selection ? inArray10(runs.id, [...selection.runIds]) : void 0,
19203
+ latestRunIds ? inArray10(runs.id, latestRunIds) : filters.runId ? eq24(runs.id, filters.runId) : void 0,
19091
19204
  cutoff ? gte3(runs.createdAt, cutoff) : void 0
19092
19205
  )).all();
19093
19206
  const advanced = filters.groupKey || filters.scope === "all-markets" ? resolveAdvancedScope(app, project.id, filters.groupKey ? "group" : "all-markets", filters.groupKey, candidateRuns) : null;
@@ -19115,7 +19228,7 @@ function readCompetitorLandscape(app, projectName, query, selection) {
19115
19228
  location: querySnapshots.location,
19116
19229
  measurementExecutionId: querySnapshots.measurementExecutionId,
19117
19230
  createdAt: querySnapshots.createdAt
19118
- }).from(querySnapshots).where(inArray9(querySnapshots.runId, candidateRuns.map((run) => run.id))).all();
19231
+ }).from(querySnapshots).where(inArray10(querySnapshots.runId, candidateRuns.map((run) => run.id))).all();
19119
19232
  const runById = new Map(candidateRuns.map((run) => [run.id, run]));
19120
19233
  const selectedIds = selection?.snapshotIds ? new Set(selection.snapshotIds) : null;
19121
19234
  const inScope = allSnapshots.filter((snapshot) => (!selectedIds || selectedIds.has(snapshot.id)) && snapshotMatchesFilters({
@@ -19299,7 +19412,7 @@ function frozenRunScopes(db, projectId, kind, groupKey, candidateRuns) {
19299
19412
  const planVersionIds = [...new Set(candidateRuns.map((run) => run.measurementPlanVersionId).filter((id) => typeof id === "string" && id.length > 0))];
19300
19413
  const historicalVersions = planVersionIds.length === 0 ? [] : db.select().from(measurementPlanVersions).where(and17(
19301
19414
  eq24(measurementPlanVersions.projectId, projectId),
19302
- inArray9(measurementPlanVersions.id, planVersionIds)
19415
+ inArray10(measurementPlanVersions.id, planVersionIds)
19303
19416
  )).all();
19304
19417
  const frozenByVersionId = new Map(historicalVersions.map((version) => [
19305
19418
  version.id,
@@ -19437,12 +19550,12 @@ function mergePins(...collections) {
19437
19550
 
19438
19551
  // ../api-routes/src/runs.ts
19439
19552
  import crypto15 from "crypto";
19440
- import { and as and19, eq as eq26, asc as asc3, desc as desc9, inArray as inArray11, or as or6, sql as sql10 } from "drizzle-orm";
19553
+ import { and as and19, eq as eq26, asc as asc3, desc as desc10, inArray as inArray12, or as or6, sql as sql10 } from "drizzle-orm";
19441
19554
  import { gte as gte4 } from "drizzle-orm";
19442
19555
 
19443
19556
  // ../api-routes/src/run-fill.ts
19444
19557
  import crypto14 from "crypto";
19445
- import { and as and18, desc as desc8, eq as eq25, gt as gt3, inArray as inArray10, isNull as isNull7, ne as ne5, or as or5, sql as sql9 } from "drizzle-orm";
19558
+ import { and as and18, desc as desc9, eq as eq25, gt as gt4, inArray as inArray11, isNull as isNull7, ne as ne5, or as or5, sql as sql9 } from "drizzle-orm";
19446
19559
  var ACTIVE_STATUSES = ["queued", "running"];
19447
19560
  function normalizeProvider(value) {
19448
19561
  return value.trim().toLocaleLowerCase("en");
@@ -19470,12 +19583,12 @@ function newerFullSweep(db, run) {
19470
19583
  ne5(runs.trigger, RunTriggers.probe),
19471
19584
  isNull7(runs.measurementScope),
19472
19585
  isNull7(runs.queries),
19473
- gt3(runs.createdAt, run.createdAt),
19586
+ gt4(runs.createdAt, run.createdAt),
19474
19587
  or5(
19475
- inArray10(runs.status, ["queued", "running", "completed", "partial"]),
19588
+ inArray11(runs.status, ["queued", "running", "completed", "partial"]),
19476
19589
  sql9`EXISTS (SELECT 1 FROM ${querySnapshots} WHERE ${querySnapshots.runId} = ${runs.id})`
19477
19590
  )
19478
- )).orderBy(desc8(runs.createdAt)).get();
19591
+ )).orderBy(desc9(runs.createdAt)).get();
19479
19592
  }
19480
19593
  function measuredOnRetiredModel(run, provider, missing) {
19481
19594
  const recorded = run.measurementExecutionIdentity?.models[provider];
@@ -19611,16 +19724,16 @@ function evaluateRunFill(db, run, input = {}) {
19611
19724
  return { kind: "fillable", slots, providers, missing };
19612
19725
  }
19613
19726
  function latestFillFor(db, runId) {
19614
- return db.select().from(runFills).where(eq25(runFills.runId, runId)).orderBy(desc8(runFills.createdAt), desc8(runFills.id)).get();
19727
+ return db.select().from(runFills).where(eq25(runFills.runId, runId)).orderBy(desc9(runFills.createdAt), desc9(runFills.id)).get();
19615
19728
  }
19616
19729
  function activeFillFor(db, projectId) {
19617
- return db.select().from(runFills).where(and18(eq25(runFills.projectId, projectId), inArray10(runFills.status, [...ACTIVE_STATUSES]))).get();
19730
+ return db.select().from(runFills).where(and18(eq25(runFills.projectId, projectId), inArray11(runFills.status, [...ACTIVE_STATUSES]))).get();
19618
19731
  }
19619
19732
  function activeSweepFor(db, projectId) {
19620
19733
  return db.select({ id: runs.id }).from(runs).where(and18(
19621
19734
  eq25(runs.projectId, projectId),
19622
19735
  eq25(runs.kind, RunKinds["answer-visibility"]),
19623
- inArray10(runs.status, [...ACTIVE_STATUSES])
19736
+ inArray11(runs.status, [...ACTIVE_STATUSES])
19624
19737
  )).get();
19625
19738
  }
19626
19739
  function readRunCompleteness(db, run, input = {}) {
@@ -19793,6 +19906,22 @@ async function runRoutes(app, opts) {
19793
19906
  if (activeRun) {
19794
19907
  return { conflict: true, activeRunId: activeRun.id };
19795
19908
  }
19909
+ const refused = providerAccountRefusal(tx, {
19910
+ projectId: project.id,
19911
+ trigger,
19912
+ force: body.force ?? false,
19913
+ now,
19914
+ providers: () => {
19915
+ const runnable = opts.getRunnableProviderNames?.();
19916
+ const roster = resolveRunnableProviderSelection({
19917
+ requestedProviders: providers,
19918
+ projectProviders: project.providers,
19919
+ runnableProviders: runnable
19920
+ }).selectedProviders;
19921
+ return providersARunWouldCall(roster, runnable);
19922
+ }
19923
+ });
19924
+ if (refused) return { conflict: false, refused };
19796
19925
  const inserted = [];
19797
19926
  for (const loc of projectLocations) {
19798
19927
  const runId2 = crypto15.randomUUID();
@@ -19813,6 +19942,7 @@ async function runRoutes(app, opts) {
19813
19942
  if (result.conflict) {
19814
19943
  throw runInProgress(project.name, kind, result.activeRunId);
19815
19944
  }
19945
+ if (result.refused) throw providersFailingError(project.name, result.refused);
19816
19946
  const results = [];
19817
19947
  for (const { runId: runId2, loc } of result.inserted) {
19818
19948
  writeAuditLog(app.db, {
@@ -19843,9 +19973,11 @@ async function runRoutes(app, opts) {
19843
19973
  providerModels: opts.getEffectiveProviderModels?.(),
19844
19974
  measurementScope: body.measurementScope ?? null,
19845
19975
  dispatchMode: body.dispatchMode ?? null,
19846
- batchEligibleProviders: opts.getBatchEligibleProviderNames?.() ?? null
19976
+ batchEligibleProviders: opts.getBatchEligibleProviderNames?.() ?? null,
19977
+ force: body.force ?? false
19847
19978
  });
19848
19979
  if (queueResult.conflict) throw runInProgress(project.name, kind, queueResult.activeRunId);
19980
+ if (queueResult.refused) throw providersFailingError(project.name, queueResult.refused);
19849
19981
  const runId = queueResult.runId;
19850
19982
  writeAuditLog(app.db, {
19851
19983
  projectId: project.id,
@@ -19869,14 +20001,14 @@ async function runRoutes(app, opts) {
19869
20001
  if (kind) filters.push(eq26(runs.kind, kind));
19870
20002
  if (status) filters.push(eq26(runs.status, status));
19871
20003
  const where = and19(...filters);
19872
- const rows = limit == null ? app.db.select().from(runs).where(where).orderBy(asc3(runs.createdAt)).all() : app.db.select().from(runs).where(where).orderBy(desc9(runs.createdAt)).limit(limit).all().reverse();
20004
+ const rows = limit == null ? app.db.select().from(runs).where(where).orderBy(asc3(runs.createdAt)).all() : app.db.select().from(runs).where(where).orderBy(desc10(runs.createdAt)).limit(limit).all().reverse();
19873
20005
  return reply.send(rows.map(formatRun));
19874
20006
  });
19875
20007
  app.get("/projects/:name/runs/latest", async (request, reply) => {
19876
20008
  const project = resolveProject(app.db, request.params.name);
19877
20009
  const countRow = app.db.select({ count: sql10`count(*)` }).from(runs).where(and19(eq26(runs.projectId, project.id), notProbeRun())).get();
19878
20010
  const totalRuns = countRow?.count ?? 0;
19879
- const latestRun = app.db.select().from(runs).where(and19(eq26(runs.projectId, project.id), notProbeRun())).orderBy(desc9(runs.createdAt), desc9(runs.id)).limit(1).get();
20011
+ const latestRun = app.db.select().from(runs).where(and19(eq26(runs.projectId, project.id), notProbeRun())).orderBy(desc10(runs.createdAt), desc10(runs.id)).limit(1).get();
19880
20012
  if (!latestRun) {
19881
20013
  return reply.send({ totalRuns: 0, run: null });
19882
20014
  }
@@ -19896,7 +20028,7 @@ async function runRoutes(app, opts) {
19896
20028
  if (status) filters.push(eq26(runs.status, status));
19897
20029
  const scopedProjectId = request.apiKey?.projectId;
19898
20030
  if (scopedProjectId) filters.push(eq26(runs.projectId, scopedProjectId));
19899
- const rows = app.db.select().from(runs).where(and19(...filters)).orderBy(desc9(runs.createdAt), desc9(runs.id)).limit(limit).all();
20031
+ const rows = app.db.select().from(runs).where(and19(...filters)).orderBy(desc10(runs.createdAt), desc10(runs.id)).limit(limit).all();
19900
20032
  return reply.send(rows.map(formatRun));
19901
20033
  });
19902
20034
  app.post("/runs", async (request, reply) => {
@@ -19913,6 +20045,8 @@ async function runRoutes(app, opts) {
19913
20045
  }
19914
20046
  const dispatchMode = parsedDispatchMode.data ?? null;
19915
20047
  const batchEligibleProviders = opts.getBatchEligibleProviderNames?.() ?? null;
20048
+ const force = request.body?.force;
20049
+ if (force !== void 0 && typeof force !== "boolean") throw validationError('"force" must be a boolean');
19916
20050
  const rawProviders = request.body?.providers;
19917
20051
  if (rawProviders?.length) {
19918
20052
  const normalized = rawProviders.map((p) => p.trim().toLowerCase()).filter(Boolean);
@@ -20008,12 +20142,18 @@ async function runRoutes(app, opts) {
20008
20142
  runnableProviders: runnableProviderNames,
20009
20143
  providerModels: opts.getEffectiveProviderModels?.(),
20010
20144
  dispatchMode,
20011
- batchEligibleProviders
20145
+ batchEligibleProviders,
20146
+ force: force ?? false
20012
20147
  });
20013
20148
  if (queueResult.conflict) {
20014
20149
  results.push({ projectName: project.name, projectId: project.id, status: "conflict", error: "run_in_progress" });
20015
20150
  continue;
20016
20151
  }
20152
+ if (queueResult.refused) {
20153
+ const refusal = providersFailingError(project.name, queueResult.refused);
20154
+ results.push({ projectName: project.name, projectId: project.id, status: "error", error: refusal.message, errorCode: refusal.code });
20155
+ continue;
20156
+ }
20017
20157
  const runId = queueResult.runId;
20018
20158
  writeAuditLog(app.db, {
20019
20159
  projectId: project.id,
@@ -20037,7 +20177,7 @@ async function runRoutes(app, opts) {
20037
20177
  const terminalStatuses = /* @__PURE__ */ new Set(["completed", "partial", "failed", "cancelled"]);
20038
20178
  if (terminalStatuses.has(run.status)) throw runNotCancellable(run.id, run.status);
20039
20179
  const now = (/* @__PURE__ */ new Date()).toISOString();
20040
- const cancelled = app.db.update(runs).set({ status: "cancelled", finishedAt: now, error: serializeRunError({ message: "Cancelled by user" }) }).where(and19(eq26(runs.id, run.id), inArray11(runs.status, ["queued", "running"]))).run();
20180
+ const cancelled = app.db.update(runs).set({ status: "cancelled", finishedAt: now, error: serializeRunError({ message: "Cancelled by user" }) }).where(and19(eq26(runs.id, run.id), inArray12(runs.status, ["queued", "running"]))).run();
20041
20181
  if (cancelled.changes === 0) {
20042
20182
  const current = app.db.select().from(runs).where(eq26(runs.id, run.id)).get();
20043
20183
  if (!current) throw notFound("Run", run.id);
@@ -20303,7 +20443,7 @@ function loadRunDetail(app, run) {
20303
20443
 
20304
20444
  // ../api-routes/src/measurement-plan.ts
20305
20445
  import crypto16 from "crypto";
20306
- import { and as and20, desc as desc10, eq as eq27 } from "drizzle-orm";
20446
+ import { and as and20, desc as desc11, eq as eq27 } from "drizzle-orm";
20307
20447
  var MEASUREMENT_PLAN_WRITE_SCOPE = "measurement-plan.write";
20308
20448
  function parseStoredPlanAnyVersion(canonicalJson3) {
20309
20449
  return parseStoredMeasurementPlanAnyVersion(canonicalJson3);
@@ -20660,7 +20800,7 @@ async function measurementPlanRoutes(app, opts) {
20660
20800
  app.get("/projects/:name/measurement-plan/versions", async (request) => {
20661
20801
  const project = resolveProject(app.db, request.params.name);
20662
20802
  const active = activePlanVersion(app, project.id);
20663
- const versions = app.db.select().from(measurementPlanVersions).where(eq27(measurementPlanVersions.projectId, project.id)).orderBy(desc10(measurementPlanVersions.revision)).all();
20803
+ const versions = app.db.select().from(measurementPlanVersions).where(eq27(measurementPlanVersions.projectId, project.id)).orderBy(desc11(measurementPlanVersions.revision)).all();
20664
20804
  return {
20665
20805
  versions: versions.map((version) => versionMetadata(version, active?.version.id ?? null))
20666
20806
  };
@@ -21401,7 +21541,7 @@ async function measurementServiceRoutes(app, opts) {
21401
21541
 
21402
21542
  // ../api-routes/src/measurement-draft.ts
21403
21543
  import crypto19 from "crypto";
21404
- import { and as and21, asc as asc4, desc as desc11, eq as eq28, inArray as inArray12 } from "drizzle-orm";
21544
+ import { and as and21, asc as asc4, desc as desc12, eq as eq28, inArray as inArray13 } from "drizzle-orm";
21405
21545
 
21406
21546
  // ../api-routes/src/measurement-draft-compile.ts
21407
21547
  var MEASUREMENT_DRAFT_MAX_TARGETS = 1e3;
@@ -23553,7 +23693,7 @@ async function measurementDraftRoutes(app, opts = {}) {
23553
23693
  // The comparable chain, not the bare active id: a label-only
23554
23694
  // republish must not flip setup back to awaiting_first_run while
23555
23695
  // the overview keeps serving the prior run.
23556
- inArray12(runs.measurementPlanVersionId, comparableMeasurementVersionIds(app.db, project.id, active.id)),
23696
+ inArray13(runs.measurementPlanVersionId, comparableMeasurementVersionIds(app.db, project.id, active.id)),
23557
23697
  eq28(runs.status, RunStatuses.completed)
23558
23698
  )).get() : void 0;
23559
23699
  const state = activeSchemaVersion === 1 ? "republish_required" : draft ? "setup_in_progress" : active ? completedRun ? "operational" : "awaiting_first_run" : "simple";
@@ -24038,7 +24178,7 @@ async function measurementDraftRoutes(app, opts = {}) {
24038
24178
  }));
24039
24179
  return settle(false, active, parseV2Plan(active));
24040
24180
  }
24041
- const latest = tx.select({ revision: measurementPlanVersions.revision }).from(measurementPlanVersions).where(eq28(measurementPlanVersions.projectId, gate.project.id)).orderBy(desc11(measurementPlanVersions.revision)).get();
24181
+ const latest = tx.select({ revision: measurementPlanVersions.revision }).from(measurementPlanVersions).where(eq28(measurementPlanVersions.projectId, gate.project.id)).orderBy(desc12(measurementPlanVersions.revision)).get();
24042
24182
  const revision = (latest?.revision ?? 0) + 1;
24043
24183
  const canonicalJson3 = canonicalMeasurementPlanV2Json(compiled.plan);
24044
24184
  const versionId = crypto19.randomUUID();
@@ -24175,7 +24315,7 @@ async function measurementDraftRoutes(app, opts = {}) {
24175
24315
  const sets = app.db.select().from(measurementQuerySets).where(eq28(measurementQuerySets.projectId, project.id)).orderBy(asc4(measurementQuerySets.name)).all();
24176
24316
  const counts2 = /* @__PURE__ */ new Map();
24177
24317
  if (sets.length) {
24178
- for (const item2 of app.db.select({ querySetId: measurementQuerySetItems.querySetId }).from(measurementQuerySetItems).where(inArray12(measurementQuerySetItems.querySetId, sets.map((set) => set.id))).all()) {
24318
+ for (const item2 of app.db.select({ querySetId: measurementQuerySetItems.querySetId }).from(measurementQuerySetItems).where(inArray13(measurementQuerySetItems.querySetId, sets.map((set) => set.id))).all()) {
24179
24319
  counts2.set(item2.querySetId, (counts2.get(item2.querySetId) ?? 0) + 1);
24180
24320
  }
24181
24321
  }
@@ -24404,7 +24544,7 @@ async function measurementDraftRoutes(app, opts = {}) {
24404
24544
  diff: { created: created.length, existing: existing.length }
24405
24545
  }));
24406
24546
  if (!querySet) return;
24407
- const highest = tx.select({ position: measurementQuerySetItems.position }).from(measurementQuerySetItems).where(eq28(measurementQuerySetItems.querySetId, querySet.id)).orderBy(desc11(measurementQuerySetItems.position)).get();
24547
+ const highest = tx.select({ position: measurementQuerySetItems.position }).from(measurementQuerySetItems).where(eq28(measurementQuerySetItems.querySetId, querySet.id)).orderBy(desc12(measurementQuerySetItems.position)).get();
24408
24548
  let position = (highest?.position ?? -1) + 1;
24409
24549
  const present = new Set(tx.select({ queryId: measurementQuerySetItems.queryId }).from(measurementQuerySetItems).where(eq28(measurementQuerySetItems.querySetId, querySet.id)).all().map((item2) => item2.queryId));
24410
24550
  for (const entry of ordered) {
@@ -25077,10 +25217,10 @@ async function measurementPropertyEvidenceRoutes(app) {
25077
25217
  }
25078
25218
 
25079
25219
  // ../api-routes/src/measurement-portfolio-reads.ts
25080
- import { and as and25, desc as desc12, eq as eq32, inArray as inArray14, lt as lt5, or as or7 } from "drizzle-orm";
25220
+ import { and as and25, desc as desc13, eq as eq32, inArray as inArray15, lt as lt5, or as or7 } from "drizzle-orm";
25081
25221
 
25082
25222
  // ../api-routes/src/measurement-question-reads.ts
25083
- import { and as and24, eq as eq31, getTableColumns, inArray as inArray13, sql as sql11 } from "drizzle-orm";
25223
+ import { and as and24, eq as eq31, getTableColumns, inArray as inArray14, sql as sql11 } from "drizzle-orm";
25084
25224
  var DEFAULT_LIMIT2 = 50;
25085
25225
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
25086
25226
  RunStatuses.completed,
@@ -25196,7 +25336,7 @@ function selectedQuestionSnapshots(db, runId, manifest, scope) {
25196
25336
  if (scope !== void 0) {
25197
25337
  const executionIds = [...new Set(manifest.expectedSlots.map((slot) => slot.executionId))];
25198
25338
  if (executionIds.length === 0) return [];
25199
- conditions.push(inArray13(querySnapshots.measurementExecutionId, executionIds));
25339
+ conditions.push(inArray14(querySnapshots.measurementExecutionId, executionIds));
25200
25340
  }
25201
25341
  if (scope?.provider !== void 0) {
25202
25342
  conditions.push(sql11`lower(trim(${querySnapshots.provider})) = ${normalizeText(scope.provider)}`);
@@ -25211,7 +25351,7 @@ function rawResponsesForLegacyQuestionSnapshots(db, runId, snapshots) {
25211
25351
  rawResponse: querySnapshots.rawResponse
25212
25352
  }).from(querySnapshots).where(and24(
25213
25353
  eq31(querySnapshots.runId, runId),
25214
- inArray13(querySnapshots.id, legacyIds)
25354
+ inArray14(querySnapshots.id, legacyIds)
25215
25355
  )).all().map((snapshot) => [snapshot.id, snapshot.rawResponse]));
25216
25356
  }
25217
25357
  function withLegacyRawEvidence(db, runId, snapshots) {
@@ -26140,14 +26280,14 @@ function previousComparableRun(db, active, current) {
26140
26280
  // republish: a run pinned to a comparable prior revision measured exactly
26141
26281
  // the questions the active revision asks. The execution-identity and scope
26142
26282
  // checks below still gate what actually compares.
26143
- inArray14(runs.measurementPlanVersionId, comparableMeasurementVersionIds(db, current.projectId, active.version.id)),
26283
+ inArray15(runs.measurementPlanVersionId, comparableMeasurementVersionIds(db, current.projectId, active.version.id)),
26144
26284
  eq32(runs.kind, RunKinds["answer-visibility"]),
26145
- inArray14(runs.status, [RunStatuses.completed, RunStatuses.partial]),
26285
+ inArray15(runs.status, [RunStatuses.completed, RunStatuses.partial]),
26146
26286
  or7(
26147
26287
  lt5(runs.createdAt, current.createdAt),
26148
26288
  and25(eq32(runs.createdAt, current.createdAt), lt5(runs.id, current.id))
26149
26289
  )
26150
- )).orderBy(desc12(runs.createdAt), desc12(runs.id)).all().filter((candidate) => (
26290
+ )).orderBy(desc13(runs.createdAt), desc13(runs.id)).all().filter((candidate) => (
26151
26291
  // Full reporting never admits probes. A plan slice is itself stored as a
26152
26292
  // probe, so an explicitly selected slice compares only with other slices;
26153
26293
  // the exact frozen scope check below then keeps the population identical.
@@ -26399,7 +26539,7 @@ function unattributedByClass(plan, run, materialized) {
26399
26539
  return { branded: read("branded"), nonBrand: read("non-brand") };
26400
26540
  }
26401
26541
  function latestRunFill(db, runId) {
26402
- const fill = db.select().from(runFills).where(eq32(runFills.runId, runId)).orderBy(desc12(runFills.createdAt), desc12(runFills.id)).get();
26542
+ const fill = db.select().from(runFills).where(eq32(runFills.runId, runId)).orderBy(desc13(runFills.createdAt), desc13(runFills.id)).get();
26403
26543
  if (!fill) return null;
26404
26544
  const { status, providers, expected, filled, createdAt, finishedAt } = formatRunFill(fill);
26405
26545
  return { status, providers, expected, filled, createdAt, finishedAt };
@@ -26551,7 +26691,7 @@ async function measurementPortfolioReadRoutes(app) {
26551
26691
 
26552
26692
  // ../api-routes/src/visibility-report.ts
26553
26693
  import { createHash as createHash7 } from "crypto";
26554
- import { and as and26, desc as desc13, eq as eq33, gte as gte5, inArray as inArray15, isNotNull as isNotNull4, isNull as isNull8, lt as lt6, lte as lte6, or as or8 } from "drizzle-orm";
26694
+ import { and as and26, desc as desc14, eq as eq33, gte as gte5, inArray as inArray16, isNotNull as isNotNull4, isNull as isNull8, lt as lt6, lte as lte6, or as or8 } from "drizzle-orm";
26555
26695
 
26556
26696
  // ../api-routes/src/measurement-scope-options.ts
26557
26697
  function marketLinks(keys, settings) {
@@ -27370,7 +27510,7 @@ function loadVisibilitySnapshots(db, runIds) {
27370
27510
  requestedContext: querySnapshots.requestedContext,
27371
27511
  supportedContext: querySnapshots.supportedContext,
27372
27512
  createdAt: querySnapshots.createdAt
27373
- }).from(querySnapshots).where(inArray15(querySnapshots.runId, [...runIds])).all();
27513
+ }).from(querySnapshots).where(inArray16(querySnapshots.runId, [...runIds])).all();
27374
27514
  for (const row of rows) {
27375
27515
  const snapshots = byRun.get(row.runId) ?? [];
27376
27516
  snapshots.push(row);
@@ -27783,7 +27923,7 @@ function completedVisibilityRuns(db, projectId, planless, query) {
27783
27923
  return db.select().from(runs).where(and26(
27784
27924
  eq33(runs.projectId, projectId),
27785
27925
  eq33(runs.kind, RunKinds["answer-visibility"]),
27786
- inArray15(runs.status, [RunStatuses.completed, RunStatuses.partial]),
27926
+ inArray16(runs.status, [RunStatuses.completed, RunStatuses.partial]),
27787
27927
  notProbeRun(),
27788
27928
  planless ? isNull8(runs.measurementPlanVersionId) : isNotNull4(runs.measurementPlanVersionId),
27789
27929
  // A scoped spot check is never a whole-project sweep. It can be inspected
@@ -27792,13 +27932,13 @@ function completedVisibilityRuns(db, projectId, planless, query) {
27792
27932
  query.runId === void 0 ? void 0 : eq33(runs.id, query.runId),
27793
27933
  query.from === void 0 ? void 0 : gte5(runs.createdAt, query.from),
27794
27934
  query.to === void 0 ? void 0 : lte6(runs.createdAt, query.to)
27795
- )).orderBy(desc13(runs.createdAt), desc13(runs.id)).limit(VISIBILITY_REPORT_MAX_RUNS).all();
27935
+ )).orderBy(desc14(runs.createdAt), desc14(runs.id)).limit(VISIBILITY_REPORT_MAX_RUNS).all();
27796
27936
  }
27797
27937
  function previousEligibleVisibilityRun(db, projectId, planless, selected) {
27798
27938
  return db.select().from(runs).where(and26(
27799
27939
  eq33(runs.projectId, projectId),
27800
27940
  eq33(runs.kind, RunKinds["answer-visibility"]),
27801
- inArray15(runs.status, [RunStatuses.completed, RunStatuses.partial]),
27941
+ inArray16(runs.status, [RunStatuses.completed, RunStatuses.partial]),
27802
27942
  notProbeRun(),
27803
27943
  planless ? isNull8(runs.measurementPlanVersionId) : isNotNull4(runs.measurementPlanVersionId),
27804
27944
  isNull8(runs.measurementScope),
@@ -27806,7 +27946,7 @@ function previousEligibleVisibilityRun(db, projectId, planless, selected) {
27806
27946
  lt6(runs.createdAt, selected.createdAt),
27807
27947
  and26(eq33(runs.createdAt, selected.createdAt), lt6(runs.id, selected.id))
27808
27948
  )
27809
- )).orderBy(desc13(runs.createdAt), desc13(runs.id)).limit(1).get();
27949
+ )).orderBy(desc14(runs.createdAt), desc14(runs.id)).limit(1).get();
27810
27950
  }
27811
27951
  function readPreviousSweep(read) {
27812
27952
  try {
@@ -27937,7 +28077,7 @@ function frozenSimpleDefinitions(db, projectId, runIds) {
27937
28077
  if (runIds.length === 0) return /* @__PURE__ */ new Map();
27938
28078
  return new Map(db.select().from(simpleMeasurementDefinitions).where(and26(
27939
28079
  eq33(simpleMeasurementDefinitions.projectId, projectId),
27940
- inArray15(simpleMeasurementDefinitions.runId, [...runIds])
28080
+ inArray16(simpleMeasurementDefinitions.runId, [...runIds])
27941
28081
  )).all().map((row) => [row.runId, row.definition]));
27942
28082
  }
27943
28083
  function simpleRunInput(db, project, run, definition, includeEvidence) {
@@ -28006,7 +28146,7 @@ function readVisibilityComparisonRuns(db, projectId, since, until, includeEviden
28006
28146
  const sourceRuns = db.select().from(runs).where(and26(
28007
28147
  eq33(runs.projectId, projectId),
28008
28148
  eq33(runs.kind, RunKinds["answer-visibility"]),
28009
- inArray15(runs.status, [RunStatuses.completed, RunStatuses.partial]),
28149
+ inArray16(runs.status, [RunStatuses.completed, RunStatuses.partial]),
28010
28150
  notProbeRun(),
28011
28151
  isNotNull4(runs.measurementPlanVersionId),
28012
28152
  isNull8(runs.measurementScope),
@@ -28036,7 +28176,7 @@ function readVisibilityComparisonRuns(db, projectId, since, until, includeEviden
28036
28176
 
28037
28177
  // ../api-routes/src/query-tracking.ts
28038
28178
  import crypto21 from "crypto";
28039
- import { and as and27, desc as desc14, eq as eq34, inArray as inArray16, isNotNull as isNotNull5, isNull as isNull9, ne as ne6 } from "drizzle-orm";
28179
+ import { and as and27, desc as desc15, eq as eq34, inArray as inArray17, isNotNull as isNotNull5, isNull as isNull9, ne as ne6 } from "drizzle-orm";
28040
28180
  var SOURCE_LIMIT = 100;
28041
28181
  var MAX_REVIEW_AGE_MS = 15 * 60 * 1e3;
28042
28182
  var MAX_REVIEW_FUTURE_SKEW_MS = 60 * 1e3;
@@ -28222,11 +28362,11 @@ function simpleMeasuredAtByQuery(db, project, queryRows2, opts) {
28222
28362
  }).from(runs).where(and27(
28223
28363
  eq34(runs.projectId, project.id),
28224
28364
  eq34(runs.kind, RunKinds["answer-visibility"]),
28225
- inArray16(runs.status, [RunStatuses.completed, RunStatuses.partial]),
28365
+ inArray17(runs.status, [RunStatuses.completed, RunStatuses.partial]),
28226
28366
  ne6(runs.trigger, RunTriggers.probe),
28227
28367
  isNull9(runs.measurementScope),
28228
28368
  isNull9(runs.measurementPlanVersionId)
28229
- )).orderBy(desc14(runs.createdAt), desc14(runs.id)).limit(SOURCE_LIMIT).all();
28369
+ )).orderBy(desc15(runs.createdAt), desc15(runs.id)).limit(SOURCE_LIMIT).all();
28230
28370
  if (eligibleRuns.length === 0) return /* @__PURE__ */ new Map();
28231
28371
  const frozenByRun = /* @__PURE__ */ new Map();
28232
28372
  for (const row of db.select({
@@ -28234,7 +28374,7 @@ function simpleMeasuredAtByQuery(db, project, queryRows2, opts) {
28234
28374
  definition: simpleMeasurementDefinitions.definition
28235
28375
  }).from(simpleMeasurementDefinitions).where(and27(
28236
28376
  eq34(simpleMeasurementDefinitions.projectId, project.id),
28237
- inArray16(simpleMeasurementDefinitions.runId, eligibleRuns.map((run) => run.id))
28377
+ inArray17(simpleMeasurementDefinitions.runId, eligibleRuns.map((run) => run.id))
28238
28378
  )).all()) {
28239
28379
  const parsed = simpleMeasurementDefinitionSchema.safeParse(row.definition);
28240
28380
  if (parsed.success) frozenByRun.set(row.runId, parsed.data);
@@ -28246,7 +28386,7 @@ function simpleMeasuredAtByQuery(db, project, queryRows2, opts) {
28246
28386
  queryId: querySnapshots.queryId,
28247
28387
  queryText: querySnapshots.queryText,
28248
28388
  provider: querySnapshots.provider
28249
- }).from(querySnapshots).where(inArray16(querySnapshots.runId, [...frozenByRun.keys()])).all()) {
28389
+ }).from(querySnapshots).where(inArray17(querySnapshots.runId, [...frozenByRun.keys()])).all()) {
28250
28390
  if (!snapshot.queryId) continue;
28251
28391
  const byQuery = snapshotsByRunQuery.get(snapshot.runId) ?? /* @__PURE__ */ new Map();
28252
28392
  const rows = byQuery.get(snapshot.queryId) ?? [];
@@ -28344,11 +28484,11 @@ function measuredAtByQuery(db, state, opts) {
28344
28484
  const eligibleRuns = db.select().from(runs).where(and27(
28345
28485
  eq34(runs.projectId, project.id),
28346
28486
  eq34(runs.kind, RunKinds["answer-visibility"]),
28347
- inArray16(runs.status, [RunStatuses.completed, RunStatuses.partial]),
28487
+ inArray17(runs.status, [RunStatuses.completed, RunStatuses.partial]),
28348
28488
  ne6(runs.trigger, RunTriggers.probe),
28349
28489
  isNull9(runs.measurementScope),
28350
28490
  isNotNull5(runs.measurementPlanVersionId)
28351
- )).orderBy(desc14(runs.createdAt), desc14(runs.id)).limit(SOURCE_LIMIT).all();
28491
+ )).orderBy(desc15(runs.createdAt), desc15(runs.id)).limit(SOURCE_LIMIT).all();
28352
28492
  if (eligibleRuns.length === 0) return /* @__PURE__ */ new Map();
28353
28493
  const versionIds = unique2(eligibleRuns.flatMap((run) => run.measurementPlanVersionId ? [run.measurementPlanVersionId] : []));
28354
28494
  const versionPlans = new Map(db.select({
@@ -28357,7 +28497,7 @@ function measuredAtByQuery(db, state, opts) {
28357
28497
  canonicalJson: measurementPlanVersions.canonicalJson
28358
28498
  }).from(measurementPlanVersions).where(and27(
28359
28499
  eq34(measurementPlanVersions.projectId, project.id),
28360
- inArray16(measurementPlanVersions.id, versionIds)
28500
+ inArray17(measurementPlanVersions.id, versionIds)
28361
28501
  )).all().flatMap((row) => {
28362
28502
  const parsed = parseStoredMeasurementPlanAnyVersion(row.canonicalJson);
28363
28503
  return parsed.schemaVersion === 2 ? [[row.id, { revision: row.revision, plan: parsed }]] : [];
@@ -28389,7 +28529,7 @@ function measuredAtByQuery(db, state, opts) {
28389
28529
  measurementExecutionId: querySnapshots.measurementExecutionId,
28390
28530
  requestedContext: querySnapshots.requestedContext,
28391
28531
  supportedContext: querySnapshots.supportedContext
28392
- }).from(querySnapshots).where(inArray16(querySnapshots.runId, eligibleRuns.map((run) => run.id))).all();
28532
+ }).from(querySnapshots).where(inArray17(querySnapshots.runId, eligibleRuns.map((run) => run.id))).all();
28393
28533
  for (const snapshot of snapshotRows) {
28394
28534
  const snapshots = snapshotsByRun.get(snapshot.runId) ?? [];
28395
28535
  snapshots.push(snapshot);
@@ -28537,13 +28677,13 @@ function savedSources(db, projectId) {
28537
28677
  researchRunQueryId: researchRunQueries.id,
28538
28678
  queryText: researchRunQueries.queryText,
28539
28679
  createdAt: researchRunQueries.createdAt
28540
- }).from(researchRunQueries).innerJoin(researchRuns, eq34(researchRunQueries.researchRunId, researchRuns.id)).where(eq34(researchRuns.projectId, projectId)).orderBy(desc14(researchRunQueries.createdAt)).limit(SOURCE_LIMIT).all().filter((row) => row.queryText.trim().length > 0);
28680
+ }).from(researchRunQueries).innerJoin(researchRuns, eq34(researchRunQueries.researchRunId, researchRuns.id)).where(eq34(researchRuns.projectId, projectId)).orderBy(desc15(researchRunQueries.createdAt)).limit(SOURCE_LIMIT).all().filter((row) => row.queryText.trim().length > 0);
28541
28681
  const discovery = db.select({
28542
28682
  discoverySessionId: discoverySessions.id,
28543
28683
  discoveryProbeId: discoveryProbes.id,
28544
28684
  queryText: discoveryProbes.query,
28545
28685
  createdAt: discoveryProbes.createdAt
28546
- }).from(discoveryProbes).innerJoin(discoverySessions, eq34(discoveryProbes.sessionId, discoverySessions.id)).where(eq34(discoverySessions.projectId, projectId)).orderBy(desc14(discoveryProbes.createdAt)).limit(SOURCE_LIMIT).all().filter((row) => row.queryText.trim().length > 0);
28686
+ }).from(discoveryProbes).innerJoin(discoverySessions, eq34(discoveryProbes.sessionId, discoverySessions.id)).where(eq34(discoverySessions.projectId, projectId)).orderBy(desc15(discoveryProbes.createdAt)).limit(SOURCE_LIMIT).all().filter((row) => row.queryText.trim().length > 0);
28547
28687
  return { research, discovery };
28548
28688
  }
28549
28689
  function workspaceDto(db, state, opts) {
@@ -29398,7 +29538,7 @@ function writeAdvancedCandidate(tx, candidate, request, now) {
29398
29538
  const removed = current.filter((row) => !candidate.queryRows.has(row.id));
29399
29539
  if (removed.length > 0) {
29400
29540
  preserveSnapshotQueryText(tx, candidate.state.project.id, removed.map((row) => row.id));
29401
- tx.delete(queries).where(inArray16(queries.id, removed.map((row) => row.id))).run();
29541
+ tx.delete(queries).where(inArray17(queries.id, removed.map((row) => row.id))).run();
29402
29542
  }
29403
29543
  for (const row of candidate.queryRows.values()) {
29404
29544
  const previous = currentById.get(row.id);
@@ -29417,7 +29557,7 @@ function writeAdvancedCandidate(tx, candidate, request, now) {
29417
29557
  if (!candidate.planChanged) return active;
29418
29558
  const plan = candidate.plan;
29419
29559
  const canonicalJson3 = canonicalMeasurementPlanV2Json(plan);
29420
- const latest = tx.select().from(measurementPlanVersions).where(eq34(measurementPlanVersions.projectId, candidate.state.project.id)).orderBy(desc14(measurementPlanVersions.revision)).get();
29560
+ const latest = tx.select().from(measurementPlanVersions).where(eq34(measurementPlanVersions.projectId, candidate.state.project.id)).orderBy(desc15(measurementPlanVersions.revision)).get();
29421
29561
  const revision = (latest?.revision ?? 0) + 1;
29422
29562
  const versionId = crypto21.randomUUID();
29423
29563
  tx.insert(measurementPlanVersions).values({
@@ -30226,7 +30366,7 @@ function aliasArraysEqual2(a, b) {
30226
30366
  }
30227
30367
 
30228
30368
  // ../api-routes/src/history.ts
30229
- import { and as and29, asc as asc5, count, desc as desc15, eq as eq36, gte as gte6, inArray as inArray17, like as like2, ne as ne7, or as or9 } from "drizzle-orm";
30369
+ import { and as and29, asc as asc5, count, desc as desc16, eq as eq36, gte as gte6, inArray as inArray18, like as like2, ne as ne7, or as or9 } from "drizzle-orm";
30230
30370
 
30231
30371
  // ../api-routes/src/notification-redaction.ts
30232
30372
  var REDACTED_URL = {
@@ -30278,27 +30418,27 @@ async function historyRoutes(app) {
30278
30418
  if (!parsed.success) throw validationError("Invalid history cleanup request", { issues: parsed.error.issues });
30279
30419
  const input = parsed.data;
30280
30420
  return app.db.transaction((tx) => {
30281
- const active = tx.select({ id: runs.id }).from(runs).where(and29(eq36(runs.projectId, project.id), eq36(runs.kind, RunKinds["answer-visibility"]), inArray17(runs.status, ["queued", "running"]))).get();
30282
- const activeResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and29(eq36(researchRuns.projectId, project.id), inArray17(researchRuns.status, ["queued", "running"]))).get();
30421
+ const active = tx.select({ id: runs.id }).from(runs).where(and29(eq36(runs.projectId, project.id), eq36(runs.kind, RunKinds["answer-visibility"]), inArray18(runs.status, ["queued", "running"]))).get();
30422
+ const activeResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and29(eq36(researchRuns.projectId, project.id), inArray18(researchRuns.status, ["queued", "running"]))).get();
30283
30423
  if (active || activeResearch) throw runInProgress(project.name, active ? "answer-visibility" : "research", (active ?? activeResearch).id);
30284
- const activeFill = tx.select({ id: runFills.id, runId: runFills.runId }).from(runFills).where(and29(eq36(runFills.projectId, project.id), inArray17(runFills.status, ["queued", "running"]))).get();
30424
+ const activeFill = tx.select({ id: runFills.id, runId: runFills.runId }).from(runFills).where(and29(eq36(runFills.projectId, project.id), inArray18(runFills.status, ["queued", "running"]))).get();
30285
30425
  if (activeFill) throw runFillInProgress(activeFill.runId, activeFill.id);
30286
- const selectedRuns = tx.select({ id: runs.id, kind: runs.kind }).from(runs).where(and29(eq36(runs.projectId, project.id), inArray17(runs.id, input.runIds))).all();
30287
- const selectedResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and29(eq36(researchRuns.projectId, project.id), inArray17(researchRuns.id, input.researchRunIds))).all();
30426
+ const selectedRuns = tx.select({ id: runs.id, kind: runs.kind }).from(runs).where(and29(eq36(runs.projectId, project.id), inArray18(runs.id, input.runIds))).all();
30427
+ const selectedResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and29(eq36(researchRuns.projectId, project.id), inArray18(researchRuns.id, input.researchRunIds))).all();
30288
30428
  if (selectedRuns.length !== input.runIds.length || selectedResearch.length !== input.researchRunIds.length) throw notFound("Selected saved run in project", project.name);
30289
30429
  if (selectedRuns.some((run) => run.kind !== RunKinds["answer-visibility"])) throw validationError("Only answer-visibility runs and research batches can be cleared. Site Health and integration runs are preserved.");
30290
30430
  const result = {
30291
30431
  dryRun: !input.confirm,
30292
30432
  runIds: input.runIds,
30293
30433
  researchRunIds: input.researchRunIds,
30294
- querySnapshots: tx.select({ value: count() }).from(querySnapshots).where(inArray17(querySnapshots.runId, input.runIds)).get().value,
30295
- researchQueries: tx.select({ value: count() }).from(researchRunQueries).where(inArray17(researchRunQueries.researchRunId, input.researchRunIds)).get().value,
30296
- insights: tx.select({ value: count() }).from(insights).where(inArray17(insights.runId, input.runIds)).get().value,
30297
- healthSnapshots: tx.select({ value: count() }).from(healthSnapshots).where(inArray17(healthSnapshots.runId, input.runIds)).get().value
30434
+ querySnapshots: tx.select({ value: count() }).from(querySnapshots).where(inArray18(querySnapshots.runId, input.runIds)).get().value,
30435
+ researchQueries: tx.select({ value: count() }).from(researchRunQueries).where(inArray18(researchRunQueries.researchRunId, input.researchRunIds)).get().value,
30436
+ insights: tx.select({ value: count() }).from(insights).where(inArray18(insights.runId, input.runIds)).get().value,
30437
+ healthSnapshots: tx.select({ value: count() }).from(healthSnapshots).where(inArray18(healthSnapshots.runId, input.runIds)).get().value
30298
30438
  };
30299
30439
  if (input.confirm) {
30300
- tx.delete(researchRuns).where(and29(eq36(researchRuns.projectId, project.id), inArray17(researchRuns.id, input.researchRunIds))).run();
30301
- tx.delete(runs).where(and29(eq36(runs.projectId, project.id), inArray17(runs.id, input.runIds))).run();
30440
+ tx.delete(researchRuns).where(and29(eq36(researchRuns.projectId, project.id), inArray18(researchRuns.id, input.researchRunIds))).run();
30441
+ tx.delete(runs).where(and29(eq36(runs.projectId, project.id), inArray18(runs.id, input.runIds))).run();
30302
30442
  writeAuditLog(tx, { projectId: project.id, actor: "api", action: "results.cleared", entityType: "project", entityId: project.id, diff: result });
30303
30443
  }
30304
30444
  return result;
@@ -30309,7 +30449,7 @@ async function historyRoutes(app) {
30309
30449
  const filters = [eq36(auditLog.projectId, project.id)];
30310
30450
  if (request.operatorAccess !== true) filters.push(ne7(auditLog.entityType, "telemetry"));
30311
30451
  addAuditHistoryFilters(filters, request.query);
30312
- const rows = app.db.select().from(auditLog).where(and29(...filters)).orderBy(desc15(auditLog.createdAt), desc15(auditLog.id)).limit(parseBoundedInt(request.query.limit, 100, 500)).offset(parseBoundedInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER)).all();
30452
+ const rows = app.db.select().from(auditLog).where(and29(...filters)).orderBy(desc16(auditLog.createdAt), desc16(auditLog.id)).limit(parseBoundedInt(request.query.limit, 100, 500)).offset(parseBoundedInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER)).all();
30313
30453
  return reply.send(rows.map(formatAuditEntry));
30314
30454
  });
30315
30455
  app.get("/history", async (request, reply) => {
@@ -30317,7 +30457,7 @@ async function historyRoutes(app) {
30317
30457
  const filters = scopedProjectId ? [eq36(auditLog.projectId, scopedProjectId)] : [];
30318
30458
  if (request.operatorAccess !== true) filters.push(ne7(auditLog.entityType, "telemetry"));
30319
30459
  addAuditHistoryFilters(filters, request.query);
30320
- const rows = app.db.select().from(auditLog).where(filters.length > 0 ? and29(...filters) : void 0).orderBy(desc15(auditLog.createdAt), desc15(auditLog.id)).limit(parseBoundedInt(request.query.limit, 100, 500)).offset(parseBoundedInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER)).all();
30460
+ const rows = app.db.select().from(auditLog).where(filters.length > 0 ? and29(...filters) : void 0).orderBy(desc16(auditLog.createdAt), desc16(auditLog.id)).limit(parseBoundedInt(request.query.limit, 100, 500)).offset(parseBoundedInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER)).all();
30321
30461
  return reply.send(rows.map(formatAuditEntry));
30322
30462
  });
30323
30463
  app.get("/projects/:name/snapshots", async (request, reply) => {
@@ -30350,7 +30490,7 @@ async function historyRoutes(app) {
30350
30490
  location: querySnapshots.location,
30351
30491
  rawResponse: querySnapshots.rawResponse,
30352
30492
  createdAt: querySnapshots.createdAt
30353
- }).from(querySnapshots).leftJoin(queries, eq36(querySnapshots.queryId, queries.id)).where(inArray17(querySnapshots.runId, projectRuns.map((r) => r.id))).orderBy(desc15(querySnapshots.createdAt)).all();
30493
+ }).from(querySnapshots).leftJoin(queries, eq36(querySnapshots.queryId, queries.id)).where(inArray18(querySnapshots.runId, projectRuns.map((r) => r.id))).orderBy(desc16(querySnapshots.createdAt)).all();
30354
30494
  const locationFilter = request.query.location;
30355
30495
  const filtered = locationFilter !== void 0 ? allSnapshots.filter((s) => s.location === (locationFilter || null)) : allSnapshots;
30356
30496
  const total = filtered.length;
@@ -30405,12 +30545,12 @@ async function historyRoutes(app) {
30405
30545
  eq36(runs.kind, RunKinds["answer-visibility"])
30406
30546
  );
30407
30547
  const requestedLimit = parseOptionalPositiveInt(request.query.limit, 100);
30408
- const projectRuns = requestedLimit == null ? app.db.select().from(runs).where(runKindFilter).orderBy(asc5(runs.createdAt)).all() : app.db.select().from(runs).where(runKindFilter).orderBy(desc15(runs.createdAt)).limit(requestedLimit).all().reverse();
30548
+ const projectRuns = requestedLimit == null ? app.db.select().from(runs).where(runKindFilter).orderBy(asc5(runs.createdAt)).all() : app.db.select().from(runs).where(runKindFilter).orderBy(desc16(runs.createdAt)).limit(requestedLimit).all().reverse();
30409
30549
  if (projectRuns.length === 0 || projectQueries.length === 0) {
30410
30550
  return reply.send([]);
30411
30551
  }
30412
30552
  const runIds = new Set(projectRuns.map((r) => r.id));
30413
- const rawSnapshots = app.db.select().from(querySnapshots).where(inArray17(querySnapshots.runId, [...runIds])).all();
30553
+ const rawSnapshots = app.db.select().from(querySnapshots).where(inArray18(querySnapshots.runId, [...runIds])).all();
30414
30554
  const timelineLocationFilter = request.query.location;
30415
30555
  const filteredSnapshots = timelineLocationFilter !== void 0 ? rawSnapshots.filter((s) => s.location === (timelineLocationFilter || null)) : rawSnapshots;
30416
30556
  const allSnapshots = filteredSnapshots.map((snapshot) => ({
@@ -30531,7 +30671,7 @@ async function historyRoutes(app) {
30531
30671
  throw validationError("Both run1 and run2 query params are required");
30532
30672
  }
30533
30673
  const requestedRunIds = [.../* @__PURE__ */ new Set([run1, run2])];
30534
- const runRows = app.db.select({ id: runs.id, projectId: runs.projectId }).from(runs).where(inArray17(runs.id, requestedRunIds)).all();
30674
+ const runRows = app.db.select({ id: runs.id, projectId: runs.projectId }).from(runs).where(inArray18(runs.id, requestedRunIds)).all();
30535
30675
  const runsById = new Map(runRows.map((row) => [row.id, row]));
30536
30676
  for (const runId of requestedRunIds) {
30537
30677
  const run = runsById.get(runId);
@@ -30636,7 +30776,7 @@ function parseOptionalPositiveInt(value, max2) {
30636
30776
  }
30637
30777
 
30638
30778
  // ../api-routes/src/analytics.ts
30639
- import { and as and30, desc as desc16, eq as eq37, gte as gte7, inArray as inArray18, lt as lt7 } from "drizzle-orm";
30779
+ import { and as and30, desc as desc17, eq as eq37, gte as gte7, inArray as inArray19, lt as lt7 } from "drizzle-orm";
30640
30780
 
30641
30781
  // ../api-routes/src/analytics-model-attribution.ts
30642
30782
  function logicalSweeps(observations) {
@@ -30732,10 +30872,10 @@ async function analyticsRoutes(app) {
30732
30872
  const projectRuns = app.db.select().from(runs).where(and30(
30733
30873
  eq37(runs.projectId, project.id),
30734
30874
  eq37(runs.kind, RunKinds["answer-visibility"]),
30735
- inArray18(runs.status, [RunStatuses.completed, RunStatuses.partial]),
30875
+ inArray19(runs.status, [RunStatuses.completed, RunStatuses.partial]),
30736
30876
  notProbeRun(),
30737
30877
  cutoff ? gte7(runs.createdAt, cutoff) : void 0
30738
- )).orderBy(desc16(runs.createdAt)).all().filter((r) => measuredWhole(app.db, r)).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
30878
+ )).orderBy(desc17(runs.createdAt)).all().filter((r) => measuredWhole(app.db, r)).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
30739
30879
  if (projectRuns.length === 0) {
30740
30880
  return reply.send({
30741
30881
  window,
@@ -30777,7 +30917,7 @@ async function analyticsRoutes(app) {
30777
30917
  citationState: querySnapshots.citationState,
30778
30918
  answerMentioned: querySnapshots.answerMentioned,
30779
30919
  answerText: querySnapshots.answerText
30780
- }).from(querySnapshots).where(inArray18(querySnapshots.runId, runIds)).all();
30920
+ }).from(querySnapshots).where(inArray19(querySnapshots.runId, runIds)).all();
30781
30921
  const rawSnapshots = referenceBasket ? loadedSnapshots.filter(
30782
30922
  (s) => s.queryId !== null || s.queryText !== null && referenceBasket.has(normalizeQueryText(s.queryText))
30783
30923
  ) : filterTrackedSnapshots(loadedSnapshots);
@@ -30827,11 +30967,11 @@ async function analyticsRoutes(app) {
30827
30967
  const anchorRunPredicate = and30(
30828
30968
  eq37(runs.projectId, project.id),
30829
30969
  eq37(runs.kind, RunKinds["answer-visibility"]),
30830
- inArray18(runs.status, [RunStatuses.completed, RunStatuses.partial]),
30970
+ inArray19(runs.status, [RunStatuses.completed, RunStatuses.partial]),
30831
30971
  notProbeRun(),
30832
30972
  lt7(runs.createdAt, cutoff)
30833
30973
  );
30834
- const anchorSweepTimes = app.db.selectDistinct({ createdAt: runs.createdAt }).from(runs).where(anchorRunPredicate).orderBy(desc16(runs.createdAt)).limit(ANCHOR_SWEEP_SCAN_LIMIT + 1).all().map((row) => row.createdAt);
30974
+ const anchorSweepTimes = app.db.selectDistinct({ createdAt: runs.createdAt }).from(runs).where(anchorRunPredicate).orderBy(desc17(runs.createdAt)).limit(ANCHOR_SWEEP_SCAN_LIMIT + 1).all().map((row) => row.createdAt);
30835
30975
  const anchorScanTruncated = anchorSweepTimes.length > ANCHOR_SWEEP_SCAN_LIMIT;
30836
30976
  if (anchorScanTruncated) anchorSweepTimes.length = ANCHOR_SWEEP_SCAN_LIMIT;
30837
30977
  if (anchorSweepTimes.length > 0) {
@@ -30857,7 +30997,7 @@ async function analyticsRoutes(app) {
30857
30997
  provider: querySnapshots.provider,
30858
30998
  model: querySnapshots.model,
30859
30999
  servedModel: querySnapshots.servedModel
30860
- }).from(querySnapshots).where(inArray18(querySnapshots.runId, runIds2)).all())) {
31000
+ }).from(querySnapshots).where(inArray19(querySnapshots.runId, runIds2)).all())) {
30861
31001
  if (pending.has(snapshot.provider)) {
30862
31002
  const models = modelsByProvider.get(snapshot.provider) ?? [];
30863
31003
  models.push(snapshot.model);
@@ -30986,7 +31126,7 @@ async function analyticsRoutes(app) {
30986
31126
  const project = resolveProject(app.db, request.params.name);
30987
31127
  const window = parseWindow(request.query.window);
30988
31128
  const cutoff = windowCutoff(window);
30989
- const completedRuns = app.db.select().from(runs).where(and30(eq37(runs.projectId, project.id), eq37(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc16(runs.createdAt), desc16(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => measuredWhole(app.db, r));
31129
+ const completedRuns = app.db.select().from(runs).where(and30(eq37(runs.projectId, project.id), eq37(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc17(runs.createdAt), desc17(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => measuredWhole(app.db, r));
30990
31130
  const latestGroup = groupRunsByCreatedAt(completedRuns)[0] ?? [];
30991
31131
  const latestGroupRunIds = latestGroup.map((r) => r.id);
30992
31132
  const latestRun = pickGroupRepresentative(latestGroup);
@@ -31009,7 +31149,7 @@ async function analyticsRoutes(app) {
31009
31149
  citationState: querySnapshots.citationState,
31010
31150
  answerMentioned: querySnapshots.answerMentioned,
31011
31151
  answerText: querySnapshots.answerText
31012
- }).from(querySnapshots).where(inArray18(querySnapshots.runId, windowRunIds)).all());
31152
+ }).from(querySnapshots).where(inArray19(querySnapshots.runId, windowRunIds)).all());
31013
31153
  for (const s of allWindowSnaps) {
31014
31154
  const timePoint = runIdToCreatedAt.get(s.runId) ?? s.runId;
31015
31155
  let entry = consistencyMap.get(s.queryId);
@@ -31030,7 +31170,7 @@ async function analyticsRoutes(app) {
31030
31170
  answerMentioned: querySnapshots.answerMentioned,
31031
31171
  answerText: querySnapshots.answerText,
31032
31172
  citedDomains: querySnapshots.citedDomains
31033
- }).from(querySnapshots).leftJoin(queries, eq37(querySnapshots.queryId, queries.id)).where(inArray18(querySnapshots.runId, latestGroupRunIds)).all());
31173
+ }).from(querySnapshots).leftJoin(queries, eq37(querySnapshots.queryId, queries.id)).where(inArray19(querySnapshots.runId, latestGroupRunIds)).all());
31034
31174
  const snapshots = rawSnapshots.map((s) => ({
31035
31175
  ...s,
31036
31176
  resolvedMentioned: resolveSnapshotAnswerMentioned(s, project)
@@ -31197,8 +31337,8 @@ async function analyticsRoutes(app) {
31197
31337
  eq37(runs.projectId, project.id),
31198
31338
  eq37(runs.kind, RunKinds["answer-visibility"]),
31199
31339
  notProbeRun(),
31200
- latestRuns ? inArray18(runs.id, latestRuns.map((run) => run.id)) : requestedRunId ? eq37(runs.id, requestedRunId) : void 0
31201
- )).orderBy(desc16(runs.createdAt), desc16(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => measuredWhole(app.db, r)).filter((r) => !cutoff || r.createdAt >= cutoff);
31340
+ latestRuns ? inArray19(runs.id, latestRuns.map((run) => run.id)) : requestedRunId ? eq37(runs.id, requestedRunId) : void 0
31341
+ )).orderBy(desc17(runs.createdAt), desc17(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => measuredWhole(app.db, r)).filter((r) => !cutoff || r.createdAt >= cutoff);
31202
31342
  if (windowRuns.length === 0) {
31203
31343
  return reply.send({
31204
31344
  ranked: buildRankedList(/* @__PURE__ */ new Map(), limit, 0, 0),
@@ -31230,7 +31370,7 @@ async function analyticsRoutes(app) {
31230
31370
  citedDomains: querySnapshots.citedDomains,
31231
31371
  citedUrls: querySnapshots.citedUrls,
31232
31372
  measurementExecutionId: querySnapshots.measurementExecutionId
31233
- }).from(querySnapshots).leftJoin(queries, eq37(querySnapshots.queryId, queries.id)).where(inArray18(querySnapshots.runId, windowRunIds)).all();
31373
+ }).from(querySnapshots).leftJoin(queries, eq37(querySnapshots.queryId, queries.id)).where(inArray19(querySnapshots.runId, windowRunIds)).all();
31234
31374
  let unclassifiedAnswers = 0;
31235
31375
  let snapshots = loadedSnapshots;
31236
31376
  if (splitByClass) {
@@ -31583,7 +31723,7 @@ function buildCategoryCounts(counts2) {
31583
31723
  }
31584
31724
 
31585
31725
  // ../api-routes/src/intelligence.ts
31586
- import { eq as eq38, desc as desc17, and as and31, inArray as inArray19, like as like3 } from "drizzle-orm";
31726
+ import { eq as eq38, desc as desc18, and as and31, inArray as inArray20, like as like3 } from "drizzle-orm";
31587
31727
  var SEVERITY_RANK = { low: 0, medium: 1, high: 2, critical: 3 };
31588
31728
  function severitiesAtOrAbove(min2) {
31589
31729
  const floor = SEVERITY_RANK[min2];
@@ -31713,7 +31853,7 @@ async function intelligenceRoutes(app) {
31713
31853
  }
31714
31854
  const severityFilter = request.query.severity?.trim();
31715
31855
  if (severityFilter) {
31716
- conditions.push(inArray19(insights.severity, severitiesAtOrAbove(severityFilter)));
31856
+ conditions.push(inArray20(insights.severity, severitiesAtOrAbove(severityFilter)));
31717
31857
  }
31718
31858
  let limit;
31719
31859
  if (request.query.limit !== void 0) {
@@ -31723,7 +31863,7 @@ async function intelligenceRoutes(app) {
31723
31863
  }
31724
31864
  limit = parsed;
31725
31865
  }
31726
- const rows = app.db.select().from(insights).where(conditions.length === 1 ? conditions[0] : and31(...conditions)).orderBy(desc17(insights.createdAt)).all();
31866
+ const rows = app.db.select().from(insights).where(conditions.length === 1 ? conditions[0] : and31(...conditions)).orderBy(desc18(insights.createdAt)).all();
31727
31867
  const showDismissed = request.query.dismissed === "true";
31728
31868
  let result = rows.filter((r) => showDismissed || !r.dismissed).map(mapInsightRow);
31729
31869
  if (limit !== void 0) result = result.slice(0, limit);
@@ -31751,23 +31891,23 @@ async function intelligenceRoutes(app) {
31751
31891
  const projectVisRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and31(
31752
31892
  eq38(runs.projectId, project.id),
31753
31893
  eq38(runs.kind, RunKinds["answer-visibility"]),
31754
- inArray19(runs.status, [RunStatuses.completed, RunStatuses.partial]),
31894
+ inArray20(runs.status, [RunStatuses.completed, RunStatuses.partial]),
31755
31895
  // Health-latest is the dashboard headline; probe runs must not
31756
31896
  // displace the most recent real visibility sweep.
31757
31897
  notProbeRun()
31758
- )).orderBy(desc17(runs.createdAt), desc17(runs.id)).all();
31898
+ )).orderBy(desc18(runs.createdAt), desc18(runs.id)).all();
31759
31899
  const latestGroup = groupRunsByCreatedAt(projectVisRuns)[0] ?? [];
31760
31900
  const latestGroupRunIds = latestGroup.map((r) => r.id);
31761
31901
  if (latestGroupRunIds.length > 0) {
31762
31902
  const groupRows = app.db.select().from(healthSnapshots).where(and31(
31763
31903
  eq38(healthSnapshots.projectId, project.id),
31764
- inArray19(healthSnapshots.runId, latestGroupRunIds)
31904
+ inArray20(healthSnapshots.runId, latestGroupRunIds)
31765
31905
  )).all();
31766
31906
  if (groupRows.length > 0) {
31767
31907
  return reply.send(aggregateHealthSnapshots(project.id, groupRows));
31768
31908
  }
31769
31909
  }
31770
- const fallback = app.db.select().from(healthSnapshots).where(eq38(healthSnapshots.projectId, project.id)).orderBy(desc17(healthSnapshots.createdAt)).limit(1).get();
31910
+ const fallback = app.db.select().from(healthSnapshots).where(eq38(healthSnapshots.projectId, project.id)).orderBy(desc18(healthSnapshots.createdAt)).limit(1).get();
31771
31911
  if (!fallback) {
31772
31912
  return reply.send(emptyHealthSnapshot(project.id));
31773
31913
  }
@@ -31777,13 +31917,13 @@ async function intelligenceRoutes(app) {
31777
31917
  const project = resolveProject(app.db, request.params.name);
31778
31918
  const parsed = request.query.limit ? parseInt(request.query.limit, 10) : NaN;
31779
31919
  const limit = Number.isNaN(parsed) ? 30 : Math.min(Math.max(parsed, 1), 100);
31780
- const rows = app.db.select().from(healthSnapshots).where(eq38(healthSnapshots.projectId, project.id)).orderBy(desc17(healthSnapshots.createdAt)).limit(limit).all();
31920
+ const rows = app.db.select().from(healthSnapshots).where(eq38(healthSnapshots.projectId, project.id)).orderBy(desc18(healthSnapshots.createdAt)).limit(limit).all();
31781
31921
  return reply.send(rows.map(mapHealthRow));
31782
31922
  });
31783
31923
  }
31784
31924
 
31785
31925
  // ../api-routes/src/traffic-analytics.ts
31786
- import { and as and33, desc as desc18, eq as eq39, gte as gte8, lt as lt8, lte as lte7, ne as ne8, sql as sql13 } from "drizzle-orm";
31926
+ import { and as and33, desc as desc19, eq as eq39, gte as gte8, lt as lt8, lte as lte7, ne as ne8, sql as sql13 } from "drizzle-orm";
31787
31927
 
31788
31928
  // ../api-routes/src/ai-referral-status.ts
31789
31929
  import { and as and32, sql as sql12 } from "drizzle-orm";
@@ -31993,7 +32133,7 @@ function readTrafficActivity(db, projectId, windowDays2) {
31993
32133
  gte8(crawlerEventsHourly.tsHour, headlineStart),
31994
32134
  lte7(crawlerEventsHourly.tsHour, headlineEnd)
31995
32135
  )
31996
- ).groupBy(crawlerEventsHourly.pathNormalized).orderBy(desc18(sql13`SUM(${crawlerEventsHourly.hits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
32136
+ ).groupBy(crawlerEventsHourly.pathNormalized).orderBy(desc19(sql13`SUM(${crawlerEventsHourly.hits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
31997
32137
  const topCrawledPaths = topPathsRows.map((r) => ({
31998
32138
  path: r.path,
31999
32139
  verifiedHits: Number(r.verifiedHits),
@@ -32011,7 +32151,7 @@ function readTrafficActivity(db, projectId, windowDays2) {
32011
32151
  gte8(aiReferralEventsHourly.tsHour, headlineStart),
32012
32152
  lte7(aiReferralEventsHourly.tsHour, headlineEnd)
32013
32153
  )
32014
- ).groupBy(aiReferralEventsHourly.product).orderBy(desc18(sql13`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).all();
32154
+ ).groupBy(aiReferralEventsHourly.product).orderBy(desc19(sql13`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).all();
32015
32155
  const referralProducts = referralProductsRows.map((r) => ({
32016
32156
  product: r.product,
32017
32157
  arrivals: Number(r.arrivals),
@@ -32028,7 +32168,7 @@ function readTrafficActivity(db, projectId, windowDays2) {
32028
32168
  gte8(aiReferralEventsHourly.tsHour, headlineStart),
32029
32169
  lte7(aiReferralEventsHourly.tsHour, headlineEnd)
32030
32170
  )
32031
- ).groupBy(aiReferralEventsHourly.landingPathNormalized).orderBy(desc18(sql13`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
32171
+ ).groupBy(aiReferralEventsHourly.landingPathNormalized).orderBy(desc19(sql13`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
32032
32172
  const topReferralLandingPaths = topReferralRows.map((r) => ({
32033
32173
  path: r.path,
32034
32174
  arrivals: Number(r.arrivals),
@@ -32147,7 +32287,7 @@ async function trafficAnalyticsRoutes(app) {
32147
32287
  }
32148
32288
 
32149
32289
  // ../api-routes/src/referral-assessment.ts
32150
- import { and as and34, desc as desc19, eq as eq40, gte as gte9, lte as lte8, ne as ne9, sql as sql14 } from "drizzle-orm";
32290
+ import { and as and34, desc as desc20, eq as eq40, gte as gte9, lte as lte8, ne as ne9, sql as sql14 } from "drizzle-orm";
32151
32291
 
32152
32292
  // ../api-routes/src/ga-ai-referral-aggregation.ts
32153
32293
  function normalizeAiTrafficClass(value) {
@@ -32296,7 +32436,7 @@ function buildAiReferralDailySeries(rows) {
32296
32436
  var DEFAULT_BURST_THRESHOLD = 100;
32297
32437
  var DEFAULT_RATIO_THRESHOLD = 3;
32298
32438
  function latestGaSyncQueriedWindow(db, projectId, startDate, endDate) {
32299
- const summary3 = db.select({ start: gaTrafficSummaries.periodStart, end: gaTrafficSummaries.periodEnd, syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq40(gaTrafficSummaries.projectId, projectId)).orderBy(desc19(gaTrafficSummaries.syncedAt)).limit(1).get();
32439
+ const summary3 = db.select({ start: gaTrafficSummaries.periodStart, end: gaTrafficSummaries.periodEnd, syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq40(gaTrafficSummaries.projectId, projectId)).orderBy(desc20(gaTrafficSummaries.syncedAt)).limit(1).get();
32300
32440
  if (!summary3 || startDate < summary3.start || endDate > summary3.end) return false;
32301
32441
  const leftByAnotherSync = db.select({ id: gaAiReferrals.id }).from(gaAiReferrals).where(and34(
32302
32442
  eq40(gaAiReferrals.projectId, projectId),
@@ -32414,7 +32554,7 @@ async function referralAssessmentRoutes(app) {
32414
32554
  }
32415
32555
 
32416
32556
  // ../api-routes/src/organic-evidence.ts
32417
- import { and as and36, desc as desc20, eq as eq42, gte as gte11, lte as lte10, or as or11, sql as sql16 } from "drizzle-orm";
32557
+ import { and as and36, desc as desc21, eq as eq42, gte as gte11, lte as lte10, or as or11, sql as sql16 } from "drizzle-orm";
32418
32558
 
32419
32559
  // ../api-routes/src/ga-measurement-analysis.ts
32420
32560
  import { and as and35, eq as eq41, gte as gte10, lte as lte9, or as or10, sql as sql15 } from "drizzle-orm";
@@ -33136,7 +33276,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
33136
33276
  eq42(runs.kind, RunKinds["answer-visibility"]),
33137
33277
  eq42(runs.status, RunStatuses.completed),
33138
33278
  notProbeRun()
33139
- )).orderBy(desc20(runs.createdAt)).get();
33279
+ )).orderBy(desc21(runs.createdAt)).get();
33140
33280
  const snapshots = latest ? db.select().from(querySnapshots).where(eq42(querySnapshots.runId, latest.id)).all() : [];
33141
33281
  const completedAt = latest ? latest.finishedAt ?? latest.createdAt : null;
33142
33282
  const visibility = latest && completedAt ? {
@@ -33376,7 +33516,7 @@ async function organicEvidenceRoutes(app) {
33376
33516
  }
33377
33517
 
33378
33518
  // ../api-routes/src/citations.ts
33379
- import { and as and37, eq as eq43, inArray as inArray20 } from "drizzle-orm";
33519
+ import { and as and37, eq as eq43, inArray as inArray21 } from "drizzle-orm";
33380
33520
  async function citationRoutes(app) {
33381
33521
  app.get("/projects/:name/citations/visibility", async (request, reply) => {
33382
33522
  const project = resolveProject(app.db, request.params.name);
@@ -33400,7 +33540,7 @@ async function citationRoutes(app) {
33400
33540
  competitorOverlap: querySnapshots.competitorOverlap,
33401
33541
  answerMentioned: querySnapshots.answerMentioned,
33402
33542
  createdAt: querySnapshots.createdAt
33403
- }).from(querySnapshots).where(inArray20(querySnapshots.runId, projectRuns.map((r) => r.id))).all();
33543
+ }).from(querySnapshots).where(inArray21(querySnapshots.runId, projectRuns.map((r) => r.id))).all();
33404
33544
  if (rawSnapshots.length === 0) {
33405
33545
  return reply.send(emptyCitationVisibility("no-runs-yet"));
33406
33546
  }
@@ -33537,7 +33677,7 @@ function computeCitationVisibility(input) {
33537
33677
  }
33538
33678
 
33539
33679
  // ../api-routes/src/visibility-stats.ts
33540
- import { and as and38, desc as desc21, eq as eq44, inArray as inArray21 } from "drizzle-orm";
33680
+ import { and as and38, desc as desc22, eq as eq44, inArray as inArray22 } from "drizzle-orm";
33541
33681
 
33542
33682
  // ../api-routes/src/visibility-compare.ts
33543
33683
  var VISIBILITY_COMPARE_MIN_RUNS = 5;
@@ -34007,7 +34147,7 @@ async function visibilityStatsRoutes(app) {
34007
34147
  lastRuns = n;
34008
34148
  }
34009
34149
  const projectQueries = app.db.select({ id: queries.id, query: queries.query }).from(queries).where(eq44(queries.projectId, project.id)).all();
34010
- let projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(and38(eq44(runs.projectId, project.id), eq44(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc21(runs.createdAt)).all().filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial);
34150
+ let projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(and38(eq44(runs.projectId, project.id), eq44(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc22(runs.createdAt)).all().filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial);
34011
34151
  if (sinceMs !== null) projectRuns = projectRuns.filter((r) => Date.parse(r.createdAt) >= sinceMs);
34012
34152
  if (untilMs !== null) projectRuns = projectRuns.filter((r) => Date.parse(r.createdAt) <= untilMs);
34013
34153
  if (lastRuns !== null) projectRuns = projectRuns.slice(0, lastRuns);
@@ -34020,7 +34160,7 @@ async function visibilityStatsRoutes(app) {
34020
34160
  citationState: querySnapshots.citationState,
34021
34161
  answerMentioned: querySnapshots.answerMentioned,
34022
34162
  createdAt: querySnapshots.createdAt
34023
- }).from(querySnapshots).where(inArray21(querySnapshots.runId, runIds)).all() : [];
34163
+ }).from(querySnapshots).where(inArray22(querySnapshots.runId, runIds)).all() : [];
34024
34164
  const stats = computeVisibilityStats({ queries: projectQueries, snapshots, groupBy });
34025
34165
  const queryAttribution = buildQueryAttribution(projectQueries);
34026
34166
  let shareOfVoice;
@@ -34031,7 +34171,7 @@ async function visibilityStatsRoutes(app) {
34031
34171
  queryText: querySnapshots.queryText,
34032
34172
  answerMentioned: querySnapshots.answerMentioned,
34033
34173
  answerText: querySnapshots.answerText
34034
- }).from(querySnapshots).where(inArray21(querySnapshots.runId, runIds)).all() : [];
34174
+ }).from(querySnapshots).where(inArray22(querySnapshots.runId, runIds)).all() : [];
34035
34175
  const attributedSovSnapshots = sovSnapshots.filter((s) => resolveCurrentQuery(queryAttribution, s) !== void 0);
34036
34176
  const advanced = activeMeasurementPlan(app.db, project.id)?.plan.schemaVersion === 2;
34037
34177
  const queryClass = advanced || projectQueryClassifier(project) ? requestedQueryClass : "all";
@@ -34128,7 +34268,7 @@ function readVisibilityCompare(db, projectName, query) {
34128
34268
  answerText: querySnapshots.answerText,
34129
34269
  citedDomains: querySnapshots.citedDomains,
34130
34270
  location: querySnapshots.location
34131
- }).from(querySnapshots).where(inArray21(querySnapshots.runId, runIds)).all() : [];
34271
+ }).from(querySnapshots).where(inArray22(querySnapshots.runId, runIds)).all() : [];
34132
34272
  return {
34133
34273
  runCount: runIds.length,
34134
34274
  snapshots: snapshots.filter((snapshot) => (providerKey2 === void 0 || normalizeText3(snapshot.provider) === providerKey2) && (locationKey2 === void 0 || (locationKey2 === "none" ? snapshot.location === null : snapshot.location !== null && normalizeText3(snapshot.location) === locationKey2)))
@@ -34239,7 +34379,7 @@ function readVisibilityContinuity(db, projectName, months) {
34239
34379
  const trackedQueries = db.select({ id: queries.id, query: queries.query }).from(queries).where(eq44(queries.projectId, project.id)).all();
34240
34380
  const loadProjectMonth = (bounds) => {
34241
34381
  const runIds = legacyCompareRunIds(db, project.id, bounds);
34242
- const rows = runIds.length > 0 && trackedQueries.length > 0 ? db.select({ queryId: querySnapshots.queryId, queryText: querySnapshots.queryText, provider: querySnapshots.provider, model: querySnapshots.model }).from(querySnapshots).where(inArray21(querySnapshots.runId, runIds)).all() : [];
34382
+ const rows = runIds.length > 0 && trackedQueries.length > 0 ? db.select({ queryId: querySnapshots.queryId, queryText: querySnapshots.queryText, provider: querySnapshots.provider, model: querySnapshots.model }).from(querySnapshots).where(inArray22(querySnapshots.runId, runIds)).all() : [];
34243
34383
  return { runCount: runIds.length, snapshots: rows.map(bare) };
34244
34384
  };
34245
34385
  const frames = [{ frame: "project", continuity: gate(trackedQueries, loadProjectMonth(fromBounds), loadProjectMonth(toBounds)) }];
@@ -34496,7 +34636,7 @@ async function resultsExportRoutes(app) {
34496
34636
  }
34497
34637
 
34498
34638
  // ../api-routes/src/composites.ts
34499
- import { eq as eq47, and as and41, desc as desc22, sql as sql18, like as like4, or as or12, inArray as inArray22 } from "drizzle-orm";
34639
+ import { eq as eq47, and as and41, desc as desc23, sql as sql18, like as like4, or as or12, inArray as inArray23 } from "drizzle-orm";
34500
34640
 
34501
34641
  // ../api-routes/src/gsc-totals.ts
34502
34642
  import { and as and40, asc as asc7, eq as eq46, sql as sql17, max, min } from "drizzle-orm";
@@ -34772,7 +34912,7 @@ async function compositeRoutes(app, options) {
34772
34912
  const project = resolveProject(app.db, request.params.name);
34773
34913
  const filterLocation = (request.query.location ?? "").trim() || null;
34774
34914
  const sinceIso = parseSinceFilter(request.query.since);
34775
- const allRunsRaw = app.db.select().from(runs).where(and41(eq47(runs.projectId, project.id), notProbeRun())).orderBy(desc22(runs.createdAt), desc22(runs.id)).all();
34915
+ const allRunsRaw = app.db.select().from(runs).where(and41(eq47(runs.projectId, project.id), notProbeRun())).orderBy(desc23(runs.createdAt), desc23(runs.id)).all();
34776
34916
  const allRuns = allRunsRaw.filter((r) => runMatchesFilters(r, filterLocation, sinceIso));
34777
34917
  const totalRuns = allRuns.length;
34778
34918
  const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
@@ -34785,9 +34925,9 @@ async function compositeRoutes(app, options) {
34785
34925
  const previousVisibilityRun = pickGroupRepresentative(previousVisRunGroup);
34786
34926
  const latestRunRow = allRuns[0] ?? null;
34787
34927
  const latestRun = latestRunRow ? { totalRuns, run: summarizeRun(latestRunRow) } : { totalRuns: 0, run: null };
34788
- const healthRow = app.db.select().from(healthSnapshots).where(eq47(healthSnapshots.projectId, project.id)).orderBy(desc22(healthSnapshots.createdAt)).limit(1).get();
34928
+ const healthRow = app.db.select().from(healthSnapshots).where(eq47(healthSnapshots.projectId, project.id)).orderBy(desc23(healthSnapshots.createdAt)).limit(1).get();
34789
34929
  const health = healthRow ? mapHealthRow2(healthRow) : null;
34790
- const insightRows = app.db.select().from(insights).where(eq47(insights.projectId, project.id)).orderBy(desc22(insights.createdAt)).all();
34930
+ const insightRows = app.db.select().from(insights).where(eq47(insights.projectId, project.id)).orderBy(desc23(insights.createdAt)).all();
34791
34931
  const topInsights = insightRows.filter((row) => !row.dismissed).slice(0, TOP_INSIGHT_LIMIT).map(mapInsightRow2);
34792
34932
  const sparklineRunIds = visibilityRuns.slice(0, DEFAULT_RUN_HISTORY_LIMIT).map((r) => r.id);
34793
34933
  const snapshotRunIds = new Set(sparklineRunIds);
@@ -34959,7 +35099,7 @@ async function compositeRoutes(app, options) {
34959
35099
  like4(queries.query, pattern)
34960
35100
  )
34961
35101
  )
34962
- ).orderBy(desc22(querySnapshots.createdAt)).limit(limit + 1).all());
35102
+ ).orderBy(desc23(querySnapshots.createdAt)).limit(limit + 1).all());
34963
35103
  const insightMatches = app.db.select().from(insights).where(
34964
35104
  and41(
34965
35105
  eq47(insights.projectId, project.id),
@@ -34970,7 +35110,7 @@ async function compositeRoutes(app, options) {
34970
35110
  sql18`${insights.cause} LIKE ${pattern} ESCAPE '\\'`
34971
35111
  )
34972
35112
  )
34973
- ).orderBy(desc22(insights.createdAt)).limit(limit + 1).all();
35113
+ ).orderBy(desc23(insights.createdAt)).limit(limit + 1).all();
34974
35114
  const hits = [];
34975
35115
  for (const row of snapshotMatches) {
34976
35116
  hits.push(buildSnapshotHit(row, rawQuery));
@@ -35042,7 +35182,7 @@ function loadSnapshotsByRunIds(app, runIds, queryIdByText) {
35042
35182
  rawResponse: querySnapshots.rawResponse,
35043
35183
  competitorOverlap: querySnapshots.competitorOverlap,
35044
35184
  citedDomains: querySnapshots.citedDomains
35045
- }).from(querySnapshots).where(inArray22(querySnapshots.runId, [...runIds])).all();
35185
+ }).from(querySnapshots).where(inArray23(querySnapshots.runId, [...runIds])).all();
35046
35186
  for (const row of rows) {
35047
35187
  const queryText = row.queryText?.trim() || null;
35048
35188
  let queryId;
@@ -35194,8 +35334,8 @@ function buildIndexCoverageScore(app, projectId) {
35194
35334
  tooltip,
35195
35335
  trend: []
35196
35336
  };
35197
- const gscRow = app.db.select().from(gscCoverageSnapshots).where(eq47(gscCoverageSnapshots.projectId, projectId)).orderBy(desc22(gscCoverageSnapshots.date)).limit(1).get();
35198
- const bingRow = app.db.select().from(bingCoverageSnapshots).where(eq47(bingCoverageSnapshots.projectId, projectId)).orderBy(desc22(bingCoverageSnapshots.date)).limit(1).get();
35337
+ const gscRow = app.db.select().from(gscCoverageSnapshots).where(eq47(gscCoverageSnapshots.projectId, projectId)).orderBy(desc23(gscCoverageSnapshots.date)).limit(1).get();
35338
+ const bingRow = app.db.select().from(bingCoverageSnapshots).where(eq47(bingCoverageSnapshots.projectId, projectId)).orderBy(desc23(bingCoverageSnapshots.date)).limit(1).get();
35199
35339
  const chosen = pickIndexCoverageRow(gscRow, bingRow);
35200
35340
  if (!chosen) return empty;
35201
35341
  const total = chosen.indexed + chosen.notIndexed;
@@ -35221,7 +35361,7 @@ function countGoogleDeindexedUrls(app, projectId) {
35221
35361
  url: gscUrlInspections.url,
35222
35362
  indexingState: gscUrlInspections.indexingState,
35223
35363
  inspectedAt: gscUrlInspections.inspectedAt
35224
- }).from(gscUrlInspections).where(eq47(gscUrlInspections.projectId, projectId)).orderBy(desc22(gscUrlInspections.inspectedAt)).all();
35364
+ }).from(gscUrlInspections).where(eq47(gscUrlInspections.projectId, projectId)).orderBy(desc23(gscUrlInspections.inspectedAt)).all();
35225
35365
  if (rows.length === 0) return 0;
35226
35366
  const canonicalUrl = (url) => url.replace(/^http:\/\//, "https://");
35227
35367
  const historyByUrl = /* @__PURE__ */ new Map();
@@ -35477,10 +35617,10 @@ function makeSnippet(text2, query) {
35477
35617
 
35478
35618
  // ../api-routes/src/content.ts
35479
35619
  import crypto24 from "crypto";
35480
- import { and as and43, desc as desc24, eq as eq49 } from "drizzle-orm";
35620
+ import { and as and43, desc as desc25, eq as eq49 } from "drizzle-orm";
35481
35621
 
35482
35622
  // ../api-routes/src/content-data.ts
35483
- import { and as and42, eq as eq48, desc as desc23, gte as gte13, inArray as inArray23, lte as lte12 } from "drizzle-orm";
35623
+ import { and as and42, eq as eq48, desc as desc24, gte as gte13, inArray as inArray24, lte as lte12 } from "drizzle-orm";
35484
35624
  var RECENT_RUNS_WINDOW = 5;
35485
35625
  function loadOrchestratorInput(db, project, locationFilter = void 0, gscWindowDays = DEFAULT_CONTENT_GSC_WINDOW_DAYS) {
35486
35626
  const projectId = project.id;
@@ -35620,12 +35760,12 @@ function listRecentAnswerVisibilityRunIds(db, projectId, limit, locationFilter)
35620
35760
  // Queued/running/failed/cancelled runs may have partial or no
35621
35761
  // snapshots; including them risks pointing latestRunId at a run with
35622
35762
  // no usable evidence.
35623
- inArray23(runs.status, [RunStatuses.completed, RunStatuses.partial]),
35763
+ inArray24(runs.status, [RunStatuses.completed, RunStatuses.partial]),
35624
35764
  // Probe runs are operator/agent test runs; they must not poison the
35625
35765
  // recent-runs window the content engine uses to recommend actions.
35626
35766
  notProbeRun()
35627
35767
  )
35628
- ).orderBy(desc23(runs.createdAt)).all();
35768
+ ).orderBy(desc24(runs.createdAt)).all();
35629
35769
  const filtered = locationFilter === void 0 ? rows : rows.filter((r) => (r.location ?? null) === locationFilter);
35630
35770
  return filtered.slice(0, limit).map((r) => r.id);
35631
35771
  }
@@ -35660,7 +35800,7 @@ function buildGaTrafficByPage(db, projectId, window) {
35660
35800
  return map;
35661
35801
  }
35662
35802
  function resolveContentGaWindow(db, projectId, windowDays2) {
35663
- const latest = db.select({ date: gaTrafficSnapshots.date }).from(gaTrafficSnapshots).where(eq48(gaTrafficSnapshots.projectId, projectId)).orderBy(desc23(gaTrafficSnapshots.date)).limit(1).get();
35803
+ const latest = db.select({ date: gaTrafficSnapshots.date }).from(gaTrafficSnapshots).where(eq48(gaTrafficSnapshots.projectId, projectId)).orderBy(desc24(gaTrafficSnapshots.date)).limit(1).get();
35664
35804
  if (!latest?.date) return null;
35665
35805
  const end = /* @__PURE__ */ new Date(`${latest.date}T00:00:00Z`);
35666
35806
  end.setUTCDate(end.getUTCDate() - (Math.max(1, windowDays2) - 1));
@@ -35688,7 +35828,7 @@ function buildCandidateQueries(opts) {
35688
35828
  const queryRows2 = opts.db.select({ id: queries.id, text: queries.query }).from(queries).where(eq48(queries.projectId, opts.projectId)).all();
35689
35829
  const queryIdByText = new Map(queryRows2.map((r) => [r.text, r.id]));
35690
35830
  const candidateQueryIds = opts.candidateQueryStrings.map((q) => queryIdByText.get(q)).filter((id) => Boolean(id));
35691
- const snapshotRows = filterTrackedSnapshots(opts.db.select().from(querySnapshots).where(inArray23(querySnapshots.runId, opts.recentRunIds)).all()).filter((r) => candidateQueryIds.includes(r.queryId));
35831
+ const snapshotRows = filterTrackedSnapshots(opts.db.select().from(querySnapshots).where(inArray24(querySnapshots.runId, opts.recentRunIds)).all()).filter((r) => candidateQueryIds.includes(r.queryId));
35692
35832
  const snapshotsByQuery = /* @__PURE__ */ new Map();
35693
35833
  for (const row of snapshotRows) {
35694
35834
  const list = snapshotsByQuery.get(row.queryId) ?? [];
@@ -36088,7 +36228,7 @@ async function contentRoutes(app, opts = {}) {
36088
36228
  const row = app.db.select().from(recommendationExplanations).where(and43(
36089
36229
  eq49(recommendationExplanations.projectId, project.id),
36090
36230
  eq49(recommendationExplanations.targetRef, request.params.targetRef)
36091
- )).orderBy(desc24(recommendationExplanations.generatedAt)).limit(1).get();
36231
+ )).orderBy(desc25(recommendationExplanations.generatedAt)).limit(1).get();
36092
36232
  if (!row) {
36093
36233
  return reply.status(404).send({ error: { code: "NOT_FOUND", message: "No cached explanation for this targetRef." } });
36094
36234
  }
@@ -36116,7 +36256,7 @@ async function contentRoutes(app, opts = {}) {
36116
36256
  const cached = app.db.select().from(recommendationExplanations).where(and43(
36117
36257
  eq49(recommendationExplanations.projectId, project.id),
36118
36258
  eq49(recommendationExplanations.targetRef, targetRef)
36119
- )).orderBy(desc24(recommendationExplanations.generatedAt)).limit(1).get();
36259
+ )).orderBy(desc25(recommendationExplanations.generatedAt)).limit(1).get();
36120
36260
  if (cached) return reply.send(formatExplanationRow(cached));
36121
36261
  }
36122
36262
  const result = await explainer({
@@ -36246,7 +36386,7 @@ async function contentRoutes(app, opts = {}) {
36246
36386
  });
36247
36387
  app.get("/projects/:name/content/domain-classifications", async (request) => {
36248
36388
  const project = resolveProject(app.db, request.params.name);
36249
- const rows = app.db.select().from(domainClassifications).where(eq49(domainClassifications.projectId, project.id)).orderBy(desc24(domainClassifications.hits)).all();
36389
+ const rows = app.db.select().from(domainClassifications).where(eq49(domainClassifications.projectId, project.id)).orderBy(desc25(domainClassifications.hits)).all();
36250
36390
  const response = {
36251
36391
  classifications: rows.map((r) => ({
36252
36392
  domain: r.domain,
@@ -36266,7 +36406,7 @@ function lookupCachedBrief(db, projectId, targetRef, promptVersion) {
36266
36406
  if (promptVersion !== void 0) {
36267
36407
  conditions.push(eq49(recommendationBriefs.promptVersion, promptVersion));
36268
36408
  }
36269
- return db.select().from(recommendationBriefs).where(and43(...conditions)).orderBy(desc24(recommendationBriefs.generatedAt)).limit(1).get();
36409
+ return db.select().from(recommendationBriefs).where(and43(...conditions)).orderBy(desc25(recommendationBriefs.generatedAt)).limit(1).get();
36270
36410
  }
36271
36411
  function parseLimitParam(raw) {
36272
36412
  if (raw === void 0) return void 0;
@@ -38832,7 +38972,11 @@ var routeCatalog = [
38832
38972
  location: stringSchema,
38833
38973
  allLocations: booleanSchema,
38834
38974
  noLocation: booleanSchema,
38835
- dispatchMode: dispatchModeRequestSchema
38975
+ dispatchMode: dispatchModeRequestSchema,
38976
+ force: {
38977
+ type: "boolean",
38978
+ description: "Queue the run even when it would be refused with PROVIDERS_FAILING. Admission only; never stored."
38979
+ }
38836
38980
  }
38837
38981
  }
38838
38982
  }
@@ -38843,7 +38987,9 @@ var routeCatalog = [
38843
38987
  400: errorResponse(
38844
38988
  'Invalid request: an untracked query, a measurement scope naming a group/target/question the published plan does not contain, a scope combined with a query list, a per-run location on a plan project, a provider roster the plan was not published for, or `dispatchMode: "batch"` when no provider of the run can batch (`details.ineligible` names each provider\'s reason).'
38845
38989
  ),
38846
- 422: errorResponse("Project has no tracked queries."),
38990
+ 422: errorResponse(
38991
+ `NO_QUERIES: the project has no tracked queries. PROVIDERS_FAILING: every provider the run would call failed on its account (rejected key, denied access, no credit) in each of its last ${PROVIDER_ACCOUNT_FAILURE_STREAK} runs. \`details.providers\` names each provider's code and \`details.retryAfter\` when one run is let through again (${PROVIDER_ACCOUNT_RETRY_HOURS}h after the newest failure). Saving a new key, model or endpoint in a provider's settings lets the next run through at once, a probe is never refused, and \`force: true\` overrides.`
38992
+ ),
38847
38993
  409: errorResponse("Run already in progress."),
38848
38994
  503: errorResponse("No runnable answer provider is configured.")
38849
38995
  }
@@ -38897,7 +39043,11 @@ var routeCatalog = [
38897
39043
  properties: {
38898
39044
  kind: stringSchema,
38899
39045
  providers: stringArraySchema,
38900
- dispatchMode: dispatchModeRequestSchema
39046
+ dispatchMode: dispatchModeRequestSchema,
39047
+ force: {
39048
+ type: "boolean",
39049
+ description: "Queue projects that would be refused with PROVIDERS_FAILING. Admission only; never stored."
39050
+ }
38901
39051
  }
38902
39052
  }
38903
39053
  }
@@ -38906,7 +39056,7 @@ var routeCatalog = [
38906
39056
  responses: {
38907
39057
  // TODO: Add `TriggerAllRunsResponse` Zod schema in contracts.
38908
39058
  207: rawJsonResponse(
38909
- "One row per project: either a queued run or an error for that project alone. A project that cannot be measured (for example one whose published measurement plan expects a different number of answers per question) never prevents or hides the others.",
39059
+ "One row per project: either a queued run or an error for that project alone. A project that cannot be measured (for example one whose published measurement plan expects a different number of answers per question, or one whose providers all keep failing on their accounts: `errorCode: PROVIDERS_FAILING`) never prevents or hides the others.",
38910
39060
  { type: "array", items: looseObjectSchema }
38911
39061
  ),
38912
39062
  400: errorResponse("Invalid request: an unknown provider name, or an unsupported run kind.")
@@ -44154,7 +44304,7 @@ function buildOperationId(method, path8) {
44154
44304
 
44155
44305
  // ../api-routes/src/keys.ts
44156
44306
  import crypto25 from "crypto";
44157
- import { desc as desc25, eq as eq50 } from "drizzle-orm";
44307
+ import { desc as desc26, eq as eq50 } from "drizzle-orm";
44158
44308
  var KEYS_WRITE_SCOPE = "keys.write";
44159
44309
  function toApiKeyDto(row, projectNames) {
44160
44310
  const scopes = Array.isArray(row.scopes) ? row.scopes : [];
@@ -44179,7 +44329,7 @@ async function keysRoutes(app) {
44179
44329
  app.get("/keys", async (request) => {
44180
44330
  requireAdminSession(request);
44181
44331
  const scopedProjectId = request.apiKey?.projectId;
44182
- const rows = scopedProjectId ? app.db.select().from(apiKeys).where(eq50(apiKeys.projectId, scopedProjectId)).orderBy(desc25(apiKeys.createdAt)).all() : app.db.select().from(apiKeys).orderBy(desc25(apiKeys.createdAt)).all();
44332
+ const rows = scopedProjectId ? app.db.select().from(apiKeys).where(eq50(apiKeys.projectId, scopedProjectId)).orderBy(desc26(apiKeys.createdAt)).all() : app.db.select().from(apiKeys).orderBy(desc26(apiKeys.createdAt)).all();
44183
44333
  const names = projectNameById(app.db);
44184
44334
  return { keys: rows.map((row) => toApiKeyDto(row, names)) };
44185
44335
  });
@@ -45181,7 +45331,7 @@ function formatNotification(row) {
45181
45331
 
45182
45332
  // ../api-routes/src/google.ts
45183
45333
  import crypto33 from "crypto";
45184
- import { eq as eq54, and as and45, desc as desc26, sql as sql19, inArray as inArray24 } from "drizzle-orm";
45334
+ import { eq as eq54, and as and45, desc as desc27, sql as sql19, inArray as inArray25 } from "drizzle-orm";
45185
45335
 
45186
45336
  // ../api-routes/src/gsc-period-comparison.ts
45187
45337
  var DAY_MS = 864e5;
@@ -47692,9 +47842,9 @@ async function googleRoutes(app, opts) {
47692
47842
  const limitVal = Math.max(parseInt(limit ?? "500", 10) || 0, 1);
47693
47843
  const offsetVal = Math.max(parseInt(offset ?? "0", 10) || 0, 0);
47694
47844
  const orderColumns = {
47695
- clicks: [desc26(gscSearchData.clicks), desc26(gscSearchData.date), gscSearchData.query],
47696
- impressions: [desc26(gscSearchData.impressions), desc26(gscSearchData.date), gscSearchData.query],
47697
- date: [desc26(gscSearchData.date), desc26(gscSearchData.clicks), gscSearchData.query]
47845
+ clicks: [desc27(gscSearchData.clicks), desc27(gscSearchData.date), gscSearchData.query],
47846
+ impressions: [desc27(gscSearchData.impressions), desc27(gscSearchData.date), gscSearchData.query],
47847
+ date: [desc27(gscSearchData.date), desc27(gscSearchData.clicks), gscSearchData.query]
47698
47848
  }[orderBy];
47699
47849
  const rows = app.db.select().from(gscSearchData).where(and45(...conditions)).orderBy(...orderColumns).limit(limitVal).offset(offsetVal).all();
47700
47850
  const totalMatching = app.db.select({ total: sql19`COUNT(*)` }).from(gscSearchData).where(and45(...conditions)).get()?.total ?? 0;
@@ -47853,7 +48003,7 @@ async function googleRoutes(app, opts) {
47853
48003
  page: gscSearchData.page,
47854
48004
  clicks: sql19`COALESCE(SUM(${gscSearchData.clicks}), 0)`,
47855
48005
  impressions: sql19`COALESCE(SUM(${gscSearchData.impressions}), 0)`
47856
- }).from(gscSearchData).where(and45(...conditions)).groupBy(gscSearchData.page).orderBy(desc26(sql19`SUM(${gscSearchData.clicks})`), desc26(sql19`SUM(${gscSearchData.impressions})`)).limit(limitVal).all();
48006
+ }).from(gscSearchData).where(and45(...conditions)).groupBy(gscSearchData.page).orderBy(desc27(sql19`SUM(${gscSearchData.clicks})`), desc27(sql19`SUM(${gscSearchData.impressions})`)).limit(limitVal).all();
47857
48007
  const windowStart = startDate ?? cutoffDate ?? "";
47858
48008
  const windowEnd = endDate ?? resolvedWindow.endDate ?? "9999-12-31";
47859
48009
  const dailyTotals = readGscDailyTotals(app.db, project.id, windowStart, windowEnd);
@@ -47996,7 +48146,7 @@ async function googleRoutes(app, opts) {
47996
48146
  const { url, limit } = request.query;
47997
48147
  const conditions = [eq54(gscUrlInspections.projectId, project.id)];
47998
48148
  if (url) conditions.push(eq54(gscUrlInspections.url, url));
47999
- const rows = app.db.select().from(gscUrlInspections).where(and45(...conditions)).orderBy(desc26(gscUrlInspections.inspectedAt)).limit(parseInt(limit ?? "100", 10)).all();
48149
+ const rows = app.db.select().from(gscUrlInspections).where(and45(...conditions)).orderBy(desc27(gscUrlInspections.inspectedAt)).limit(parseInt(limit ?? "100", 10)).all();
48000
48150
  return rows.map((r) => ({
48001
48151
  id: r.id,
48002
48152
  url: r.url,
@@ -48015,7 +48165,7 @@ async function googleRoutes(app, opts) {
48015
48165
  });
48016
48166
  app.get("/projects/:name/google/gsc/deindexed", async (request) => {
48017
48167
  const project = resolveProject(app.db, request.params.name);
48018
- const allInspections = app.db.select().from(gscUrlInspections).where(eq54(gscUrlInspections.projectId, project.id)).orderBy(desc26(gscUrlInspections.inspectedAt)).all();
48168
+ const allInspections = app.db.select().from(gscUrlInspections).where(eq54(gscUrlInspections.projectId, project.id)).orderBy(desc27(gscUrlInspections.inspectedAt)).all();
48019
48169
  const byUrl = /* @__PURE__ */ new Map();
48020
48170
  for (const row of allInspections) {
48021
48171
  const existing = byUrl.get(row.url);
@@ -48043,7 +48193,7 @@ async function googleRoutes(app, opts) {
48043
48193
  });
48044
48194
  app.get("/projects/:name/google/gsc/coverage", async (request) => {
48045
48195
  const project = resolveProject(app.db, request.params.name);
48046
- const allInspections = app.db.select().from(gscUrlInspections).where(eq54(gscUrlInspections.projectId, project.id)).orderBy(desc26(gscUrlInspections.inspectedAt)).all();
48196
+ const allInspections = app.db.select().from(gscUrlInspections).where(eq54(gscUrlInspections.projectId, project.id)).orderBy(desc27(gscUrlInspections.inspectedAt)).all();
48047
48197
  const canonicalUrl = (url) => url.replace(/^http:\/\//, "https://");
48048
48198
  const latestByUrl = /* @__PURE__ */ new Map();
48049
48199
  const historyByUrl = /* @__PURE__ */ new Map();
@@ -48092,7 +48242,7 @@ async function googleRoutes(app, opts) {
48092
48242
  const total = latestByUrl.size;
48093
48243
  const indexed = indexedUrls.length;
48094
48244
  const notIndexed = notIndexedUrls.length;
48095
- const latestSnapshot = app.db.select({ createdAt: gscCoverageSnapshots.createdAt }).from(gscCoverageSnapshots).where(eq54(gscCoverageSnapshots.projectId, project.id)).orderBy(desc26(gscCoverageSnapshots.createdAt)).limit(1).get();
48245
+ const latestSnapshot = app.db.select({ createdAt: gscCoverageSnapshots.createdAt }).from(gscCoverageSnapshots).where(eq54(gscCoverageSnapshots.projectId, project.id)).orderBy(desc27(gscCoverageSnapshots.createdAt)).limit(1).get();
48096
48246
  const lastSyncedAt = latestSnapshot?.createdAt ?? null;
48097
48247
  const formatRow = (r) => ({
48098
48248
  id: r.id,
@@ -48148,7 +48298,7 @@ async function googleRoutes(app, opts) {
48148
48298
  const project = resolveProject(app.db, request.params.name);
48149
48299
  const parsed = parseInt(request.query.limit ?? "90", 10);
48150
48300
  const limit = Number.isNaN(parsed) || parsed <= 0 ? 90 : parsed;
48151
- const rows = app.db.select().from(gscCoverageSnapshots).where(eq54(gscCoverageSnapshots.projectId, project.id)).orderBy(desc26(gscCoverageSnapshots.date)).limit(limit).all();
48301
+ const rows = app.db.select().from(gscCoverageSnapshots).where(eq54(gscCoverageSnapshots.projectId, project.id)).orderBy(desc27(gscCoverageSnapshots.date)).limit(limit).all();
48152
48302
  return rows.map((r) => ({
48153
48303
  date: r.date,
48154
48304
  indexed: r.indexed,
@@ -48362,7 +48512,7 @@ async function googleRoutes(app, opts) {
48362
48512
  const { accessToken } = await getValidToken(store, project.canonicalDomain, "gsc", googleClientId, googleClientSecret);
48363
48513
  let urlsToNotify = request.body?.urls ?? [];
48364
48514
  if (request.body?.allUnindexed) {
48365
- const allInspections = app.db.select().from(gscUrlInspections).where(eq54(gscUrlInspections.projectId, project.id)).orderBy(desc26(gscUrlInspections.inspectedAt)).all();
48515
+ const allInspections = app.db.select().from(gscUrlInspections).where(eq54(gscUrlInspections.projectId, project.id)).orderBy(desc27(gscUrlInspections.inspectedAt)).all();
48366
48516
  const latestByUrl = /* @__PURE__ */ new Map();
48367
48517
  for (const row of allInspections) {
48368
48518
  if (!latestByUrl.has(row.url)) {
@@ -48729,7 +48879,7 @@ async function googleRoutes(app, opts) {
48729
48879
  const conditions = [eq54(gbpDailyMetrics.projectId, project.id)];
48730
48880
  if (request.query.locationName) conditions.push(eq54(gbpDailyMetrics.locationName, request.query.locationName));
48731
48881
  if (request.query.metric) conditions.push(eq54(gbpDailyMetrics.metric, request.query.metric));
48732
- const rows = app.db.select().from(gbpDailyMetrics).where(and45(...conditions)).orderBy(desc26(gbpDailyMetrics.date)).all();
48882
+ const rows = app.db.select().from(gbpDailyMetrics).where(and45(...conditions)).orderBy(desc27(gbpDailyMetrics.date)).all();
48733
48883
  return {
48734
48884
  metrics: rows.map((r) => ({ locationName: r.locationName, date: r.date, metric: r.metric, value: r.value })),
48735
48885
  total: rows.length
@@ -48776,7 +48926,7 @@ async function googleRoutes(app, opts) {
48776
48926
  const project = resolveProject(app.db, request.params.name);
48777
48927
  const conditions = [eq54(gbpLodgingSnapshots.projectId, project.id)];
48778
48928
  if (request.query.locationName) conditions.push(eq54(gbpLodgingSnapshots.locationName, request.query.locationName));
48779
- const rows = app.db.select().from(gbpLodgingSnapshots).where(and45(...conditions)).orderBy(desc26(gbpLodgingSnapshots.syncedAt)).all();
48929
+ const rows = app.db.select().from(gbpLodgingSnapshots).where(and45(...conditions)).orderBy(desc27(gbpLodgingSnapshots.syncedAt)).all();
48780
48930
  const latestByLocation = /* @__PURE__ */ new Map();
48781
48931
  for (const row of rows) {
48782
48932
  if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
@@ -48793,7 +48943,7 @@ async function googleRoutes(app, opts) {
48793
48943
  const project = resolveProject(app.db, request.params.name);
48794
48944
  const conditions = [eq54(gbpAttributesSnapshots.projectId, project.id)];
48795
48945
  if (request.query.locationName) conditions.push(eq54(gbpAttributesSnapshots.locationName, request.query.locationName));
48796
- const rows = app.db.select().from(gbpAttributesSnapshots).where(and45(...conditions)).orderBy(desc26(gbpAttributesSnapshots.syncedAt)).all();
48946
+ const rows = app.db.select().from(gbpAttributesSnapshots).where(and45(...conditions)).orderBy(desc27(gbpAttributesSnapshots.syncedAt)).all();
48797
48947
  const latestByLocation = /* @__PURE__ */ new Map();
48798
48948
  for (const row of rows) {
48799
48949
  if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
@@ -48813,7 +48963,7 @@ async function googleRoutes(app, opts) {
48813
48963
  const project = resolveProject(app.db, request.params.name);
48814
48964
  const conditions = [eq54(gbpPlaceDetails.projectId, project.id)];
48815
48965
  if (request.query.locationName) conditions.push(eq54(gbpPlaceDetails.locationName, request.query.locationName));
48816
- const rows = app.db.select().from(gbpPlaceDetails).where(and45(...conditions)).orderBy(desc26(gbpPlaceDetails.syncedAt)).all();
48966
+ const rows = app.db.select().from(gbpPlaceDetails).where(and45(...conditions)).orderBy(desc27(gbpPlaceDetails.syncedAt)).all();
48817
48967
  const latestByLocation = /* @__PURE__ */ new Map();
48818
48968
  for (const row of rows) {
48819
48969
  if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
@@ -48840,7 +48990,7 @@ async function googleRoutes(app, opts) {
48840
48990
  locationName ? eq54(gbpLocations.locationName, locationName) : eq54(gbpLocations.selected, true)
48841
48991
  )).orderBy(gbpLocations.displayName).all();
48842
48992
  const latestRating = /* @__PURE__ */ new Map();
48843
- for (const row of app.db.select().from(gbpReviewRatings).where(eq54(gbpReviewRatings.projectId, project.id)).orderBy(desc26(gbpReviewRatings.observedAt)).all()) {
48993
+ for (const row of app.db.select().from(gbpReviewRatings).where(eq54(gbpReviewRatings.projectId, project.id)).orderBy(desc27(gbpReviewRatings.observedAt)).all()) {
48844
48994
  if (!latestRating.has(row.locationName)) latestRating.set(row.locationName, row);
48845
48995
  }
48846
48996
  const locations = locationRows.map((loc) => {
@@ -48861,7 +49011,7 @@ async function googleRoutes(app, opts) {
48861
49011
  if (locationName) conditions.push(eq54(gbpReviews.locationName, locationName));
48862
49012
  if (negativeOnly) conditions.push(sql19`${gbpReviews.starRating} BETWEEN 1 AND ${negativeMaxStars}`);
48863
49013
  const total = app.db.select({ n: sql19`count(*)` }).from(gbpReviews).where(and45(...conditions)).get()?.n ?? 0;
48864
- const reviews = app.db.select().from(gbpReviews).where(and45(...conditions)).orderBy(desc26(gbpReviews.updateTime), gbpReviews.reviewName).limit(limit).all().map((r) => ({
49014
+ const reviews = app.db.select().from(gbpReviews).where(and45(...conditions)).orderBy(desc27(gbpReviews.updateTime), gbpReviews.reviewName).limit(limit).all().map((r) => ({
48865
49015
  locationName: r.locationName,
48866
49016
  origin: r.origin,
48867
49017
  reviewName: r.reviewName,
@@ -48900,10 +49050,10 @@ async function googleRoutes(app, opts) {
48900
49050
  locationProfiles: []
48901
49051
  });
48902
49052
  }
48903
- const metricRows = app.db.select().from(gbpDailyMetrics).where(and45(eq54(gbpDailyMetrics.projectId, project.id), inArray24(gbpDailyMetrics.locationName, locationNames))).all();
48904
- const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and45(eq54(gbpKeywordImpressions.projectId, project.id), inArray24(gbpKeywordImpressions.locationName, locationNames))).all();
48905
- const placeActionRows = app.db.select().from(gbpPlaceActions).where(and45(eq54(gbpPlaceActions.projectId, project.id), inArray24(gbpPlaceActions.locationName, locationNames))).all();
48906
- const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and45(eq54(gbpLodgingSnapshots.projectId, project.id), inArray24(gbpLodgingSnapshots.locationName, locationNames))).orderBy(desc26(gbpLodgingSnapshots.syncedAt)).all();
49053
+ const metricRows = app.db.select().from(gbpDailyMetrics).where(and45(eq54(gbpDailyMetrics.projectId, project.id), inArray25(gbpDailyMetrics.locationName, locationNames))).all();
49054
+ const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and45(eq54(gbpKeywordImpressions.projectId, project.id), inArray25(gbpKeywordImpressions.locationName, locationNames))).all();
49055
+ const placeActionRows = app.db.select().from(gbpPlaceActions).where(and45(eq54(gbpPlaceActions.projectId, project.id), inArray25(gbpPlaceActions.locationName, locationNames))).all();
49056
+ const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and45(eq54(gbpLodgingSnapshots.projectId, project.id), inArray25(gbpLodgingSnapshots.locationName, locationNames))).orderBy(desc27(gbpLodgingSnapshots.syncedAt)).all();
48907
49057
  const latestLodgingByLocation = /* @__PURE__ */ new Map();
48908
49058
  for (const row of lodgingRows) {
48909
49059
  if (!latestLodgingByLocation.has(row.locationName)) {
@@ -48917,7 +49067,7 @@ async function googleRoutes(app, opts) {
48917
49067
  regularHours: gbpLocations.regularHours,
48918
49068
  primaryPhone: gbpLocations.primaryPhone,
48919
49069
  openStatus: gbpLocations.openStatus
48920
- }).from(gbpLocations).where(and45(eq54(gbpLocations.projectId, project.id), inArray24(gbpLocations.locationName, locationNames))).all();
49070
+ }).from(gbpLocations).where(and45(eq54(gbpLocations.projectId, project.id), inArray25(gbpLocations.locationName, locationNames))).all();
48921
49071
  return buildGbpSummary({
48922
49072
  locationName,
48923
49073
  locationCount: locationNames.length,
@@ -48948,7 +49098,7 @@ function parseReviewLimit(value) {
48948
49098
 
48949
49099
  // ../api-routes/src/google-marketing.ts
48950
49100
  import crypto34 from "crypto";
48951
- import { and as and46, desc as desc27, eq as eq55, isNull as isNull10, lt as lt9, ne as ne10, or as or13, sql as sql20 } from "drizzle-orm";
49101
+ import { and as and46, desc as desc28, eq as eq55, isNull as isNull10, lt as lt9, ne as ne10, or as or13, sql as sql20 } from "drizzle-orm";
48952
49102
  import { z as z4 } from "zod";
48953
49103
  var snapshotPageQuerySchema = z4.object({
48954
49104
  limit: z4.coerce.number().int().min(1).max(GOOGLE_MARKETING_STORED_SNAPSHOT_PAGE_MAX).optional(),
@@ -50164,7 +50314,7 @@ async function googleMarketingRoutes(app, opts) {
50164
50314
  eq55(runs.projectId, project.id),
50165
50315
  eq55(runs.kind, RunKinds["google-ads-sync"]),
50166
50316
  or13(eq55(runs.status, RunStatuses.queued), eq55(runs.status, RunStatuses.running))
50167
- )).orderBy(desc27(runs.createdAt)).get();
50317
+ )).orderBy(desc28(runs.createdAt)).get();
50168
50318
  if (existing) {
50169
50319
  run = existing;
50170
50320
  return;
@@ -50200,7 +50350,7 @@ async function googleMarketingRoutes(app, opts) {
50200
50350
  eq55(runs.projectId, project.id),
50201
50351
  eq55(runs.kind, RunKinds["gtm-sync"]),
50202
50352
  or13(eq55(runs.status, RunStatuses.queued), eq55(runs.status, RunStatuses.running))
50203
- )).orderBy(desc27(runs.createdAt)).get();
50353
+ )).orderBy(desc28(runs.createdAt)).get();
50204
50354
  if (existing) {
50205
50355
  run = existing;
50206
50356
  return;
@@ -50235,7 +50385,7 @@ async function googleMarketingRoutes(app, opts) {
50235
50385
  ));
50236
50386
  }
50237
50387
  const limit = query.limit ?? 50;
50238
- const rows = app.db.select().from(googleAdsRawSnapshots).where(and46(...conditions)).orderBy(desc27(googleAdsRawSnapshots.capturedAt), desc27(googleAdsRawSnapshots.id)).limit(limit + 1).all();
50388
+ const rows = app.db.select().from(googleAdsRawSnapshots).where(and46(...conditions)).orderBy(desc28(googleAdsRawSnapshots.capturedAt), desc28(googleAdsRawSnapshots.id)).limit(limit + 1).all();
50239
50389
  const page3 = rows.slice(0, limit);
50240
50390
  const total = app.db.select({ total: sql20`COUNT(*)`.mapWith(Number).as("total") }).from(googleAdsRawSnapshots).where(eq55(googleAdsRawSnapshots.projectId, project.id)).get();
50241
50391
  return {
@@ -50267,7 +50417,7 @@ async function googleMarketingRoutes(app, opts) {
50267
50417
  ));
50268
50418
  }
50269
50419
  const limit = query.limit ?? 50;
50270
- const rows = app.db.select().from(gtmRawSnapshots).where(and46(...conditions)).orderBy(desc27(gtmRawSnapshots.capturedAt), desc27(gtmRawSnapshots.id)).limit(limit + 1).all();
50420
+ const rows = app.db.select().from(gtmRawSnapshots).where(and46(...conditions)).orderBy(desc28(gtmRawSnapshots.capturedAt), desc28(gtmRawSnapshots.id)).limit(limit + 1).all();
50271
50421
  const page3 = rows.slice(0, limit);
50272
50422
  const total = app.db.select({ total: sql20`COUNT(*)`.mapWith(Number).as("total") }).from(gtmRawSnapshots).where(eq55(gtmRawSnapshots.projectId, project.id)).get();
50273
50423
  return {
@@ -50538,7 +50688,7 @@ async function googleMarketingRoutes(app, opts) {
50538
50688
 
50539
50689
  // ../api-routes/src/ads.ts
50540
50690
  import crypto37 from "crypto";
50541
- import { eq as eq57, and as and48, asc as asc11, desc as desc28, gt as gt5, gte as gte14, lt as lt10, lte as lte14, ne as ne11, inArray as inArray25, or as or15, isNull as isNull12, isNotNull as isNotNull7, sql as sql22 } from "drizzle-orm";
50691
+ import { eq as eq57, and as and48, asc as asc11, desc as desc29, gt as gt6, gte as gte14, lt as lt10, lte as lte14, ne as ne11, inArray as inArray26, or as or15, isNull as isNull12, isNotNull as isNotNull7, sql as sql22 } from "drizzle-orm";
50542
50692
 
50543
50693
  // ../api-routes/src/ads-activation.ts
50544
50694
  import crypto35 from "crypto";
@@ -51924,7 +52074,7 @@ async function executeApprovedAdsActivation(dependencies, request) {
51924
52074
 
51925
52075
  // ../api-routes/src/ads-activation-routes.ts
51926
52076
  import crypto36 from "crypto";
51927
- import { and as and47, asc as asc10, eq as eq56, gt as gt4, isNotNull as isNotNull6, isNull as isNull11, lte as lte13, or as or14, sql as sql21 } from "drizzle-orm";
52077
+ import { and as and47, asc as asc10, eq as eq56, gt as gt5, isNotNull as isNotNull6, isNull as isNull11, lte as lte13, or as or14, sql as sql21 } from "drizzle-orm";
51928
52078
  var MAX_ACTIVATION_GRANT_LIFETIME_MS = 24 * 60 * 60 * 1e3;
51929
52079
  var ACTIVATION_LEASE_MS = 5 * 6e4;
51930
52080
  var ACTIVATION_REVOCATION_SETTLEMENT_MS = ACTIVATION_LEASE_MS;
@@ -52145,7 +52295,7 @@ function createActivationStore(app, request) {
52145
52295
  eq56(adsOperations.id, input.operationId),
52146
52296
  eq56(adsOperations.state, AdsOperationStates.pending),
52147
52297
  eq56(adsOperations.leaseOwner, input.leaseOwner),
52148
- gt4(adsOperations.leaseExpiresAt, input.now)
52298
+ gt5(adsOperations.leaseExpiresAt, input.now)
52149
52299
  )).run();
52150
52300
  const operation = loadActivationOperation(tx, input.operationId);
52151
52301
  if (!operation) throw internalError("Ads activation receipt was not found");
@@ -52201,7 +52351,7 @@ function createActivationStore(app, request) {
52201
52351
  eq56(adsOperations.id, input.operationId),
52202
52352
  eq56(adsOperations.state, AdsOperationStates.pending),
52203
52353
  eq56(adsOperations.leaseOwner, input.leaseOwner),
52204
- gt4(adsOperations.leaseExpiresAt, input.next.updatedAt)
52354
+ gt5(adsOperations.leaseExpiresAt, input.next.updatedAt)
52205
52355
  )).run();
52206
52356
  if (lease.changes !== 1 || existing.state !== input.fromState) {
52207
52357
  const current2 = loadActivationOperation(tx, input.operationId);
@@ -52243,7 +52393,7 @@ function createActivationStore(app, request) {
52243
52393
  eq56(adsOperations.id, input.operationId),
52244
52394
  eq56(adsOperations.state, AdsOperationStates.pending),
52245
52395
  eq56(adsOperations.leaseOwner, input.leaseOwner),
52246
- gt4(adsOperations.leaseExpiresAt, input.next.updatedAt)
52396
+ gt5(adsOperations.leaseExpiresAt, input.next.updatedAt)
52247
52397
  )).run();
52248
52398
  if (lease.changes !== 1 || existing.state !== input.fromState) {
52249
52399
  const operation2 = loadActivationOperation(tx, input.operationId);
@@ -52306,7 +52456,7 @@ function createActivationStore(app, request) {
52306
52456
  eq56(adsOperations.id, input.operationId),
52307
52457
  eq56(adsOperations.state, AdsOperationStates.pending),
52308
52458
  eq56(adsOperations.leaseOwner, input.leaseOwner),
52309
- gt4(adsOperations.leaseExpiresAt, input.now)
52459
+ gt5(adsOperations.leaseExpiresAt, input.now)
52310
52460
  )).run();
52311
52461
  if (operationUpdate.changes === 1) {
52312
52462
  const grantUpdate = tx.update(adsActivationGrants).set({
@@ -53582,7 +53732,7 @@ function semanticallyMatchesMaterializedEntity(app, input) {
53582
53732
  eq57(adsOperations.projectId, input.projectId),
53583
53733
  eq57(adsOperations.entityType, input.entityType),
53584
53734
  eq57(adsOperations.entityId, input.entityId),
53585
- inArray25(adsOperations.kind, [createKind, updateKind])
53735
+ inArray26(adsOperations.kind, [createKind, updateKind])
53586
53736
  )).orderBy(asc11(adsOperations.createdAt), asc11(adsOperations.id)).all();
53587
53737
  if (rows.some((row) => row.state === AdsOperationStates.pending || row.state === AdsOperationStates.reconciling || row.state === AdsOperationStates.unknown || row.kind === updateKind && row.state === AdsOperationStates.succeeded)) {
53588
53738
  return false;
@@ -54019,7 +54169,7 @@ function quarantineExhaustedReconciliation(app, row, now, policy, context) {
54019
54169
  eq57(adsOperations.id, row.id),
54020
54170
  eq57(adsOperations.projectId, row.projectId),
54021
54171
  gte14(adsOperations.reconcileAttempts, policy.maxAttempts),
54022
- inArray25(adsOperations.state, [
54172
+ inArray26(adsOperations.state, [
54023
54173
  AdsOperationStates.pending,
54024
54174
  AdsOperationStates.unknown,
54025
54175
  AdsOperationStates.reconciling
@@ -54243,7 +54393,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
54243
54393
  eq57(adsOperations.reconcileStrategy, AdsReconcileStrategies.create_fingerprint),
54244
54394
  or15(
54245
54395
  isNotNull7(adsOperations.entityId),
54246
- inArray25(adsOperations.state, [
54396
+ inArray26(adsOperations.state, [
54247
54397
  AdsOperationStates.pending,
54248
54398
  AdsOperationStates.reconciling
54249
54399
  ])
@@ -54291,7 +54441,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
54291
54441
  const eligibleProjectIds = [...credentialsByProjectId.keys()];
54292
54442
  if (eligibleProjectIds.length === 0) return;
54293
54443
  const rows = app.db.select().from(adsOperations).where(and48(
54294
- inArray25(adsOperations.projectId, eligibleProjectIds),
54444
+ inArray26(adsOperations.projectId, eligibleProjectIds),
54295
54445
  staleReconcileWhere
54296
54446
  )).orderBy(asc11(adsOperations.updatedAt)).limit(config.batchSize).all();
54297
54447
  for (const row of rows) {
@@ -54613,12 +54763,12 @@ async function adsRoutes(app, opts) {
54613
54763
  const cursor = parsed.data.cursor ? decodeAdsOperationCursor(parsed.data.cursor, project.id, parsed.data.state) : void 0;
54614
54764
  const rows = app.db.select().from(adsOperations).where(and48(
54615
54765
  eq57(adsOperations.projectId, project.id),
54616
- inArray25(adsOperations.state, parsed.data.state),
54766
+ inArray26(adsOperations.state, parsed.data.state),
54617
54767
  cursor ? or15(
54618
- gt5(adsOperations.createdAt, cursor.createdAt),
54768
+ gt6(adsOperations.createdAt, cursor.createdAt),
54619
54769
  and48(
54620
54770
  eq57(adsOperations.createdAt, cursor.createdAt),
54621
- gt5(adsOperations.id, cursor.id)
54771
+ gt6(adsOperations.id, cursor.id)
54622
54772
  )
54623
54773
  ) : void 0
54624
54774
  )).orderBy(asc11(adsOperations.createdAt), asc11(adsOperations.id)).limit(parsed.data.limit + 1).all();
@@ -55047,7 +55197,7 @@ async function adsRoutes(app, opts) {
55047
55197
  const inFlight = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and48(
55048
55198
  eq57(runs.projectId, project.id),
55049
55199
  eq57(runs.kind, RunKinds["ads-sync"]),
55050
- inArray25(runs.status, [RunStatuses.queued, RunStatuses.running])
55200
+ inArray26(runs.status, [RunStatuses.queued, RunStatuses.running])
55051
55201
  )).get();
55052
55202
  if (inFlight) {
55053
55203
  const existing = { runId: inFlight.id, status: inFlight.status };
@@ -55178,7 +55328,7 @@ async function adsRoutes(app, opts) {
55178
55328
  const latestAdsSync = app.db.select({ id: runs.id, kind: runs.kind, status: runs.status }).from(runs).where(and48(
55179
55329
  eq57(runs.projectId, project.id),
55180
55330
  eq57(runs.kind, RunKinds["ads-sync"])
55181
- )).orderBy(desc28(runs.createdAt)).get();
55331
+ )).orderBy(desc29(runs.createdAt)).get();
55182
55332
  const snapshot = storedSnapshotProvenance({
55183
55333
  connected: Boolean(connection),
55184
55334
  connectionLastSyncedAt: connection?.lastSyncedAt ?? null,
@@ -55582,7 +55732,7 @@ async function adsRoutes(app, opts) {
55582
55732
 
55583
55733
  // ../api-routes/src/bing.ts
55584
55734
  import crypto39 from "crypto";
55585
- import { eq as eq58, and as and49, desc as desc29 } from "drizzle-orm";
55735
+ import { eq as eq58, and as and49, desc as desc30 } from "drizzle-orm";
55586
55736
 
55587
55737
  // ../integration-bing/src/bing-client.ts
55588
55738
  import crypto38 from "crypto";
@@ -56001,7 +56151,7 @@ async function bingRoutes(app, opts) {
56001
56151
  const store = requireConnectionStore();
56002
56152
  const project = resolveProject(app.db, request.params.name);
56003
56153
  requireConnection(store, project.canonicalDomain);
56004
- const allInspections = app.db.select().from(bingUrlInspections).where(eq58(bingUrlInspections.projectId, project.id)).orderBy(desc29(bingUrlInspections.inspectedAt)).all();
56154
+ const allInspections = app.db.select().from(bingUrlInspections).where(eq58(bingUrlInspections.projectId, project.id)).orderBy(desc30(bingUrlInspections.inspectedAt)).all();
56005
56155
  const latestByUrl = /* @__PURE__ */ new Map();
56006
56156
  const definitiveByUrl = /* @__PURE__ */ new Map();
56007
56157
  for (const row of allInspections) {
@@ -56090,7 +56240,7 @@ async function bingRoutes(app, opts) {
56090
56240
  const project = resolveProject(app.db, request.params.name);
56091
56241
  const parsed = parseInt(request.query.limit ?? "90", 10);
56092
56242
  const limit = Number.isNaN(parsed) || parsed <= 0 ? 90 : parsed;
56093
- const rows = app.db.select().from(bingCoverageSnapshots).where(eq58(bingCoverageSnapshots.projectId, project.id)).orderBy(desc29(bingCoverageSnapshots.date)).limit(limit).all();
56243
+ const rows = app.db.select().from(bingCoverageSnapshots).where(eq58(bingCoverageSnapshots.projectId, project.id)).orderBy(desc30(bingCoverageSnapshots.date)).limit(limit).all();
56094
56244
  return rows.map((r) => ({
56095
56245
  date: r.date,
56096
56246
  indexed: r.indexed,
@@ -56103,7 +56253,7 @@ async function bingRoutes(app, opts) {
56103
56253
  const project = resolveProject(app.db, request.params.name);
56104
56254
  const { url, limit } = request.query;
56105
56255
  const whereClause = url ? and49(eq58(bingUrlInspections.projectId, project.id), eq58(bingUrlInspections.url, url)) : eq58(bingUrlInspections.projectId, project.id);
56106
- const filtered = app.db.select().from(bingUrlInspections).where(whereClause).orderBy(desc29(bingUrlInspections.inspectedAt)).limit(Math.max(1, Math.min(parseInt(limit ?? "100", 10) || 100, 1e3))).all();
56256
+ const filtered = app.db.select().from(bingUrlInspections).where(whereClause).orderBy(desc30(bingUrlInspections.inspectedAt)).limit(Math.max(1, Math.min(parseInt(limit ?? "100", 10) || 100, 1e3))).all();
56107
56257
  return filtered.map((r) => ({
56108
56258
  id: r.id,
56109
56259
  url: r.url,
@@ -56247,7 +56397,7 @@ async function bingRoutes(app, opts) {
56247
56397
  }
56248
56398
  let urlsToSubmit = request.body?.urls ?? [];
56249
56399
  if (request.body?.allUnindexed) {
56250
- const allInspections = app.db.select().from(bingUrlInspections).where(eq58(bingUrlInspections.projectId, project.id)).orderBy(desc29(bingUrlInspections.inspectedAt)).all();
56400
+ const allInspections = app.db.select().from(bingUrlInspections).where(eq58(bingUrlInspections.projectId, project.id)).orderBy(desc30(bingUrlInspections.inspectedAt)).all();
56251
56401
  const latestByUrl = /* @__PURE__ */ new Map();
56252
56402
  for (const row of allInspections) {
56253
56403
  if (!latestByUrl.has(row.url)) {
@@ -56506,7 +56656,7 @@ async function cdpRoutes(app, opts) {
56506
56656
 
56507
56657
  // ../api-routes/src/ga.ts
56508
56658
  import crypto40 from "crypto";
56509
- import { eq as eq60, desc as desc30, and as and51, sql as sql23 } from "drizzle-orm";
56659
+ import { eq as eq60, desc as desc31, and as and51, sql as sql23 } from "drizzle-orm";
56510
56660
 
56511
56661
  // ../api-routes/src/ga-session-history.ts
56512
56662
  function buildSessionHistory(landingPageDays, dailyTotals) {
@@ -56982,7 +57132,7 @@ async function ga4Routes(app, opts) {
56982
57132
  if (!connected) {
56983
57133
  return { connected: false, propertyId: null, clientEmail: null, authMethod: null, lastSyncedAt: null };
56984
57134
  }
56985
- const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq60(gaTrafficSummaries.projectId, project.id)).orderBy(desc30(gaTrafficSummaries.syncedAt)).limit(1).get();
57135
+ const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq60(gaTrafficSummaries.projectId, project.id)).orderBy(desc31(gaTrafficSummaries.syncedAt)).limit(1).get();
56986
57136
  return {
56987
57137
  connected: true,
56988
57138
  propertyId: saConn?.propertyId ?? oauthConn?.propertyId ?? null,
@@ -57412,7 +57562,7 @@ async function ga4Routes(app, opts) {
57412
57562
  const socialTotals = app.db.select({
57413
57563
  sessions: sql23`SUM(${gaSocialReferrals.sessions})`
57414
57564
  }).from(gaSocialReferrals).where(and51(...socialConditions)).get();
57415
- const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq60(gaTrafficSummaries.projectId, project.id)).orderBy(desc30(gaTrafficSummaries.syncedAt)).limit(1).get();
57565
+ const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq60(gaTrafficSummaries.projectId, project.id)).orderBy(desc31(gaTrafficSummaries.syncedAt)).limit(1).get();
57416
57566
  const total = summaryRow?.totalSessions ?? 0;
57417
57567
  const totalDirectSessions = directTotalRow?.totalDirectSessions ?? 0;
57418
57568
  const totalOrganicSessions = summaryRow?.totalOrganicSessions ?? 0;
@@ -59364,7 +59514,7 @@ async function wordpressRoutes(app, opts) {
59364
59514
 
59365
59515
  // ../api-routes/src/backlinks.ts
59366
59516
  import crypto42 from "crypto";
59367
- import { and as and53, asc as asc12, desc as desc31, eq as eq61, sql as sql24 } from "drizzle-orm";
59517
+ import { and as and53, asc as asc12, desc as desc32, eq as eq61, sql as sql24 } from "drizzle-orm";
59368
59518
 
59369
59519
  // ../integration-commoncrawl/src/constants.ts
59370
59520
  import os2 from "os";
@@ -59865,7 +60015,7 @@ function latestSummaryForProject(db, projectId, source, release) {
59865
60015
  eq61(backlinkSummaries.source, source)
59866
60016
  ];
59867
60017
  if (release) conditions.push(eq61(backlinkSummaries.release, release));
59868
- return db.select().from(backlinkSummaries).where(and53(...conditions)).orderBy(desc31(backlinkSummaries.queriedAt)).limit(1).get();
60018
+ return db.select().from(backlinkSummaries).where(and53(...conditions)).orderBy(desc32(backlinkSummaries.queriedAt)).limit(1).get();
59869
60019
  }
59870
60020
  function parseExcludeCrawlers(value) {
59871
60021
  if (!value) return false;
@@ -59887,7 +60037,7 @@ function computeFilteredSummary(db, base) {
59887
60037
  count: sql24`count(*)`,
59888
60038
  total: sql24`coalesce(sum(${backlinkDomains.numHosts}), 0)`
59889
60039
  }).from(backlinkDomains).where(filteredCondition).get();
59890
- const top10Rows = db.select({ numHosts: backlinkDomains.numHosts }).from(backlinkDomains).where(filteredCondition).orderBy(desc31(backlinkDomains.numHosts)).limit(10).all();
60040
+ const top10Rows = db.select({ numHosts: backlinkDomains.numHosts }).from(backlinkDomains).where(filteredCondition).orderBy(desc32(backlinkDomains.numHosts)).limit(10).all();
59891
60041
  const totalLinkingDomains = Number(filteredAgg?.count ?? 0);
59892
60042
  const totalHosts = Number(filteredAgg?.total ?? 0);
59893
60043
  const unfilteredLinkingDomains = Number(unfilteredAgg?.count ?? 0);
@@ -59908,7 +60058,7 @@ function computeFilteredSummary(db, base) {
59908
60058
  };
59909
60059
  }
59910
60060
  function buildSourceAvailability(db, projectId, source, connected, excludeCrawlers) {
59911
- const summary3 = db.select().from(backlinkSummaries).where(and53(eq61(backlinkSummaries.projectId, projectId), eq61(backlinkSummaries.source, source))).orderBy(desc31(backlinkSummaries.queriedAt)).limit(1).get();
60061
+ const summary3 = db.select().from(backlinkSummaries).where(and53(eq61(backlinkSummaries.projectId, projectId), eq61(backlinkSummaries.source, source))).orderBy(desc32(backlinkSummaries.queriedAt)).limit(1).get();
59912
60062
  let totalLinkingDomains = summary3?.totalLinkingDomains ?? 0;
59913
60063
  if (summary3 && excludeCrawlers) {
59914
60064
  const filtered = db.select({ count: sql24`count(*)` }).from(backlinkDomains).where(and53(
@@ -60013,11 +60163,11 @@ async function backlinksRoutes(app, opts) {
60013
60163
  return reply.status(201).send(mapSyncRow(inserted));
60014
60164
  });
60015
60165
  app.get("/backlinks/syncs/latest", async (_request, reply) => {
60016
- const row = app.db.select().from(ccReleaseSyncs).orderBy(desc31(ccReleaseSyncs.updatedAt)).limit(1).get();
60166
+ const row = app.db.select().from(ccReleaseSyncs).orderBy(desc32(ccReleaseSyncs.updatedAt)).limit(1).get();
60017
60167
  return reply.send(row ? mapSyncRow(row) : null);
60018
60168
  });
60019
60169
  app.get("/backlinks/syncs", async (_request, reply) => {
60020
- const rows = app.db.select().from(ccReleaseSyncs).orderBy(desc31(ccReleaseSyncs.updatedAt)).all();
60170
+ const rows = app.db.select().from(ccReleaseSyncs).orderBy(desc32(ccReleaseSyncs.updatedAt)).all();
60021
60171
  return reply.send(rows.map(mapSyncRow));
60022
60172
  });
60023
60173
  app.get("/backlinks/releases", async (_request, reply) => {
@@ -60104,7 +60254,7 @@ async function backlinksRoutes(app, opts) {
60104
60254
  linkingDomain: backlinkDomains.linkingDomain,
60105
60255
  numHosts: backlinkDomains.numHosts,
60106
60256
  source: backlinkDomains.source
60107
- }).from(backlinkDomains).where(domainCondition).orderBy(desc31(backlinkDomains.numHosts)).limit(limit).offset(offset).all();
60257
+ }).from(backlinkDomains).where(domainCondition).orderBy(desc32(backlinkDomains.numHosts)).limit(limit).offset(offset).all();
60108
60258
  let summary3 = null;
60109
60259
  if (summaryRow) {
60110
60260
  summary3 = excludeCrawlers ? computeFilteredSummary(app.db, summaryRow) : mapSummaryRow(summaryRow);
@@ -60150,7 +60300,7 @@ import crypto45 from "crypto";
60150
60300
  import { isIP } from "net";
60151
60301
  import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
60152
60302
  import { Agent as UndiciAgent } from "undici";
60153
- import { and as and57, desc as desc32, eq as eq65, gte as gte16, inArray as inArray26, lte as lte17, sql as sql27 } from "drizzle-orm";
60303
+ import { and as and57, desc as desc33, eq as eq65, gte as gte16, inArray as inArray27, lte as lte17, sql as sql27 } from "drizzle-orm";
60154
60304
 
60155
60305
  // ../api-routes/src/cloudflare-worker-version.ts
60156
60306
  var CURRENT_CLOUDFLARE_WORKER_VERSION = "1.0.1";
@@ -79892,7 +80042,7 @@ async function trafficRoutes(app, opts) {
79892
80042
  eq65(runs.kind, RunKinds["traffic-sync"]),
79893
80043
  eq65(runs.sourceId, row.id)
79894
80044
  )
79895
- ).orderBy(desc32(runs.startedAt)).limit(1).get();
80045
+ ).orderBy(desc33(runs.startedAt)).limit(1).get();
79896
80046
  return {
79897
80047
  ...rowToDto(row),
79898
80048
  totals24h: {
@@ -79971,14 +80121,14 @@ async function trafficRoutes(app, opts) {
79971
80121
  });
79972
80122
  app.get("/projects/:name/traffic/sources", async (request) => {
79973
80123
  const project = resolveProject(app.db, request.params.name);
79974
- const rows = app.db.select().from(trafficSources).where(eq65(trafficSources.projectId, project.id)).orderBy(desc32(trafficSources.createdAt)).all();
80124
+ const rows = app.db.select().from(trafficSources).where(eq65(trafficSources.projectId, project.id)).orderBy(desc33(trafficSources.createdAt)).all();
79975
80125
  const sources = rows.filter((row) => row.status !== TrafficSourceStatuses.archived).map(rowToDto);
79976
80126
  const response = { sources };
79977
80127
  return response;
79978
80128
  });
79979
80129
  app.get("/projects/:name/traffic/status", async (request) => {
79980
80130
  const project = resolveProject(app.db, request.params.name);
79981
- const rows = app.db.select().from(trafficSources).where(eq65(trafficSources.projectId, project.id)).orderBy(desc32(trafficSources.createdAt)).all();
80131
+ const rows = app.db.select().from(trafficSources).where(eq65(trafficSources.projectId, project.id)).orderBy(desc33(trafficSources.createdAt)).all();
79982
80132
  const since = new Date(Date.now() - 24 * 60 * 6e4).toISOString();
79983
80133
  const sources = rows.filter((row) => row.status !== TrafficSourceStatuses.archived).map((row) => buildSourceDetail(project.id, row, since));
79984
80134
  const response = { sources };
@@ -80089,7 +80239,7 @@ async function trafficRoutes(app, opts) {
80089
80239
  const listed = useContentList ? contentPaths : infraPaths;
80090
80240
  const IN_LIST_CAP = 2e4;
80091
80241
  const listFitsInSql = listed.length <= IN_LIST_CAP;
80092
- const contentExpr = listed.length === 0 ? useContentList ? sql27`0` : sql27`${crawlerEventsHourly.hits}` : useContentList ? sql27`CASE WHEN ${inArray26(crawlerEventsHourly.pathNormalized, listed)} THEN ${crawlerEventsHourly.hits} ELSE 0 END` : sql27`CASE WHEN ${inArray26(crawlerEventsHourly.pathNormalized, listed)} THEN 0 ELSE ${crawlerEventsHourly.hits} END`;
80242
+ const contentExpr = listed.length === 0 ? useContentList ? sql27`0` : sql27`${crawlerEventsHourly.hits}` : useContentList ? sql27`CASE WHEN ${inArray27(crawlerEventsHourly.pathNormalized, listed)} THEN ${crawlerEventsHourly.hits} ELSE 0 END` : sql27`CASE WHEN ${inArray27(crawlerEventsHourly.pathNormalized, listed)} THEN 0 ELSE ${crawlerEventsHourly.hits} END`;
80093
80243
  if (listFitsInSql) {
80094
80244
  const crawlerSeries = app.db.select({
80095
80245
  bucket: crawlerSeriesBucket,
@@ -80116,7 +80266,7 @@ async function trafficRoutes(app, opts) {
80116
80266
  if (useContentList ? inList : !inList) point.crawlerContentHits += hits;
80117
80267
  }
80118
80268
  }
80119
- const rows = app.db.select().from(crawlerEventsHourly).where(crawlerWhere).orderBy(desc32(crawlerEventsHourly.tsHour)).limit(limit).all();
80269
+ const rows = app.db.select().from(crawlerEventsHourly).where(crawlerWhere).orderBy(desc33(crawlerEventsHourly.tsHour)).limit(limit).all();
80120
80270
  for (const r of rows) {
80121
80271
  events.push({
80122
80272
  kind: TrafficEventKinds.crawler,
@@ -80156,7 +80306,7 @@ async function trafficRoutes(app, opts) {
80156
80306
  for (const row of userFetchSeries) {
80157
80307
  trafficSeriesPoint(seriesByBucket, row.bucket).aiUserFetchHits = Number(row.hits);
80158
80308
  }
80159
- const rows = app.db.select().from(aiUserFetchEventsHourly).where(userFetchWhere).orderBy(desc32(aiUserFetchEventsHourly.tsHour)).limit(limit).all();
80309
+ const rows = app.db.select().from(aiUserFetchEventsHourly).where(userFetchWhere).orderBy(desc33(aiUserFetchEventsHourly.tsHour)).limit(limit).all();
80160
80310
  for (const r of rows) {
80161
80311
  events.push({
80162
80312
  kind: TrafficEventKinds["ai-user-fetch"],
@@ -80209,7 +80359,7 @@ async function trafficRoutes(app, opts) {
80209
80359
  point.aiReferralHits = Number(row.hits);
80210
80360
  point.aiReferralLandedHits = Number(row.landed);
80211
80361
  }
80212
- const rows = app.db.select().from(aiReferralEventsHourly).where(aiWhere).orderBy(desc32(aiReferralEventsHourly.tsHour)).limit(limit).all();
80362
+ const rows = app.db.select().from(aiReferralEventsHourly).where(aiWhere).orderBy(desc33(aiReferralEventsHourly.tsHour)).limit(limit).all();
80213
80363
  for (const r of rows) {
80214
80364
  const counts2 = aiReferralClassCounts(r.sessionsOrHits, r.paidSessionsOrHits, r.organicSessionsOrHits);
80215
80365
  events.push({
@@ -80478,7 +80628,7 @@ var reportSweepsCheck = {
80478
80628
  };
80479
80629
 
80480
80630
  // ../api-routes/src/doctor/checks/report-models.ts
80481
- import { and as and59, eq as eq67, gte as gte18, inArray as inArray27, lte as lte19 } from "drizzle-orm";
80631
+ import { and as and59, eq as eq67, gte as gte18, inArray as inArray28, lte as lte19 } from "drizzle-orm";
80482
80632
  var reportModelsCheck = {
80483
80633
  id: "report.models",
80484
80634
  category: CheckCategories.providers,
@@ -80493,7 +80643,7 @@ var reportModelsCheck = {
80493
80643
  const months = reportMonths.flatMap((month) => {
80494
80644
  const bounds = calendarMonthBounds(month);
80495
80645
  const previous = new Date(Date.parse(bounds.since) - 1).toISOString().slice(0, 7);
80496
- const observations = ctx.db.select({ provider: querySnapshots.provider, model: querySnapshots.model, at: runs.createdAt }).from(querySnapshots).innerJoin(runs, eq67(runs.id, querySnapshots.runId)).where(and59(eq67(runs.projectId, ctx.project.id), eq67(runs.kind, RunKinds["answer-visibility"]), inArray27(runs.status, [RunStatuses.completed, RunStatuses.partial]), notProbeRun(), gte18(runs.createdAt, bounds.since), lte19(runs.createdAt, bounds.until))).all();
80646
+ const observations = ctx.db.select({ provider: querySnapshots.provider, model: querySnapshots.model, at: runs.createdAt }).from(querySnapshots).innerJoin(runs, eq67(runs.id, querySnapshots.runId)).where(and59(eq67(runs.projectId, ctx.project.id), eq67(runs.kind, RunKinds["answer-visibility"]), inArray28(runs.status, [RunStatuses.completed, RunStatuses.partial]), notProbeRun(), gte18(runs.createdAt, bounds.since), lte19(runs.createdAt, bounds.until))).all();
80497
80647
  return readVisibilityContinuity(ctx.db, ctx.project.name, { from: previous, to: month }).map(({ frame, continuity: continuity2 }) => ({
80498
80648
  month,
80499
80649
  previousMonth: previous,
@@ -81570,7 +81720,7 @@ var ga4ConnectionCheck = {
81570
81720
  var GA_AUTH_CHECKS = [ga4ConnectionCheck];
81571
81721
 
81572
81722
  // ../api-routes/src/doctor/checks/data-freshness.ts
81573
- import { and as and62, desc as desc33, eq as eq73, inArray as inArray28 } from "drizzle-orm";
81723
+ import { and as and62, desc as desc34, eq as eq73, inArray as inArray29 } from "drizzle-orm";
81574
81724
  var GA_DATA_AGING_DAYS = 3;
81575
81725
  var GA_DATA_STALE_DAYS = 5;
81576
81726
  var GSC_DATA_AGING_DAYS = 5;
@@ -81598,7 +81748,7 @@ function skipped(code, summary3) {
81598
81748
  return { status: CheckStatuses.skipped, code, summary: summary3, remediation: null };
81599
81749
  }
81600
81750
  function lastSyncAgeDays(ctx, kinds) {
81601
- const row = ctx.db.select({ createdAt: runs.createdAt }).from(runs).where(and62(eq73(runs.projectId, ctx.project.id), inArray28(runs.kind, kinds), eq73(runs.status, "completed"))).orderBy(desc33(runs.createdAt)).limit(1).get();
81751
+ const row = ctx.db.select({ createdAt: runs.createdAt }).from(runs).where(and62(eq73(runs.projectId, ctx.project.id), inArray29(runs.kind, kinds), eq73(runs.status, "completed"))).orderBy(desc34(runs.createdAt)).limit(1).get();
81602
81752
  if (!row?.createdAt) return null;
81603
81753
  const age = Math.floor((Date.now() - Date.parse(row.createdAt)) / DAY_MS2);
81604
81754
  return Number.isFinite(age) ? age : null;
@@ -81694,7 +81844,7 @@ var gaRecentDataCheck = {
81694
81844
  const connection = gaConnected(ctx);
81695
81845
  if (connection === "store-unavailable") return skipped("ga.data.store-unavailable", "No GA4 credential store configured for this deployment.");
81696
81846
  if (connection === "not-connected") return skipped("ga.data.not-connected", "GA4 is not connected for this project.");
81697
- const newest = ctx.db.select({ date: gaDailyTotals.date }).from(gaDailyTotals).where(eq73(gaDailyTotals.projectId, ctx.project.id)).orderBy(desc33(gaDailyTotals.date)).limit(1).get();
81847
+ const newest = ctx.db.select({ date: gaDailyTotals.date }).from(gaDailyTotals).where(eq73(gaDailyTotals.projectId, ctx.project.id)).orderBy(desc34(gaDailyTotals.date)).limit(1).get();
81698
81848
  return grade(ctx, GA_SPEC, newest?.date);
81699
81849
  }
81700
81850
  };
@@ -81711,7 +81861,7 @@ var gscRecentDataCheck = {
81711
81861
  }
81712
81862
  const watermark = ctx.db.select({ dataThroughDate: gscDataWatermarks.dataThroughDate }).from(gscDataWatermarks).where(eq73(gscDataWatermarks.projectId, ctx.project.id)).get();
81713
81863
  if (watermark?.dataThroughDate) return grade(ctx, GSC_SPEC, watermark.dataThroughDate);
81714
- const newest = ctx.db.select({ date: gscDailyTotals.date }).from(gscDailyTotals).where(eq73(gscDailyTotals.projectId, ctx.project.id)).orderBy(desc33(gscDailyTotals.date)).limit(1).get();
81864
+ const newest = ctx.db.select({ date: gscDailyTotals.date }).from(gscDailyTotals).where(eq73(gscDailyTotals.projectId, ctx.project.id)).orderBy(desc34(gscDailyTotals.date)).limit(1).get();
81715
81865
  return grade(ctx, GSC_SPEC, newest?.date);
81716
81866
  }
81717
81867
  };
@@ -82967,7 +83117,7 @@ var RUNTIME_STATE_CHECKS = [
82967
83117
  ];
82968
83118
 
82969
83119
  // ../api-routes/src/doctor/checks/traffic-source.ts
82970
- import { and as and65, eq as eq77, gte as gte19, inArray as inArray29, ne as ne14, sql as sql28 } from "drizzle-orm";
83120
+ import { and as and65, eq as eq77, gte as gte19, inArray as inArray30, ne as ne14, sql as sql28 } from "drizzle-orm";
82971
83121
  var RECENT_DATA_WARN_DAYS = 7;
82972
83122
  var RECENT_DATA_FAIL_DAYS = 30;
82973
83123
  function isCloudflareDirectPush(source) {
@@ -83115,7 +83265,7 @@ var recentDataCheck = {
83115
83265
  ctx.db.select({ total: sql28`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
83116
83266
  and65(
83117
83267
  eq77(crawlerEventsHourly.projectId, ctx.project.id),
83118
- inArray29(crawlerEventsHourly.sourceId, activeSourceIds),
83268
+ inArray30(crawlerEventsHourly.sourceId, activeSourceIds),
83119
83269
  gte19(crawlerEventsHourly.tsHour, warnCutoff)
83120
83270
  )
83121
83271
  ).get()?.total ?? 0
@@ -83124,7 +83274,7 @@ var recentDataCheck = {
83124
83274
  ctx.db.select({ total: sql28`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
83125
83275
  and65(
83126
83276
  eq77(aiReferralEventsHourly.projectId, ctx.project.id),
83127
- inArray29(aiReferralEventsHourly.sourceId, activeSourceIds),
83277
+ inArray30(aiReferralEventsHourly.sourceId, activeSourceIds),
83128
83278
  gte19(aiReferralEventsHourly.tsHour, warnCutoff)
83129
83279
  )
83130
83280
  ).get()?.total ?? 0
@@ -83133,7 +83283,7 @@ var recentDataCheck = {
83133
83283
  ctx.db.select({ total: sql28`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
83134
83284
  and65(
83135
83285
  eq77(aiUserFetchEventsHourly.projectId, ctx.project.id),
83136
- inArray29(aiUserFetchEventsHourly.sourceId, activeSourceIds),
83286
+ inArray30(aiUserFetchEventsHourly.sourceId, activeSourceIds),
83137
83287
  gte19(aiUserFetchEventsHourly.tsHour, warnCutoff)
83138
83288
  )
83139
83289
  ).get()?.total ?? 0
@@ -83159,7 +83309,7 @@ var recentDataCheck = {
83159
83309
  ctx.db.select({ total: sql28`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
83160
83310
  and65(
83161
83311
  eq77(crawlerEventsHourly.projectId, ctx.project.id),
83162
- inArray29(crawlerEventsHourly.sourceId, activeSourceIds),
83312
+ inArray30(crawlerEventsHourly.sourceId, activeSourceIds),
83163
83313
  gte19(crawlerEventsHourly.tsHour, failCutoff)
83164
83314
  )
83165
83315
  ).get()?.total ?? 0
@@ -83168,7 +83318,7 @@ var recentDataCheck = {
83168
83318
  ctx.db.select({ total: sql28`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
83169
83319
  and65(
83170
83320
  eq77(aiReferralEventsHourly.projectId, ctx.project.id),
83171
- inArray29(aiReferralEventsHourly.sourceId, activeSourceIds),
83321
+ inArray30(aiReferralEventsHourly.sourceId, activeSourceIds),
83172
83322
  gte19(aiReferralEventsHourly.tsHour, failCutoff)
83173
83323
  )
83174
83324
  ).get()?.total ?? 0
@@ -83177,7 +83327,7 @@ var recentDataCheck = {
83177
83327
  ctx.db.select({ total: sql28`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
83178
83328
  and65(
83179
83329
  eq77(aiUserFetchEventsHourly.projectId, ctx.project.id),
83180
- inArray29(aiUserFetchEventsHourly.sourceId, activeSourceIds),
83330
+ inArray30(aiUserFetchEventsHourly.sourceId, activeSourceIds),
83181
83331
  gte19(aiUserFetchEventsHourly.tsHour, failCutoff)
83182
83332
  )
83183
83333
  ).get()?.total ?? 0
@@ -84184,7 +84334,7 @@ async function doctorRoutes(app, opts) {
84184
84334
 
84185
84335
  // ../api-routes/src/discovery/routes.ts
84186
84336
  import crypto47 from "crypto";
84187
- import { and as and66, desc as desc34, eq as eq78, gte as gte20, inArray as inArray30, isNull as isNull14, or as or17 } from "drizzle-orm";
84337
+ import { and as and66, desc as desc35, eq as eq78, gte as gte20, inArray as inArray31, isNull as isNull14, or as or17 } from "drizzle-orm";
84188
84338
  var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
84189
84339
  async function discoveryRoutes(app, opts) {
84190
84340
  app.post("/projects/:name/discover/run", async (request, reply) => {
@@ -84239,13 +84389,13 @@ async function discoveryRoutes(app, opts) {
84239
84389
  // must never reuse another set's session. Null (= Gemini-only
84240
84390
  // default, including explicit ['gemini']) matches legacy rows.
84241
84391
  seedProviders == null ? isNull14(discoverySessions.seedProviders) : eq78(discoverySessions.seedProviders, seedProviders),
84242
- inArray30(discoverySessions.status, [
84392
+ inArray31(discoverySessions.status, [
84243
84393
  DiscoverySessionStatuses.queued,
84244
84394
  DiscoverySessionStatuses.seeding,
84245
84395
  DiscoverySessionStatuses.probing
84246
84396
  ]),
84247
84397
  gte20(discoverySessions.createdAt, ageFloorIso)
84248
- )).orderBy(desc34(discoverySessions.createdAt)).get();
84398
+ )).orderBy(desc35(discoverySessions.createdAt)).get();
84249
84399
  if (existing && existing.runId) {
84250
84400
  return { reused: true, sessionId: existing.id, runId: existing.runId };
84251
84401
  }
@@ -84314,7 +84464,7 @@ async function discoveryRoutes(app, opts) {
84314
84464
  const project = resolveProject(app.db, request.params.name);
84315
84465
  const parsedLimit = parseInt(request.query.limit ?? "", 10);
84316
84466
  const limit = Number.isNaN(parsedLimit) || parsedLimit <= 0 ? 50 : parsedLimit;
84317
- const rows = app.db.select().from(discoverySessions).where(eq78(discoverySessions.projectId, project.id)).orderBy(desc34(discoverySessions.createdAt)).limit(limit).all();
84467
+ const rows = app.db.select().from(discoverySessions).where(eq78(discoverySessions.projectId, project.id)).orderBy(desc35(discoverySessions.createdAt)).limit(limit).all();
84318
84468
  return reply.send(rows.map(serializeSession));
84319
84469
  }
84320
84470
  );
@@ -84938,7 +85088,7 @@ function dedupeStrings(input) {
84938
85088
 
84939
85089
  // ../api-routes/src/technical-aeo.ts
84940
85090
  import crypto49 from "crypto";
84941
- import { and as and67, asc as asc14, count as count2, desc as desc35, eq as eq80, inArray as inArray31, isNotNull as isNotNull8, isNull as isNull15, lt as lt13, or as or18, sql as sql29 } from "drizzle-orm";
85091
+ import { and as and67, asc as asc14, count as count2, desc as desc36, eq as eq80, inArray as inArray32, isNotNull as isNotNull8, isNull as isNull15, lt as lt13, or as or18, sql as sql29 } from "drizzle-orm";
84942
85092
  import { alias } from "drizzle-orm/sqlite-core";
84943
85093
  var FETCHED_SITE_CRAWL_STATES = /* @__PURE__ */ new Set([
84944
85094
  ...SiteCrawlFetchedStates,
@@ -85263,11 +85413,11 @@ async function technicalAeoRoutes(app, opts) {
85263
85413
  eq80(siteCrawlSnapshots.projectId, projectId),
85264
85414
  eq80(runs.projectId, projectId),
85265
85415
  eq80(runs.kind, RunKinds["site-audit"]),
85266
- inArray31(runs.status, SURFACEABLE_STATUSES),
85416
+ inArray32(runs.status, SURFACEABLE_STATUSES),
85267
85417
  notProbeRun()
85268
85418
  ];
85269
85419
  if (runId) filters.push(eq80(siteCrawlSnapshots.runId, runId));
85270
- return app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq80(siteCrawlSnapshots.runId, runs.id)).where(and67(...filters)).orderBy(desc35(siteCrawlSnapshots.createdAt), desc35(siteCrawlSnapshots.runId)).limit(1).get();
85420
+ return app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq80(siteCrawlSnapshots.runId, runs.id)).where(and67(...filters)).orderBy(desc36(siteCrawlSnapshots.createdAt), desc36(siteCrawlSnapshots.runId)).limit(1).get();
85271
85421
  };
85272
85422
  const detailScopeFor = (projectId, snapshot) => snapshot.detailsAvailable && snapshot.attemptId ? { projectId, runId: snapshot.runId, attemptId: snapshot.attemptId } : null;
85273
85423
  const completenessOf = (snapshot) => ({
@@ -85294,7 +85444,7 @@ async function technicalAeoRoutes(app, opts) {
85294
85444
  eq80(runs.id, runId),
85295
85445
  eq80(runs.projectId, projectId),
85296
85446
  eq80(runs.kind, RunKinds["site-audit"]),
85297
- inArray31(runs.status, SURFACEABLE_STATUSES),
85447
+ inArray32(runs.status, SURFACEABLE_STATUSES),
85298
85448
  notProbeRun()
85299
85449
  )).limit(1).get());
85300
85450
  const assertKnownAuditRun = (projectId, runId) => {
@@ -85304,7 +85454,7 @@ async function technicalAeoRoutes(app, opts) {
85304
85454
  eq80(siteAuditSnapshots.projectId, projectId),
85305
85455
  eq80(runs.projectId, projectId),
85306
85456
  eq80(runs.kind, RunKinds["site-audit"]),
85307
- inArray31(runs.status, SURFACEABLE_STATUSES),
85457
+ inArray32(runs.status, SURFACEABLE_STATUSES),
85308
85458
  notProbeRun()
85309
85459
  )).limit(1).get());
85310
85460
  const emptyCrawlSummary = (projectName, legacyAuditAvailable) => ({
@@ -85328,17 +85478,17 @@ async function technicalAeoRoutes(app, opts) {
85328
85478
  eq80(siteAuditSnapshots.projectId, project.id),
85329
85479
  eq80(runs.projectId, project.id),
85330
85480
  eq80(runs.kind, RunKinds["site-audit"]),
85331
- inArray31(runs.status, SURFACEABLE_STATUSES),
85481
+ inArray32(runs.status, SURFACEABLE_STATUSES),
85332
85482
  notProbeRun()
85333
85483
  ];
85334
85484
  const targetFilters = request.query.runId ? [...baseFilters, eq80(siteAuditSnapshots.runId, request.query.runId)] : baseFilters;
85335
- const latest = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq80(siteAuditSnapshots.runId, runs.id)).where(and67(...targetFilters)).orderBy(desc35(siteAuditSnapshots.createdAt)).limit(1).get();
85485
+ const latest = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq80(siteAuditSnapshots.runId, runs.id)).where(and67(...targetFilters)).orderBy(desc36(siteAuditSnapshots.createdAt)).limit(1).get();
85336
85486
  if (!latest) {
85337
85487
  if (request.query.runId) throw notFound("Site audit run", request.query.runId);
85338
85488
  return emptyScore(project.name);
85339
85489
  }
85340
85490
  const snap = latest.snap;
85341
- const previous = app.db.select({ snap: siteAuditSnapshots }).from(siteAuditSnapshots).innerJoin(runs, eq80(siteAuditSnapshots.runId, runs.id)).where(and67(...baseFilters, lt13(siteAuditSnapshots.createdAt, snap.createdAt))).orderBy(desc35(siteAuditSnapshots.createdAt)).limit(1).get()?.snap ?? null;
85491
+ const previous = app.db.select({ snap: siteAuditSnapshots }).from(siteAuditSnapshots).innerJoin(runs, eq80(siteAuditSnapshots.runId, runs.id)).where(and67(...baseFilters, lt13(siteAuditSnapshots.createdAt, snap.createdAt))).orderBy(desc36(siteAuditSnapshots.createdAt)).limit(1).get()?.snap ?? null;
85342
85492
  const deltaScore = previous ? snap.aggregateScore - previous.aggregateScore : null;
85343
85493
  const trend = deltaScore == null ? null : deltaScore > 0 ? SiteAuditTrendDirections.up : deltaScore < 0 ? SiteAuditTrendDirections.down : SiteAuditTrendDirections.flat;
85344
85494
  return {
@@ -85368,11 +85518,11 @@ async function technicalAeoRoutes(app, opts) {
85368
85518
  eq80(siteAuditSnapshots.projectId, project.id),
85369
85519
  eq80(runs.projectId, project.id),
85370
85520
  eq80(runs.kind, RunKinds["site-audit"]),
85371
- inArray31(runs.status, SURFACEABLE_STATUSES),
85521
+ inArray32(runs.status, SURFACEABLE_STATUSES),
85372
85522
  notProbeRun()
85373
85523
  ];
85374
85524
  if (request.query.runId) targetFilters.push(eq80(siteAuditSnapshots.runId, request.query.runId));
85375
- const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq80(siteAuditSnapshots.runId, runs.id)).where(and67(...targetFilters)).orderBy(desc35(siteAuditSnapshots.createdAt)).limit(1).get();
85525
+ const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq80(siteAuditSnapshots.runId, runs.id)).where(and67(...targetFilters)).orderBy(desc36(siteAuditSnapshots.createdAt)).limit(1).get();
85376
85526
  if (!latest && request.query.runId) {
85377
85527
  throw notFound("Site audit run", request.query.runId);
85378
85528
  }
@@ -85387,7 +85537,7 @@ async function technicalAeoRoutes(app, opts) {
85387
85537
  const total = totalRow?.value ?? 0;
85388
85538
  const limit = parsePositiveInt(request.query.limit, 100, 500);
85389
85539
  const offset = parsePositiveInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER);
85390
- const orderBy = request.query.sort === "score-desc" ? desc35(siteAuditPages.overallScore) : request.query.sort === "url" ? asc14(siteAuditPages.url) : asc14(siteAuditPages.overallScore);
85540
+ const orderBy = request.query.sort === "score-desc" ? desc36(siteAuditPages.overallScore) : request.query.sort === "url" ? asc14(siteAuditPages.url) : asc14(siteAuditPages.overallScore);
85391
85541
  const rows = app.db.select().from(siteAuditPages).where(where).orderBy(orderBy).limit(limit).offset(offset).all();
85392
85542
  const pages = rows.map((row) => ({
85393
85543
  url: row.url,
@@ -85410,9 +85560,9 @@ async function technicalAeoRoutes(app, opts) {
85410
85560
  eq80(siteAuditSnapshots.projectId, project.id),
85411
85561
  eq80(runs.projectId, project.id),
85412
85562
  eq80(runs.kind, RunKinds["site-audit"]),
85413
- inArray31(runs.status, SURFACEABLE_STATUSES),
85563
+ inArray32(runs.status, SURFACEABLE_STATUSES),
85414
85564
  notProbeRun()
85415
- )).orderBy(desc35(siteAuditSnapshots.createdAt)).limit(limit).all();
85565
+ )).orderBy(desc36(siteAuditSnapshots.createdAt)).limit(limit).all();
85416
85566
  return { project: project.name, points: rows.reverse() };
85417
85567
  });
85418
85568
  app.get("/projects/:name/technical-aeo/crawl", async (request) => {
@@ -85718,8 +85868,8 @@ async function technicalAeoRoutes(app, opts) {
85718
85868
  eq80(siteCrawlEdges.internal, true),
85719
85869
  isNotNull8(siteCrawlEdges.targetNodeKey),
85720
85870
  or18(
85721
- inArray31(siteCrawlEdges.sourceNodeKey, frontier),
85722
- inArray31(siteCrawlEdges.targetNodeKey, frontier)
85871
+ inArray32(siteCrawlEdges.sourceNodeKey, frontier),
85872
+ inArray32(siteCrawlEdges.targetNodeKey, frontier)
85723
85873
  )
85724
85874
  )).orderBy(asc14(siteCrawlEdges.edgeKey)).limit(maxEdges + maxNodes + 1).all();
85725
85875
  if (candidates.length > maxEdges + maxNodes) queryTruncated = true;
@@ -85756,7 +85906,7 @@ async function technicalAeoRoutes(app, opts) {
85756
85906
  eq80(siteCrawlPages.projectId, scope.projectId),
85757
85907
  eq80(siteCrawlPages.runId, scope.runId),
85758
85908
  eq80(siteCrawlPages.attemptId, scope.attemptId),
85759
- inArray31(siteCrawlPages.nodeKey, nodeKeys)
85909
+ inArray32(siteCrawlPages.nodeKey, nodeKeys)
85760
85910
  )).all();
85761
85911
  const persistedNodeKeys = new Set(pageRows.map((row) => row.nodeKey));
85762
85912
  const outermostNodeKeys = pageRows.filter((row) => distances.get(row.nodeKey) === hops).map((row) => row.nodeKey);
@@ -85766,8 +85916,8 @@ async function technicalAeoRoutes(app, opts) {
85766
85916
  eq80(siteCrawlEdges.attemptId, scope.attemptId),
85767
85917
  eq80(siteCrawlEdges.internal, true),
85768
85918
  isNotNull8(siteCrawlEdges.targetNodeKey),
85769
- inArray31(siteCrawlEdges.sourceNodeKey, outermostNodeKeys),
85770
- inArray31(siteCrawlEdges.targetNodeKey, outermostNodeKeys)
85919
+ inArray32(siteCrawlEdges.sourceNodeKey, outermostNodeKeys),
85920
+ inArray32(siteCrawlEdges.targetNodeKey, outermostNodeKeys)
85771
85921
  )).limit(1).get();
85772
85922
  if (omittedOutermostEdge && !seenEdgeKeys.has(omittedOutermostEdge.edgeKey)) {
85773
85923
  omittedEdgeKeys.add(omittedOutermostEdge.edgeKey);
@@ -85870,7 +86020,7 @@ async function technicalAeoRoutes(app, opts) {
85870
86020
  eq80(siteCrawlEdges.followable, true),
85871
86021
  eq80(siteCrawlEdges.relation, "anchor"),
85872
86022
  isNotNull8(siteCrawlEdges.targetNodeKey),
85873
- inArray31(siteCrawlEdges.sourceNodeKey, frontier)
86023
+ inArray32(siteCrawlEdges.sourceNodeKey, frontier)
85874
86024
  )).orderBy(asc14(siteCrawlEdges.edgeKey)).limit(SITE_HEALTH_PATH_MAX_VISITED_NODES + 1).all();
85875
86025
  if (candidates.length > SITE_HEALTH_PATH_MAX_VISITED_NODES) truncated = true;
85876
86026
  const candidateTargetKeys = [...new Set(candidates.map((edge) => edge.targetNodeKey).filter((nodeKey) => nodeKey != null))];
@@ -85878,7 +86028,7 @@ async function technicalAeoRoutes(app, opts) {
85878
86028
  eq80(siteCrawlPages.projectId, scope.projectId),
85879
86029
  eq80(siteCrawlPages.runId, scope.runId),
85880
86030
  eq80(siteCrawlPages.attemptId, scope.attemptId),
85881
- inArray31(siteCrawlPages.nodeKey, candidateTargetKeys)
86031
+ inArray32(siteCrawlPages.nodeKey, candidateTargetKeys)
85882
86032
  )).all().map((row) => row.nodeKey));
85883
86033
  const next = /* @__PURE__ */ new Set();
85884
86034
  for (const edge of candidates.slice(0, SITE_HEALTH_PATH_MAX_VISITED_NODES)) {
@@ -85924,7 +86074,7 @@ async function technicalAeoRoutes(app, opts) {
85924
86074
  eq80(siteCrawlPages.projectId, scope.projectId),
85925
86075
  eq80(siteCrawlPages.runId, scope.runId),
85926
86076
  eq80(siteCrawlPages.attemptId, scope.attemptId),
85927
- inArray31(siteCrawlPages.nodeKey, pathKeys)
86077
+ inArray32(siteCrawlPages.nodeKey, pathKeys)
85928
86078
  )).all();
85929
86079
  const pageByKey = new Map(pathRows.map((row) => [row.nodeKey, row]));
85930
86080
  const pathDetection = templateDetectionOf(snapshot.templateDetection);
@@ -85960,7 +86110,7 @@ async function technicalAeoRoutes(app, opts) {
85960
86110
  eq80(siteCrawlSnapshots.complete, true),
85961
86111
  notProbeRun()
85962
86112
  ];
85963
- const afterTarget = request.query.toRunId ? resolveCrawl(project.id, request.query.toRunId) : app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq80(siteCrawlSnapshots.runId, runs.id)).where(and67(...completeSnapshotFilters)).orderBy(desc35(siteCrawlSnapshots.createdAt), desc35(siteCrawlSnapshots.runId)).limit(1).get();
86113
+ const afterTarget = request.query.toRunId ? resolveCrawl(project.id, request.query.toRunId) : app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq80(siteCrawlSnapshots.runId, runs.id)).where(and67(...completeSnapshotFilters)).orderBy(desc36(siteCrawlSnapshots.createdAt), desc36(siteCrawlSnapshots.runId)).limit(1).get();
85964
86114
  if (request.query.toRunId && !afterTarget) throw notFound("Site crawl run", request.query.toRunId);
85965
86115
  const beforeTarget = request.query.fromRunId ? resolveCrawl(project.id, request.query.fromRunId) : afterTarget ? app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq80(siteCrawlSnapshots.runId, runs.id)).where(and67(
85966
86116
  ...completeSnapshotFilters,
@@ -85971,7 +86121,7 @@ async function technicalAeoRoutes(app, opts) {
85971
86121
  lt13(siteCrawlSnapshots.runId, afterTarget.snapshot.runId)
85972
86122
  )
85973
86123
  )
85974
- )).orderBy(desc35(siteCrawlSnapshots.createdAt), desc35(siteCrawlSnapshots.runId)).limit(1).get() : void 0;
86124
+ )).orderBy(desc36(siteCrawlSnapshots.createdAt), desc36(siteCrawlSnapshots.runId)).limit(1).get() : void 0;
85975
86125
  if (request.query.fromRunId && !beforeTarget) throw notFound("Site crawl run", request.query.fromRunId);
85976
86126
  if (!afterTarget) {
85977
86127
  const latestCrawl = resolveCrawl(project.id);
@@ -86216,14 +86366,14 @@ async function technicalAeoRoutes(app, opts) {
86216
86366
  eq80(siteCrawlPages.projectId, scope.projectId),
86217
86367
  eq80(siteCrawlPages.runId, scope.runId),
86218
86368
  eq80(siteCrawlPages.attemptId, scope.attemptId),
86219
- inArray31(siteCrawlPages.nodeKey, pageKeys)
86369
+ inArray32(siteCrawlPages.nodeKey, pageKeys)
86220
86370
  )).all();
86221
86371
  const edgeRowsFor = (scope) => linkKeys.length === 0 ? [] : app.db.select().from(siteCrawlEdges).where(and67(
86222
86372
  eq80(siteCrawlEdges.projectId, scope.projectId),
86223
86373
  eq80(siteCrawlEdges.runId, scope.runId),
86224
86374
  eq80(siteCrawlEdges.attemptId, scope.attemptId),
86225
86375
  eq80(siteCrawlEdges.internal, true),
86226
- inArray31(siteCrawlEdges.edgeKey, linkKeys)
86376
+ inArray32(siteCrawlEdges.edgeKey, linkKeys)
86227
86377
  )).all();
86228
86378
  const beforePages = new Map(pageRowsFor(beforeScope).map((row) => [row.nodeKey, mapCrawlPage(row)]));
86229
86379
  const afterPages = new Map(pageRowsFor(afterScope).map((row) => [row.nodeKey, mapCrawlPage(row)]));
@@ -86361,7 +86511,7 @@ async function technicalAeoRoutes(app, opts) {
86361
86511
  const healthState = parseSiteHealthState(request.query.healthState);
86362
86512
  const limit = parseBoundedLimit(request.query.limit, 100, 200);
86363
86513
  const offset = decodeCursor(request.query.cursor);
86364
- const orderBy = request.query.sort === "score-desc" ? [desc35(siteCrawlPages.auditScore), asc14(siteCrawlPages.nodeKey)] : request.query.sort === "score-asc" ? [asc14(siteCrawlPages.auditScore), asc14(siteCrawlPages.nodeKey)] : request.query.sort === "path" ? [asc14(siteCrawlPages.path), asc14(siteCrawlPages.nodeKey)] : [asc14(siteCrawlPages.url), asc14(siteCrawlPages.nodeKey)];
86514
+ const orderBy = request.query.sort === "score-desc" ? [desc36(siteCrawlPages.auditScore), asc14(siteCrawlPages.nodeKey)] : request.query.sort === "score-asc" ? [asc14(siteCrawlPages.auditScore), asc14(siteCrawlPages.nodeKey)] : request.query.sort === "path" ? [asc14(siteCrawlPages.path), asc14(siteCrawlPages.nodeKey)] : [asc14(siteCrawlPages.url), asc14(siteCrawlPages.nodeKey)];
86365
86515
  let healthStateFilter = null;
86366
86516
  if (healthState) {
86367
86517
  const legacyRow = app.db.select({ id: siteCrawlPages.id }).from(siteCrawlPages).where(and67(
@@ -86674,15 +86824,15 @@ async function technicalAeoRoutes(app, opts) {
86674
86824
  eq80(runs.projectId, project.id),
86675
86825
  eq80(runs.kind, RunKinds["site-audit"]),
86676
86826
  notProbeRun()
86677
- )).orderBy(desc35(runs.createdAt), desc35(runs.id)).limit(limit).all();
86827
+ )).orderBy(desc36(runs.createdAt), desc36(runs.id)).limit(limit).all();
86678
86828
  const runIds = rows.map((row) => row.runId);
86679
86829
  const crawlRunIds = new Set(runIds.length === 0 ? [] : app.db.select({ runId: siteCrawlSnapshots.runId }).from(siteCrawlSnapshots).innerJoin(runs, eq80(siteCrawlSnapshots.runId, runs.id)).where(and67(
86680
86830
  eq80(siteCrawlSnapshots.projectId, project.id),
86681
86831
  eq80(runs.projectId, project.id),
86682
86832
  eq80(runs.kind, RunKinds["site-audit"]),
86683
- inArray31(runs.status, SURFACEABLE_STATUSES),
86833
+ inArray32(runs.status, SURFACEABLE_STATUSES),
86684
86834
  notProbeRun(),
86685
- inArray31(siteCrawlSnapshots.runId, runIds)
86835
+ inArray32(siteCrawlSnapshots.runId, runIds)
86686
86836
  )).all().map((row) => row.runId));
86687
86837
  return {
86688
86838
  project: project.name,
@@ -86705,7 +86855,7 @@ async function technicalAeoRoutes(app, opts) {
86705
86855
  const attempt = app.db.select().from(siteCrawlAttempts).where(and67(
86706
86856
  eq80(siteCrawlAttempts.projectId, project.id),
86707
86857
  eq80(siteCrawlAttempts.runId, run.id)
86708
- )).orderBy(desc35(siteCrawlAttempts.attemptNumber), desc35(siteCrawlAttempts.updatedAt)).limit(1).get();
86858
+ )).orderBy(desc36(siteCrawlAttempts.attemptNumber), desc36(siteCrawlAttempts.updatedAt)).limit(1).get();
86709
86859
  const persistedLayout = attempt ? app.db.select().from(siteCrawlGraphLayouts).where(and67(
86710
86860
  eq80(siteCrawlGraphLayouts.projectId, project.id),
86711
86861
  eq80(siteCrawlGraphLayouts.runId, run.id),
@@ -86752,7 +86902,7 @@ async function technicalAeoRoutes(app, opts) {
86752
86902
  const attempt = tx.select().from(siteCrawlAttempts).where(and67(
86753
86903
  eq80(siteCrawlAttempts.projectId, project.id),
86754
86904
  eq80(siteCrawlAttempts.runId, run.id)
86755
- )).orderBy(desc35(siteCrawlAttempts.attemptNumber), desc35(siteCrawlAttempts.updatedAt)).limit(1).get();
86905
+ )).orderBy(desc36(siteCrawlAttempts.attemptNumber), desc36(siteCrawlAttempts.updatedAt)).limit(1).get();
86756
86906
  const state = run.status === RunStatuses.queued ? "waiting" : run.status === RunStatuses.running ? "collecting" : "terminal";
86757
86907
  const base = {
86758
86908
  project: project.name,
@@ -86822,7 +86972,7 @@ async function technicalAeoRoutes(app, opts) {
86822
86972
  )).where(and67(
86823
86973
  eq80(runs.projectId, project.id),
86824
86974
  eq80(runs.kind, RunKinds["site-audit"]),
86825
- inArray31(runs.status, [RunStatuses.queued, RunStatuses.running])
86975
+ inArray32(runs.status, [RunStatuses.queued, RunStatuses.running])
86826
86976
  )).get();
86827
86977
  if (existing) {
86828
86978
  if (existing.identityKey === identityKey) {
@@ -86876,7 +87026,7 @@ async function technicalAeoRoutes(app, opts) {
86876
87026
  // ../api-routes/src/research.ts
86877
87027
  import crypto50 from "crypto";
86878
87028
  import { z as z5 } from "zod";
86879
- import { and as and68, count as count3, desc as desc36, eq as eq81, gte as gte21, lt as lt14, or as or19, sql as sql30 } from "drizzle-orm";
87029
+ import { and as and68, count as count3, desc as desc37, eq as eq81, gte as gte21, lt as lt14, or as or19, sql as sql30 } from "drizzle-orm";
86880
87030
  var sameLocation = (a, b) => a.label === b.label && a.city === b.city && a.region === b.region && a.country === b.country && a.timezone === b.timezone;
86881
87031
  var BATCH_RECEIPT_PREFIX = "__canonry_research_batch__:";
86882
87032
  async function researchRoutes(app, opts) {
@@ -87047,7 +87197,7 @@ async function researchRoutes(app, opts) {
87047
87197
  const rows = app.db.select().from(researchRuns).where(and68(
87048
87198
  eq81(researchRuns.projectId, project.id),
87049
87199
  cursor ? or19(lt14(researchRuns.createdAt, cursor.createdAt), and68(eq81(researchRuns.createdAt, cursor.createdAt), lt14(researchRuns.id, cursor.id))) : void 0
87050
- )).orderBy(desc36(researchRuns.createdAt), desc36(researchRuns.id)).limit(limit + 1).all();
87200
+ )).orderBy(desc37(researchRuns.createdAt), desc37(researchRuns.id)).limit(limit + 1).all();
87051
87201
  const runs2 = rows.slice(0, limit).map(serializeRun);
87052
87202
  const last = runs2.at(-1);
87053
87203
  const nextCursor = rows.length > limit && last ? Buffer.from(JSON.stringify({ projectId: project.id, createdAt: last.createdAt, id: last.id })).toString("base64url") : null;
@@ -87228,7 +87378,7 @@ function utcDayBounds(now) {
87228
87378
  }
87229
87379
 
87230
87380
  // ../api-routes/src/snapshot-competitor-refresh.ts
87231
- import { and as and69, eq as eq82, inArray as inArray32 } from "drizzle-orm";
87381
+ import { and as and69, eq as eq82, inArray as inArray33 } from "drizzle-orm";
87232
87382
  var SNAPSHOT_BATCH_SIZE = 500;
87233
87383
  function backfillProjectAnswerMentions(db, projectId, opts) {
87234
87384
  const isDryRun = opts?.dryRun === true;
@@ -87272,7 +87422,7 @@ function backfillProjectAnswerMentions(db, projectId, opts) {
87272
87422
  competitorOverlap: querySnapshots.competitorOverlap,
87273
87423
  recommendedCompetitors: querySnapshots.recommendedCompetitors,
87274
87424
  rawResponse: querySnapshots.rawResponse
87275
- }).from(querySnapshots).where(inArray32(querySnapshots.runId, batchRunIds)).all();
87425
+ }).from(querySnapshots).where(inArray33(querySnapshots.runId, batchRunIds)).all();
87276
87426
  const pendingUpdates = [];
87277
87427
  for (const snapshot of snapshotRows) {
87278
87428
  if (competitorFieldsOnly && snapshot.answerText == null) continue;
@@ -88328,7 +88478,7 @@ var IntelligenceService = class {
88328
88478
  this.db.select({ one: sql31`1` }).from(querySnapshots).where(eq84(querySnapshots.runId, runs.id))
88329
88479
  )
88330
88480
  )
88331
- ).orderBy(desc37(runs.finishedAt), desc37(runs.createdAt)).limit(HISTORY_WINDOW_RUNS).all();
88481
+ ).orderBy(desc38(runs.finishedAt), desc38(runs.createdAt)).limit(HISTORY_WINDOW_RUNS).all();
88332
88482
  const trackedCompetitors = this.loadTrackedCompetitors(projectId);
88333
88483
  const currentRun = this.buildRunData(
88334
88484
  runId,
@@ -88447,10 +88597,10 @@ var IntelligenceService = class {
88447
88597
  buildGbpLocationSignals(projectId, locationName, displayName, fallbackDate) {
88448
88598
  const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(and71(eq84(gbpDailyMetrics.projectId, projectId), eq84(gbpDailyMetrics.locationName, locationName))).all();
88449
88599
  const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(and71(eq84(gbpPlaceActions.projectId, projectId), eq84(gbpPlaceActions.locationName, locationName))).all();
88450
- const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and71(eq84(gbpLodgingSnapshots.projectId, projectId), eq84(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc37(gbpLodgingSnapshots.syncedAt)).limit(1).get();
88600
+ const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and71(eq84(gbpLodgingSnapshots.projectId, projectId), eq84(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc38(gbpLodgingSnapshots.syncedAt)).limit(1).get();
88451
88601
  const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(and71(eq84(gbpLocations.projectId, projectId), eq84(gbpLocations.locationName, locationName))).get();
88452
88602
  const descriptionMissing = !(ownerRow?.description ?? "").trim();
88453
- const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and71(eq84(gbpPlaceDetails.projectId, projectId), eq84(gbpPlaceDetails.locationName, locationName))).orderBy(desc37(gbpPlaceDetails.syncedAt)).limit(1).get();
88603
+ const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and71(eq84(gbpPlaceDetails.projectId, projectId), eq84(gbpPlaceDetails.locationName, locationName))).orderBy(desc38(gbpPlaceDetails.syncedAt)).limit(1).get();
88454
88604
  const placesAmenities = placeRow ? extractPlaceAmenities(placeRow.attributes) : [];
88455
88605
  const summary3 = buildGbpSummary({
88456
88606
  locationName,
@@ -88657,7 +88807,7 @@ var IntelligenceService = class {
88657
88807
  let wouldDeleteTotal = 0;
88658
88808
  const existingByRunId = /* @__PURE__ */ new Map();
88659
88809
  if (isDryRun && targetRuns.length > 0) {
88660
- const rows = this.db.select({ runId: insights.runId }).from(insights).where(inArray33(insights.runId, targetRuns.map((r) => r.id))).all();
88810
+ const rows = this.db.select({ runId: insights.runId }).from(insights).where(inArray34(insights.runId, targetRuns.map((r) => r.id))).all();
88661
88811
  for (const r of rows) {
88662
88812
  if (r.runId == null) continue;
88663
88813
  existingByRunId.set(r.runId, (existingByRunId.get(r.runId) ?? 0) + 1);
@@ -88712,7 +88862,7 @@ var IntelligenceService = class {
88712
88862
  */
88713
88863
  runIdsWithSnapshots(runIds) {
88714
88864
  if (runIds.length === 0) return /* @__PURE__ */ new Set();
88715
- const rows = this.db.select({ runId: querySnapshots.runId }).from(querySnapshots).where(inArray33(querySnapshots.runId, [...runIds])).groupBy(querySnapshots.runId).all();
88865
+ const rows = this.db.select({ runId: querySnapshots.runId }).from(querySnapshots).where(inArray34(querySnapshots.runId, [...runIds])).groupBy(querySnapshots.runId).all();
88716
88866
  return new Set(rows.map((r) => r.runId));
88717
88867
  }
88718
88868
  /**
@@ -88857,7 +89007,7 @@ var IntelligenceService = class {
88857
89007
  // Defensive — see top of file.
88858
89008
  ne15(runs.trigger, RunTriggers.probe)
88859
89009
  )
88860
- ).orderBy(desc37(runs.createdAt), desc37(runs.id)).limit((RECURRENCE_LOOKBACK_RUNS + 1) * ROWS_PER_GROUP_BUDGET).all();
89010
+ ).orderBy(desc38(runs.createdAt), desc38(runs.id)).limit((RECURRENCE_LOOKBACK_RUNS + 1) * ROWS_PER_GROUP_BUDGET).all();
88861
89011
  const recentGroups = groupRunsByCreatedAt(recentRunRows);
88862
89012
  const recentRunIds = [];
88863
89013
  const recentRunIdToCreatedAt = /* @__PURE__ */ new Map();
@@ -88873,7 +89023,7 @@ var IntelligenceService = class {
88873
89023
  const haveHistory = recentRunIds.length > 0;
88874
89024
  const priorRegressionsByPair = /* @__PURE__ */ new Map();
88875
89025
  if (haveHistory) {
88876
- const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and71(eq84(insights.type, "regression"), inArray33(insights.runId, recentRunIds))).all();
89026
+ const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and71(eq84(insights.type, "regression"), inArray34(insights.runId, recentRunIds))).all();
88877
89027
  const regressionGroups = /* @__PURE__ */ new Map();
88878
89028
  for (const row of priorRows) {
88879
89029
  if (!row.runId) continue;