@ainyc/canonry 4.114.1 → 4.115.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.
- package/assets/assets/{BacklinksPage-C60ma4Sg.js → BacklinksPage-DhXsZ8Sb.js} +1 -1
- package/assets/assets/{ChartPrimitives-Blgw1l6J.js → ChartPrimitives-Cdj0P8uG.js} +1 -1
- package/assets/assets/ProjectPage-DAWtJQ3w.js +7 -0
- package/assets/assets/{RunRow-DgQiXWZl.js → RunRow-GJ_2CEif.js} +1 -1
- package/assets/assets/{RunsPage-C9upHccV.js → RunsPage-upaDiLFK.js} +1 -1
- package/assets/assets/{SettingsPage-Bz_-_DnJ.js → SettingsPage-FbmEaN16.js} +1 -1
- package/assets/assets/{TrafficPage-BhBnQl2N.js → TrafficPage-Di0H5JRu.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-DWXqcRNO.js → TrafficSourceDetailPage-Bc2mxXSV.js} +1 -1
- package/assets/assets/{arrow-left-C6SuuEtD.js → arrow-left-yOCIy3_x.js} +1 -1
- package/assets/assets/{extract-error-message-DPZ5yqzd.js → extract-error-message-tCNIzznL.js} +1 -1
- package/assets/assets/index-Bb5yUz7k.css +1 -0
- package/assets/assets/{index-C3oQZHf8.js → index-D0ZdnFQf.js} +43 -43
- package/assets/assets/{trash-2-D3Nju7AK.js → trash-2-gRyTO-PS.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-3VSTTH4M.js → chunk-BXNFOGDF.js} +227 -187
- package/dist/{chunk-WMWZW34J.js → chunk-PGVGHGIX.js} +3 -3
- package/dist/cli.js +3 -3
- package/dist/index.js +3 -3
- package/dist/{intelligence-service-I5EQ77KZ.js → intelligence-service-2C7H4C6A.js} +1 -1
- package/dist/mcp.js +1 -1
- package/package.json +10 -10
- package/assets/assets/ProjectPage-DfvEEwNU.js +0 -7
- package/assets/assets/index-CReX5Jn9.css +0 -1
- /package/dist/{chunk-DUBZH5JW.js → chunk-MO7GPMNV.js} +0 -0
|
@@ -276,7 +276,7 @@ import {
|
|
|
276
276
|
} from "./chunk-VEUBAZRG.js";
|
|
277
277
|
|
|
278
278
|
// src/intelligence-service.ts
|
|
279
|
-
import { eq as eq38, desc as desc18, asc as asc6, and as
|
|
279
|
+
import { eq as eq38, desc as desc18, asc as asc6, and as and30, ne as ne5, or as or6, inArray as inArray14, gte as gte7, lte as lte4 } from "drizzle-orm";
|
|
280
280
|
|
|
281
281
|
// ../db/src/client.ts
|
|
282
282
|
import { mkdirSync } from "fs";
|
|
@@ -6706,7 +6706,7 @@ async function queryRoutes(app, opts) {
|
|
|
6706
6706
|
|
|
6707
6707
|
// ../api-routes/src/competitors.ts
|
|
6708
6708
|
import crypto6 from "crypto";
|
|
6709
|
-
import { eq as eq5 } from "drizzle-orm";
|
|
6709
|
+
import { and as and2, eq as eq5 } from "drizzle-orm";
|
|
6710
6710
|
function normalizeCompetitor(domain) {
|
|
6711
6711
|
const reg = registrableDomain(domain);
|
|
6712
6712
|
if (reg) return reg;
|
|
@@ -6725,11 +6725,14 @@ function normalizeCompetitorList(domains) {
|
|
|
6725
6725
|
}
|
|
6726
6726
|
return result;
|
|
6727
6727
|
}
|
|
6728
|
+
function serializeCompetitor(row) {
|
|
6729
|
+
return { id: row.id, domain: row.domain, createdAt: row.createdAt };
|
|
6730
|
+
}
|
|
6728
6731
|
async function competitorRoutes(app) {
|
|
6729
6732
|
app.get("/projects/:name/competitors", async (request, reply) => {
|
|
6730
6733
|
const project = resolveProject(app.db, request.params.name);
|
|
6731
6734
|
const rows = app.db.select().from(competitors).where(eq5(competitors.projectId, project.id)).all();
|
|
6732
|
-
return reply.send(rows.map(
|
|
6735
|
+
return reply.send(rows.map(serializeCompetitor));
|
|
6733
6736
|
});
|
|
6734
6737
|
app.put("/projects/:name/competitors", async (request, reply) => {
|
|
6735
6738
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -6759,7 +6762,7 @@ async function competitorRoutes(app) {
|
|
|
6759
6762
|
});
|
|
6760
6763
|
});
|
|
6761
6764
|
const rows = app.db.select().from(competitors).where(eq5(competitors.projectId, project.id)).all();
|
|
6762
|
-
return reply.send(rows.map(
|
|
6765
|
+
return reply.send(rows.map(serializeCompetitor));
|
|
6763
6766
|
});
|
|
6764
6767
|
app.post("/projects/:name/competitors", async (request, reply) => {
|
|
6765
6768
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -6791,7 +6794,7 @@ async function competitorRoutes(app) {
|
|
|
6791
6794
|
});
|
|
6792
6795
|
});
|
|
6793
6796
|
const rows = app.db.select().from(competitors).where(eq5(competitors.projectId, project.id)).all();
|
|
6794
|
-
return reply.send(rows.map(
|
|
6797
|
+
return reply.send(rows.map(serializeCompetitor));
|
|
6795
6798
|
});
|
|
6796
6799
|
app.delete("/projects/:name/competitors", async (request, reply) => {
|
|
6797
6800
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -6813,7 +6816,26 @@ async function competitorRoutes(app) {
|
|
|
6813
6816
|
});
|
|
6814
6817
|
});
|
|
6815
6818
|
const rows = app.db.select().from(competitors).where(eq5(competitors.projectId, project.id)).all();
|
|
6816
|
-
return reply.send(rows.map(
|
|
6819
|
+
return reply.send(rows.map(serializeCompetitor));
|
|
6820
|
+
});
|
|
6821
|
+
app.delete("/projects/:name/competitors/:id", async (request, reply) => {
|
|
6822
|
+
const project = resolveProject(app.db, request.params.name);
|
|
6823
|
+
const competitor = app.db.select().from(competitors).where(and2(eq5(competitors.projectId, project.id), eq5(competitors.id, request.params.id))).get();
|
|
6824
|
+
if (!competitor) {
|
|
6825
|
+
throw notFound("Competitor", request.params.id);
|
|
6826
|
+
}
|
|
6827
|
+
app.db.transaction((tx) => {
|
|
6828
|
+
tx.delete(competitors).where(eq5(competitors.id, competitor.id)).run();
|
|
6829
|
+
writeAuditLog(tx, auditFromRequest(request, {
|
|
6830
|
+
projectId: project.id,
|
|
6831
|
+
actor: "api",
|
|
6832
|
+
action: "competitors.deleted",
|
|
6833
|
+
entityType: "competitor",
|
|
6834
|
+
entityId: competitor.id,
|
|
6835
|
+
diff: { deleted: [competitor.domain] }
|
|
6836
|
+
}));
|
|
6837
|
+
});
|
|
6838
|
+
return reply.status(204).send();
|
|
6817
6839
|
});
|
|
6818
6840
|
}
|
|
6819
6841
|
function parseCompetitorBatch(value) {
|
|
@@ -6829,12 +6851,12 @@ function parseCompetitorBatch(value) {
|
|
|
6829
6851
|
|
|
6830
6852
|
// ../api-routes/src/runs.ts
|
|
6831
6853
|
import crypto8 from "crypto";
|
|
6832
|
-
import { and as
|
|
6854
|
+
import { and as and4, eq as eq7, asc, desc, or as or2, sql as sql5 } from "drizzle-orm";
|
|
6833
6855
|
import { gte } from "drizzle-orm";
|
|
6834
6856
|
|
|
6835
6857
|
// ../api-routes/src/run-queue.ts
|
|
6836
6858
|
import crypto7 from "crypto";
|
|
6837
|
-
import { and as
|
|
6859
|
+
import { and as and3, eq as eq6, or } from "drizzle-orm";
|
|
6838
6860
|
function queueRunIfProjectIdle(db, params) {
|
|
6839
6861
|
const createdAt = params.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
6840
6862
|
const kind = params.kind ?? "answer-visibility";
|
|
@@ -6842,7 +6864,7 @@ function queueRunIfProjectIdle(db, params) {
|
|
|
6842
6864
|
const runId = crypto7.randomUUID();
|
|
6843
6865
|
return db.transaction((tx) => {
|
|
6844
6866
|
const activeRun = tx.select().from(runs).where(
|
|
6845
|
-
|
|
6867
|
+
and3(
|
|
6846
6868
|
eq6(runs.projectId, params.projectId),
|
|
6847
6869
|
or(eq6(runs.status, "queued"), eq6(runs.status, "running"))
|
|
6848
6870
|
)
|
|
@@ -6925,7 +6947,7 @@ async function runRoutes(app, opts) {
|
|
|
6925
6947
|
throw validationError("No locations configured for this project");
|
|
6926
6948
|
}
|
|
6927
6949
|
const result = app.db.transaction((tx) => {
|
|
6928
|
-
const activeRun = tx.select({ id: runs.id }).from(runs).where(
|
|
6950
|
+
const activeRun = tx.select({ id: runs.id }).from(runs).where(and4(
|
|
6929
6951
|
eq7(runs.projectId, project.id),
|
|
6930
6952
|
or2(eq7(runs.status, "queued"), eq7(runs.status, "running"))
|
|
6931
6953
|
)).get();
|
|
@@ -6998,15 +7020,15 @@ async function runRoutes(app, opts) {
|
|
|
6998
7020
|
const parsedLimit = parseInt(request.query.limit ?? "", 10);
|
|
6999
7021
|
const limit = Number.isNaN(parsedLimit) || parsedLimit <= 0 ? void 0 : parsedLimit;
|
|
7000
7022
|
const kind = parseListKind(request.query.kind);
|
|
7001
|
-
const where = kind ?
|
|
7023
|
+
const where = kind ? and4(eq7(runs.projectId, project.id), eq7(runs.kind, kind)) : eq7(runs.projectId, project.id);
|
|
7002
7024
|
const rows = limit == null ? app.db.select().from(runs).where(where).orderBy(asc(runs.createdAt)).all() : app.db.select().from(runs).where(where).orderBy(desc(runs.createdAt)).limit(limit).all().reverse();
|
|
7003
7025
|
return reply.send(rows.map(formatRun));
|
|
7004
7026
|
});
|
|
7005
7027
|
app.get("/projects/:name/runs/latest", async (request, reply) => {
|
|
7006
7028
|
const project = resolveProject(app.db, request.params.name);
|
|
7007
|
-
const countRow = app.db.select({ count: sql5`count(*)` }).from(runs).where(
|
|
7029
|
+
const countRow = app.db.select({ count: sql5`count(*)` }).from(runs).where(and4(eq7(runs.projectId, project.id), notProbeRun())).get();
|
|
7008
7030
|
const totalRuns = countRow?.count ?? 0;
|
|
7009
|
-
const latestRun = app.db.select().from(runs).where(
|
|
7031
|
+
const latestRun = app.db.select().from(runs).where(and4(eq7(runs.projectId, project.id), notProbeRun())).orderBy(desc(runs.createdAt), desc(runs.id)).limit(1).get();
|
|
7010
7032
|
if (!latestRun) {
|
|
7011
7033
|
return reply.send({ totalRuns: 0, run: null });
|
|
7012
7034
|
}
|
|
@@ -7025,7 +7047,7 @@ async function runRoutes(app, opts) {
|
|
|
7025
7047
|
if (kind) filters.push(eq7(runs.kind, kind));
|
|
7026
7048
|
const scopedProjectId = request.apiKey?.projectId;
|
|
7027
7049
|
if (scopedProjectId) filters.push(eq7(runs.projectId, scopedProjectId));
|
|
7028
|
-
const rows = app.db.select().from(runs).where(
|
|
7050
|
+
const rows = app.db.select().from(runs).where(and4(...filters)).orderBy(desc(runs.createdAt), desc(runs.id)).limit(limit).all();
|
|
7029
7051
|
return reply.send(rows.map(formatRun));
|
|
7030
7052
|
});
|
|
7031
7053
|
app.post("/runs", async (request, reply) => {
|
|
@@ -7236,7 +7258,7 @@ function loadRunDetail(app, run) {
|
|
|
7236
7258
|
|
|
7237
7259
|
// ../api-routes/src/apply.ts
|
|
7238
7260
|
import crypto10 from "crypto";
|
|
7239
|
-
import { and as
|
|
7261
|
+
import { and as and5, eq as eq8 } from "drizzle-orm";
|
|
7240
7262
|
|
|
7241
7263
|
// ../api-routes/src/schedule-utils.ts
|
|
7242
7264
|
import { CronExpressionParser } from "cron-parser";
|
|
@@ -7679,7 +7701,7 @@ async function applyRoutes(app, opts) {
|
|
|
7679
7701
|
});
|
|
7680
7702
|
const AV_KIND = SchedulableRunKinds["answer-visibility"];
|
|
7681
7703
|
if (resolvedSchedule) {
|
|
7682
|
-
const existingSched = tx.select().from(schedules).where(
|
|
7704
|
+
const existingSched = tx.select().from(schedules).where(and5(eq8(schedules.projectId, projectId), eq8(schedules.kind, AV_KIND))).get();
|
|
7683
7705
|
if (existingSched) {
|
|
7684
7706
|
tx.update(schedules).set({
|
|
7685
7707
|
cronExpr: resolvedSchedule.cronExpr,
|
|
@@ -7705,9 +7727,9 @@ async function applyRoutes(app, opts) {
|
|
|
7705
7727
|
}
|
|
7706
7728
|
scheduleAction = "upsert";
|
|
7707
7729
|
} else if (deleteSchedule) {
|
|
7708
|
-
const existingSched = tx.select().from(schedules).where(
|
|
7730
|
+
const existingSched = tx.select().from(schedules).where(and5(eq8(schedules.projectId, projectId), eq8(schedules.kind, AV_KIND))).get();
|
|
7709
7731
|
if (existingSched) {
|
|
7710
|
-
tx.delete(schedules).where(
|
|
7732
|
+
tx.delete(schedules).where(and5(eq8(schedules.projectId, projectId), eq8(schedules.kind, AV_KIND))).run();
|
|
7711
7733
|
scheduleAction = "delete";
|
|
7712
7734
|
}
|
|
7713
7735
|
}
|
|
@@ -7791,7 +7813,7 @@ function normalizeCompetitorList2(domains) {
|
|
|
7791
7813
|
}
|
|
7792
7814
|
|
|
7793
7815
|
// ../api-routes/src/history.ts
|
|
7794
|
-
import { and as
|
|
7816
|
+
import { and as and6, eq as eq9, desc as desc2, inArray as inArray2 } from "drizzle-orm";
|
|
7795
7817
|
|
|
7796
7818
|
// ../api-routes/src/notification-redaction.ts
|
|
7797
7819
|
var REDACTED_URL = {
|
|
@@ -7849,7 +7871,7 @@ async function historyRoutes(app) {
|
|
|
7849
7871
|
const project = resolveProject(app.db, request.params.name);
|
|
7850
7872
|
const limit = parseInt(request.query.limit ?? "50", 10);
|
|
7851
7873
|
const offset = parseInt(request.query.offset ?? "0", 10);
|
|
7852
|
-
const projectRuns = app.db.select({ id: runs.id }).from(runs).where(
|
|
7874
|
+
const projectRuns = app.db.select({ id: runs.id }).from(runs).where(and6(eq9(runs.projectId, project.id), notProbeRun())).all();
|
|
7853
7875
|
if (projectRuns.length === 0) {
|
|
7854
7876
|
return reply.send({ snapshots: [], total: 0 });
|
|
7855
7877
|
}
|
|
@@ -7898,7 +7920,7 @@ async function historyRoutes(app) {
|
|
|
7898
7920
|
app.get("/projects/:name/timeline", async (request, reply) => {
|
|
7899
7921
|
const project = resolveProject(app.db, request.params.name);
|
|
7900
7922
|
const projectQueries = app.db.select().from(queries).where(eq9(queries.projectId, project.id)).all();
|
|
7901
|
-
const projectRuns = app.db.select().from(runs).where(
|
|
7923
|
+
const projectRuns = app.db.select().from(runs).where(and6(eq9(runs.projectId, project.id), notProbeRun())).orderBy(runs.createdAt).all();
|
|
7902
7924
|
if (projectRuns.length === 0 || projectQueries.length === 0) {
|
|
7903
7925
|
return reply.send([]);
|
|
7904
7926
|
}
|
|
@@ -8109,13 +8131,13 @@ function formatAuditEntry(row) {
|
|
|
8109
8131
|
}
|
|
8110
8132
|
|
|
8111
8133
|
// ../api-routes/src/analytics.ts
|
|
8112
|
-
import { and as
|
|
8134
|
+
import { and as and7, eq as eq10, desc as desc3, inArray as inArray3 } from "drizzle-orm";
|
|
8113
8135
|
async function analyticsRoutes(app) {
|
|
8114
8136
|
app.get("/projects/:name/analytics/metrics", async (request, reply) => {
|
|
8115
8137
|
const project = resolveProject(app.db, request.params.name);
|
|
8116
8138
|
const window = parseWindow(request.query.window);
|
|
8117
8139
|
const cutoff = windowCutoff(window);
|
|
8118
|
-
const projectRuns = app.db.select().from(runs).where(
|
|
8140
|
+
const projectRuns = app.db.select().from(runs).where(and7(eq10(runs.projectId, project.id), notProbeRun())).orderBy(runs.createdAt).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
|
|
8119
8141
|
if (projectRuns.length === 0) {
|
|
8120
8142
|
return reply.send({
|
|
8121
8143
|
window,
|
|
@@ -8167,14 +8189,14 @@ async function analyticsRoutes(app) {
|
|
|
8167
8189
|
const project = resolveProject(app.db, request.params.name);
|
|
8168
8190
|
const window = parseWindow(request.query.window);
|
|
8169
8191
|
const cutoff = windowCutoff(window);
|
|
8170
|
-
const completedRuns = app.db.select().from(runs).where(
|
|
8192
|
+
const completedRuns = app.db.select().from(runs).where(and7(eq10(runs.projectId, project.id), notProbeRun())).orderBy(desc3(runs.createdAt), desc3(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial");
|
|
8171
8193
|
const latestGroup = groupRunsByCreatedAt(completedRuns)[0] ?? [];
|
|
8172
8194
|
const latestGroupRunIds = latestGroup.map((r) => r.id);
|
|
8173
8195
|
const latestRun = pickGroupRepresentative(latestGroup);
|
|
8174
8196
|
if (!latestRun) {
|
|
8175
8197
|
return reply.send({ cited: [], gap: [], uncited: [], mentionedQueries: [], mentionGap: [], notMentioned: [], runId: "", window });
|
|
8176
8198
|
}
|
|
8177
|
-
const windowRuns = app.db.select().from(runs).where(
|
|
8199
|
+
const windowRuns = app.db.select().from(runs).where(and7(eq10(runs.projectId, project.id), notProbeRun())).orderBy(runs.createdAt).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
|
|
8178
8200
|
const windowRunIds = windowRuns.map((r) => r.id);
|
|
8179
8201
|
const runIdToCreatedAt = new Map(windowRuns.map((r) => [r.id, r.createdAt]));
|
|
8180
8202
|
const consistencyMap = /* @__PURE__ */ new Map();
|
|
@@ -8305,7 +8327,7 @@ async function analyticsRoutes(app) {
|
|
|
8305
8327
|
const mapped = surfaceClassFromCompetitorType(row.competitorType);
|
|
8306
8328
|
if (mapped) storedSurfaceClasses.set(normalizeProjectDomain(row.domain), mapped);
|
|
8307
8329
|
}
|
|
8308
|
-
const windowRuns = app.db.select().from(runs).where(
|
|
8330
|
+
const windowRuns = app.db.select().from(runs).where(and7(eq10(runs.projectId, project.id), notProbeRun())).orderBy(desc3(runs.createdAt), desc3(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => !cutoff || r.createdAt >= cutoff);
|
|
8309
8331
|
if (windowRuns.length === 0) {
|
|
8310
8332
|
return reply.send({
|
|
8311
8333
|
overall: [],
|
|
@@ -8570,7 +8592,7 @@ function buildCategoryCounts(counts2) {
|
|
|
8570
8592
|
}
|
|
8571
8593
|
|
|
8572
8594
|
// ../api-routes/src/intelligence.ts
|
|
8573
|
-
import { eq as eq11, desc as desc4, and as
|
|
8595
|
+
import { eq as eq11, desc as desc4, and as and8, inArray as inArray4, like } from "drizzle-orm";
|
|
8574
8596
|
var SEVERITY_RANK = { low: 0, medium: 1, high: 2, critical: 3 };
|
|
8575
8597
|
function severitiesAtOrAbove(min) {
|
|
8576
8598
|
const floor = SEVERITY_RANK[min];
|
|
@@ -8710,7 +8732,7 @@ async function intelligenceRoutes(app) {
|
|
|
8710
8732
|
}
|
|
8711
8733
|
limit = parsed;
|
|
8712
8734
|
}
|
|
8713
|
-
const rows = app.db.select().from(insights).where(conditions.length === 1 ? conditions[0] :
|
|
8735
|
+
const rows = app.db.select().from(insights).where(conditions.length === 1 ? conditions[0] : and8(...conditions)).orderBy(desc4(insights.createdAt)).all();
|
|
8714
8736
|
const showDismissed = request.query.dismissed === "true";
|
|
8715
8737
|
let result = rows.filter((r) => showDismissed || !r.dismissed).map(mapInsightRow);
|
|
8716
8738
|
if (limit !== void 0) result = result.slice(0, limit);
|
|
@@ -8735,7 +8757,7 @@ async function intelligenceRoutes(app) {
|
|
|
8735
8757
|
});
|
|
8736
8758
|
app.get("/projects/:name/health/latest", async (request, reply) => {
|
|
8737
8759
|
const project = resolveProject(app.db, request.params.name);
|
|
8738
|
-
const projectVisRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
|
|
8760
|
+
const projectVisRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and8(
|
|
8739
8761
|
eq11(runs.projectId, project.id),
|
|
8740
8762
|
eq11(runs.kind, RunKinds["answer-visibility"]),
|
|
8741
8763
|
inArray4(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
@@ -8746,7 +8768,7 @@ async function intelligenceRoutes(app) {
|
|
|
8746
8768
|
const latestGroup = groupRunsByCreatedAt(projectVisRuns)[0] ?? [];
|
|
8747
8769
|
const latestGroupRunIds = latestGroup.map((r) => r.id);
|
|
8748
8770
|
if (latestGroupRunIds.length > 0) {
|
|
8749
|
-
const groupRows = app.db.select().from(healthSnapshots).where(
|
|
8771
|
+
const groupRows = app.db.select().from(healthSnapshots).where(and8(
|
|
8750
8772
|
eq11(healthSnapshots.projectId, project.id),
|
|
8751
8773
|
inArray4(healthSnapshots.runId, latestGroupRunIds)
|
|
8752
8774
|
)).all();
|
|
@@ -8770,14 +8792,14 @@ async function intelligenceRoutes(app) {
|
|
|
8770
8792
|
}
|
|
8771
8793
|
|
|
8772
8794
|
// ../api-routes/src/report.ts
|
|
8773
|
-
import { and as
|
|
8795
|
+
import { and as and12, desc as desc7, eq as eq15, gte as gte2, inArray as inArray6, lt, lte, ne as ne2, or as or3, sql as sql7 } from "drizzle-orm";
|
|
8774
8796
|
|
|
8775
8797
|
// ../api-routes/src/content.ts
|
|
8776
8798
|
import crypto11 from "crypto";
|
|
8777
|
-
import { and as
|
|
8799
|
+
import { and as and10, desc as desc6, eq as eq13 } from "drizzle-orm";
|
|
8778
8800
|
|
|
8779
8801
|
// ../api-routes/src/content-data.ts
|
|
8780
|
-
import { and as
|
|
8802
|
+
import { and as and9, eq as eq12, desc as desc5, inArray as inArray5 } from "drizzle-orm";
|
|
8781
8803
|
var RECENT_RUNS_WINDOW = 5;
|
|
8782
8804
|
function loadOrchestratorInput(db, project, locationFilter = void 0) {
|
|
8783
8805
|
const projectId = project.id;
|
|
@@ -8907,7 +8929,7 @@ function listCompetitorDomains(db, projectId) {
|
|
|
8907
8929
|
}
|
|
8908
8930
|
function listRecentAnswerVisibilityRunIds(db, projectId, limit, locationFilter) {
|
|
8909
8931
|
const rows = db.select({ id: runs.id, location: runs.location }).from(runs).where(
|
|
8910
|
-
|
|
8932
|
+
and9(
|
|
8911
8933
|
eq12(runs.projectId, projectId),
|
|
8912
8934
|
eq12(runs.kind, RunKinds["answer-visibility"]),
|
|
8913
8935
|
// Queued/running/failed/cancelled runs may have partial or no
|
|
@@ -9278,7 +9300,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
9278
9300
|
dismissedAt: now
|
|
9279
9301
|
}
|
|
9280
9302
|
}).run();
|
|
9281
|
-
const row = app.db.select().from(contentTargetDismissals).where(
|
|
9303
|
+
const row = app.db.select().from(contentTargetDismissals).where(and10(
|
|
9282
9304
|
eq13(contentTargetDismissals.projectId, project.id),
|
|
9283
9305
|
eq13(contentTargetDismissals.targetRef, targetRef)
|
|
9284
9306
|
)).get();
|
|
@@ -9288,7 +9310,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
9288
9310
|
app.delete("/projects/:name/content/dismissals/:targetRef", async (request, reply) => {
|
|
9289
9311
|
const project = resolveProject(app.db, request.params.name);
|
|
9290
9312
|
const { targetRef } = request.params;
|
|
9291
|
-
const result = app.db.delete(contentTargetDismissals).where(
|
|
9313
|
+
const result = app.db.delete(contentTargetDismissals).where(and10(
|
|
9292
9314
|
eq13(contentTargetDismissals.projectId, project.id),
|
|
9293
9315
|
eq13(contentTargetDismissals.targetRef, targetRef)
|
|
9294
9316
|
)).run();
|
|
@@ -9299,7 +9321,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
9299
9321
|
});
|
|
9300
9322
|
app.get("/projects/:name/content/recommendations/:targetRef/analysis", async (request, reply) => {
|
|
9301
9323
|
const project = resolveProject(app.db, request.params.name);
|
|
9302
|
-
const row = app.db.select().from(recommendationExplanations).where(
|
|
9324
|
+
const row = app.db.select().from(recommendationExplanations).where(and10(
|
|
9303
9325
|
eq13(recommendationExplanations.projectId, project.id),
|
|
9304
9326
|
eq13(recommendationExplanations.targetRef, request.params.targetRef)
|
|
9305
9327
|
)).orderBy(desc6(recommendationExplanations.generatedAt)).limit(1).get();
|
|
@@ -9327,7 +9349,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
9327
9349
|
throw notFound("contentRecommendation", targetRef);
|
|
9328
9350
|
}
|
|
9329
9351
|
if (!body.forceRefresh) {
|
|
9330
|
-
const cached = app.db.select().from(recommendationExplanations).where(
|
|
9352
|
+
const cached = app.db.select().from(recommendationExplanations).where(and10(
|
|
9331
9353
|
eq13(recommendationExplanations.projectId, project.id),
|
|
9332
9354
|
eq13(recommendationExplanations.targetRef, targetRef)
|
|
9333
9355
|
)).orderBy(desc6(recommendationExplanations.generatedAt)).limit(1).get();
|
|
@@ -9366,7 +9388,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
9366
9388
|
generatedAt: now
|
|
9367
9389
|
}
|
|
9368
9390
|
}).run();
|
|
9369
|
-
const row = app.db.select().from(recommendationExplanations).where(
|
|
9391
|
+
const row = app.db.select().from(recommendationExplanations).where(and10(
|
|
9370
9392
|
eq13(recommendationExplanations.projectId, project.id),
|
|
9371
9393
|
eq13(recommendationExplanations.targetRef, targetRef),
|
|
9372
9394
|
eq13(recommendationExplanations.promptVersion, result.promptVersion)
|
|
@@ -9450,7 +9472,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
9450
9472
|
generatedAt: now
|
|
9451
9473
|
}
|
|
9452
9474
|
}).run();
|
|
9453
|
-
const row = app.db.select().from(recommendationBriefs).where(
|
|
9475
|
+
const row = app.db.select().from(recommendationBriefs).where(and10(
|
|
9454
9476
|
eq13(recommendationBriefs.projectId, project.id),
|
|
9455
9477
|
eq13(recommendationBriefs.targetRef, targetRef),
|
|
9456
9478
|
eq13(recommendationBriefs.promptVersion, result.promptVersion)
|
|
@@ -9480,7 +9502,7 @@ function lookupCachedBrief(db, projectId, targetRef, promptVersion) {
|
|
|
9480
9502
|
if (promptVersion !== void 0) {
|
|
9481
9503
|
conditions.push(eq13(recommendationBriefs.promptVersion, promptVersion));
|
|
9482
9504
|
}
|
|
9483
|
-
return db.select().from(recommendationBriefs).where(
|
|
9505
|
+
return db.select().from(recommendationBriefs).where(and10(...conditions)).orderBy(desc6(recommendationBriefs.generatedAt)).limit(1).get();
|
|
9484
9506
|
}
|
|
9485
9507
|
function parseLimitParam(raw) {
|
|
9486
9508
|
if (raw === void 0) return void 0;
|
|
@@ -9506,7 +9528,7 @@ function winnabilityClassRank(winnabilityClass) {
|
|
|
9506
9528
|
}
|
|
9507
9529
|
|
|
9508
9530
|
// ../api-routes/src/gsc-totals.ts
|
|
9509
|
-
import { and as
|
|
9531
|
+
import { and as and11, asc as asc2, eq as eq14, sql as sql6 } from "drizzle-orm";
|
|
9510
9532
|
function readGscDailyTotals(db, projectId, startDate, endDate) {
|
|
9511
9533
|
const rows = db.select({
|
|
9512
9534
|
date: gscDailyTotals.date,
|
|
@@ -9514,7 +9536,7 @@ function readGscDailyTotals(db, projectId, startDate, endDate) {
|
|
|
9514
9536
|
impressions: gscDailyTotals.impressions,
|
|
9515
9537
|
position: gscDailyTotals.position
|
|
9516
9538
|
}).from(gscDailyTotals).where(
|
|
9517
|
-
|
|
9539
|
+
and11(
|
|
9518
9540
|
eq14(gscDailyTotals.projectId, projectId),
|
|
9519
9541
|
sql6`${gscDailyTotals.date} >= ${startDate}`,
|
|
9520
9542
|
sql6`${gscDailyTotals.date} <= ${endDate}`
|
|
@@ -11945,7 +11967,7 @@ function buildGscSection(db, projectId, projectBrandNames, canonicalDomain, trac
|
|
|
11945
11967
|
function buildGaSection(db, projectId, windowDays) {
|
|
11946
11968
|
const gaWindowKey = GA_WINDOW_SUMMARY_KEYS[windowDays];
|
|
11947
11969
|
const windowSummary = gaWindowKey ? db.select().from(gaTrafficWindowSummaries).where(
|
|
11948
|
-
|
|
11970
|
+
and12(
|
|
11949
11971
|
eq15(gaTrafficWindowSummaries.projectId, projectId),
|
|
11950
11972
|
eq15(gaTrafficWindowSummaries.windowKey, gaWindowKey)
|
|
11951
11973
|
)
|
|
@@ -12123,7 +12145,7 @@ function nonSubresourceReferralPathCondition() {
|
|
|
12123
12145
|
}
|
|
12124
12146
|
function buildServerActivity(db, projectId, windowDays) {
|
|
12125
12147
|
const sourceRows = db.select({ id: trafficSources.id }).from(trafficSources).where(
|
|
12126
|
-
|
|
12148
|
+
and12(
|
|
12127
12149
|
eq15(trafficSources.projectId, projectId),
|
|
12128
12150
|
ne2(trafficSources.status, TrafficSourceStatuses.archived)
|
|
12129
12151
|
)
|
|
@@ -12139,7 +12161,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12139
12161
|
const trendStart = new Date(trendStartMs).toISOString();
|
|
12140
12162
|
const sumVerifiedCrawlers = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
|
|
12141
12163
|
db.select({ total: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
12142
|
-
|
|
12164
|
+
and12(
|
|
12143
12165
|
eq15(crawlerEventsHourly.projectId, projectId),
|
|
12144
12166
|
eq15(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
12145
12167
|
gte2(crawlerEventsHourly.tsHour, windowStartIso),
|
|
@@ -12149,7 +12171,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12149
12171
|
);
|
|
12150
12172
|
const sumUnverifiedCrawlers = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
|
|
12151
12173
|
db.select({ total: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
12152
|
-
|
|
12174
|
+
and12(
|
|
12153
12175
|
eq15(crawlerEventsHourly.projectId, projectId),
|
|
12154
12176
|
ne2(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
12155
12177
|
gte2(crawlerEventsHourly.tsHour, windowStartIso),
|
|
@@ -12159,7 +12181,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12159
12181
|
);
|
|
12160
12182
|
const sumReferrals = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
|
|
12161
12183
|
db.select({ total: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
12162
|
-
|
|
12184
|
+
and12(
|
|
12163
12185
|
eq15(aiReferralEventsHourly.projectId, projectId),
|
|
12164
12186
|
nonSubresourceReferralPathCondition(),
|
|
12165
12187
|
gte2(aiReferralEventsHourly.tsHour, windowStartIso),
|
|
@@ -12169,7 +12191,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12169
12191
|
);
|
|
12170
12192
|
const sumUserFetches = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
|
|
12171
12193
|
db.select({ total: sql7`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
12172
|
-
|
|
12194
|
+
and12(
|
|
12173
12195
|
eq15(aiUserFetchEventsHourly.projectId, projectId),
|
|
12174
12196
|
gte2(aiUserFetchEventsHourly.tsHour, windowStartIso),
|
|
12175
12197
|
exclusiveEnd ? lt(aiUserFetchEventsHourly.tsHour, windowEndIso) : lte(aiUserFetchEventsHourly.tsHour, windowEndIso)
|
|
@@ -12189,7 +12211,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12189
12211
|
verificationStatus: crawlerEventsHourly.verificationStatus,
|
|
12190
12212
|
hits: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
12191
12213
|
}).from(crawlerEventsHourly).where(
|
|
12192
|
-
|
|
12214
|
+
and12(
|
|
12193
12215
|
eq15(crawlerEventsHourly.projectId, projectId),
|
|
12194
12216
|
gte2(crawlerEventsHourly.tsHour, headlineStart),
|
|
12195
12217
|
lte(crawlerEventsHourly.tsHour, headlineEnd)
|
|
@@ -12199,7 +12221,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12199
12221
|
operator: crawlerEventsHourly.operator,
|
|
12200
12222
|
hits: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
12201
12223
|
}).from(crawlerEventsHourly).where(
|
|
12202
|
-
|
|
12224
|
+
and12(
|
|
12203
12225
|
eq15(crawlerEventsHourly.projectId, projectId),
|
|
12204
12226
|
eq15(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
12205
12227
|
gte2(crawlerEventsHourly.tsHour, priorStart),
|
|
@@ -12210,7 +12232,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12210
12232
|
operator: aiReferralEventsHourly.operator,
|
|
12211
12233
|
hits: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
|
|
12212
12234
|
}).from(aiReferralEventsHourly).where(
|
|
12213
|
-
|
|
12235
|
+
and12(
|
|
12214
12236
|
eq15(aiReferralEventsHourly.projectId, projectId),
|
|
12215
12237
|
nonSubresourceReferralPathCondition(),
|
|
12216
12238
|
gte2(aiReferralEventsHourly.tsHour, headlineStart),
|
|
@@ -12221,7 +12243,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12221
12243
|
operator: aiUserFetchEventsHourly.operator,
|
|
12222
12244
|
hits: sql7`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
|
|
12223
12245
|
}).from(aiUserFetchEventsHourly).where(
|
|
12224
|
-
|
|
12246
|
+
and12(
|
|
12225
12247
|
eq15(aiUserFetchEventsHourly.projectId, projectId),
|
|
12226
12248
|
gte2(aiUserFetchEventsHourly.tsHour, headlineStart),
|
|
12227
12249
|
lte(aiUserFetchEventsHourly.tsHour, headlineEnd)
|
|
@@ -12265,7 +12287,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12265
12287
|
hits: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`,
|
|
12266
12288
|
operators: sql7`COUNT(DISTINCT ${crawlerEventsHourly.operator})`
|
|
12267
12289
|
}).from(crawlerEventsHourly).where(
|
|
12268
|
-
|
|
12290
|
+
and12(
|
|
12269
12291
|
eq15(crawlerEventsHourly.projectId, projectId),
|
|
12270
12292
|
eq15(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
12271
12293
|
gte2(crawlerEventsHourly.tsHour, headlineStart),
|
|
@@ -12282,7 +12304,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12282
12304
|
arrivals: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
|
|
12283
12305
|
landingPaths: sql7`COUNT(DISTINCT ${aiReferralEventsHourly.landingPathNormalized})`
|
|
12284
12306
|
}).from(aiReferralEventsHourly).where(
|
|
12285
|
-
|
|
12307
|
+
and12(
|
|
12286
12308
|
eq15(aiReferralEventsHourly.projectId, projectId),
|
|
12287
12309
|
nonSubresourceReferralPathCondition(),
|
|
12288
12310
|
gte2(aiReferralEventsHourly.tsHour, headlineStart),
|
|
@@ -12299,7 +12321,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12299
12321
|
arrivals: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
|
|
12300
12322
|
products: sql7`COUNT(DISTINCT ${aiReferralEventsHourly.product})`
|
|
12301
12323
|
}).from(aiReferralEventsHourly).where(
|
|
12302
|
-
|
|
12324
|
+
and12(
|
|
12303
12325
|
eq15(aiReferralEventsHourly.projectId, projectId),
|
|
12304
12326
|
nonSubresourceReferralPathCondition(),
|
|
12305
12327
|
gte2(aiReferralEventsHourly.tsHour, headlineStart),
|
|
@@ -12315,7 +12337,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12315
12337
|
date: sql7`SUBSTR(${crawlerEventsHourly.tsHour}, 1, 10)`,
|
|
12316
12338
|
hits: sql7`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
12317
12339
|
}).from(crawlerEventsHourly).where(
|
|
12318
|
-
|
|
12340
|
+
and12(
|
|
12319
12341
|
eq15(crawlerEventsHourly.projectId, projectId),
|
|
12320
12342
|
eq15(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
12321
12343
|
gte2(crawlerEventsHourly.tsHour, trendStart),
|
|
@@ -12326,7 +12348,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12326
12348
|
date: sql7`SUBSTR(${aiReferralEventsHourly.tsHour}, 1, 10)`,
|
|
12327
12349
|
hits: sql7`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
|
|
12328
12350
|
}).from(aiReferralEventsHourly).where(
|
|
12329
|
-
|
|
12351
|
+
and12(
|
|
12330
12352
|
eq15(aiReferralEventsHourly.projectId, projectId),
|
|
12331
12353
|
nonSubresourceReferralPathCondition(),
|
|
12332
12354
|
gte2(aiReferralEventsHourly.tsHour, trendStart),
|
|
@@ -12337,7 +12359,7 @@ function buildServerActivity(db, projectId, windowDays) {
|
|
|
12337
12359
|
date: sql7`SUBSTR(${aiUserFetchEventsHourly.tsHour}, 1, 10)`,
|
|
12338
12360
|
hits: sql7`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
|
|
12339
12361
|
}).from(aiUserFetchEventsHourly).where(
|
|
12340
|
-
|
|
12362
|
+
and12(
|
|
12341
12363
|
eq15(aiUserFetchEventsHourly.projectId, projectId),
|
|
12342
12364
|
gte2(aiUserFetchEventsHourly.tsHour, trendStart),
|
|
12343
12365
|
lte(aiUserFetchEventsHourly.tsHour, headlineEnd)
|
|
@@ -12422,7 +12444,7 @@ function buildIndexingHealth(db, projectId) {
|
|
|
12422
12444
|
return null;
|
|
12423
12445
|
}
|
|
12424
12446
|
function buildCitationsTrend(db, projectId, queryLookup, locationFilter) {
|
|
12425
|
-
const visibilityRuns = db.select().from(runs).where(
|
|
12447
|
+
const visibilityRuns = db.select().from(runs).where(and12(eq15(runs.projectId, projectId), eq15(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter);
|
|
12426
12448
|
const totalQueries = queryLookup.byId.size;
|
|
12427
12449
|
const points = [];
|
|
12428
12450
|
for (const run of visibilityRuns) {
|
|
@@ -12470,7 +12492,7 @@ function buildCitationsTrend(db, projectId, queryLookup, locationFilter) {
|
|
|
12470
12492
|
}
|
|
12471
12493
|
function buildInsightList(db, projectId, locationFilter) {
|
|
12472
12494
|
const recentRunIds = db.select({ id: runs.id, location: runs.location }).from(runs).where(
|
|
12473
|
-
|
|
12495
|
+
and12(
|
|
12474
12496
|
eq15(runs.projectId, projectId),
|
|
12475
12497
|
eq15(runs.kind, RunKinds["answer-visibility"]),
|
|
12476
12498
|
or3(eq15(runs.status, RunStatuses.completed), eq15(runs.status, RunStatuses.partial)),
|
|
@@ -12478,7 +12500,7 @@ function buildInsightList(db, projectId, locationFilter) {
|
|
|
12478
12500
|
)
|
|
12479
12501
|
).orderBy(desc7(runs.createdAt)).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter).slice(0, INSIGHT_LOOKBACK_RUNS).map((r) => r.id);
|
|
12480
12502
|
if (recentRunIds.length === 0) return [];
|
|
12481
|
-
const rows = db.select().from(insights).where(
|
|
12503
|
+
const rows = db.select().from(insights).where(and12(eq15(insights.projectId, projectId), inArray6(insights.runId, recentRunIds))).orderBy(desc7(insights.createdAt)).all();
|
|
12482
12504
|
const severityRank = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
12483
12505
|
const flat = rows.filter((r) => !r.dismissed).map((r) => {
|
|
12484
12506
|
const recommendation = r.recommendation;
|
|
@@ -13030,7 +13052,7 @@ function buildProjectReport(db, projectName, periodDays) {
|
|
|
13030
13052
|
const project = resolveProject(db, projectName);
|
|
13031
13053
|
const queryLookup = loadQueryLookup(db, project.id);
|
|
13032
13054
|
const comparisonWindowDays = reportComparisonWindowDays(periodDays);
|
|
13033
|
-
const allRuns = db.select().from(runs).where(
|
|
13055
|
+
const allRuns = db.select().from(runs).where(and12(eq15(runs.projectId, project.id), notProbeRun())).orderBy(desc7(runs.createdAt), desc7(runs.id)).all();
|
|
13034
13056
|
const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
|
|
13035
13057
|
const completedVisRunGroups = groupRunsByCreatedAt(
|
|
13036
13058
|
visibilityRuns.filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial)
|
|
@@ -13266,7 +13288,7 @@ async function reportRoutes(app) {
|
|
|
13266
13288
|
}
|
|
13267
13289
|
|
|
13268
13290
|
// ../api-routes/src/citations.ts
|
|
13269
|
-
import { and as
|
|
13291
|
+
import { and as and13, eq as eq16, inArray as inArray7 } from "drizzle-orm";
|
|
13270
13292
|
async function citationRoutes(app) {
|
|
13271
13293
|
app.get("/projects/:name/citations/visibility", async (request, reply) => {
|
|
13272
13294
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -13275,7 +13297,7 @@ async function citationRoutes(app) {
|
|
|
13275
13297
|
if (projectQueries.length === 0) {
|
|
13276
13298
|
return reply.send(emptyCitationVisibility("no-queries"));
|
|
13277
13299
|
}
|
|
13278
|
-
const projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
|
|
13300
|
+
const projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and13(eq16(runs.projectId, project.id), notProbeRun())).all();
|
|
13279
13301
|
if (projectRuns.length === 0) {
|
|
13280
13302
|
return reply.send(emptyCitationVisibility("no-runs-yet"));
|
|
13281
13303
|
}
|
|
@@ -13431,7 +13453,7 @@ function normalizeDomain2(domain) {
|
|
|
13431
13453
|
}
|
|
13432
13454
|
|
|
13433
13455
|
// ../api-routes/src/visibility-stats.ts
|
|
13434
|
-
import { and as
|
|
13456
|
+
import { and as and14, desc as desc8, eq as eq17, inArray as inArray8 } from "drizzle-orm";
|
|
13435
13457
|
function round42(value) {
|
|
13436
13458
|
return Math.round(value * 1e4) / 1e4;
|
|
13437
13459
|
}
|
|
@@ -13583,7 +13605,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
13583
13605
|
lastRuns = n;
|
|
13584
13606
|
}
|
|
13585
13607
|
const projectQueries = app.db.select({ id: queries.id, query: queries.query }).from(queries).where(eq17(queries.projectId, project.id)).all();
|
|
13586
|
-
let projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(
|
|
13608
|
+
let projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(and14(eq17(runs.projectId, project.id), eq17(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc8(runs.createdAt)).all().filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial);
|
|
13587
13609
|
if (sinceMs !== null) projectRuns = projectRuns.filter((r) => Date.parse(r.createdAt) >= sinceMs);
|
|
13588
13610
|
if (untilMs !== null) projectRuns = projectRuns.filter((r) => Date.parse(r.createdAt) <= untilMs);
|
|
13589
13611
|
if (lastRuns !== null) projectRuns = projectRuns.slice(0, lastRuns);
|
|
@@ -13653,7 +13675,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
13653
13675
|
}
|
|
13654
13676
|
|
|
13655
13677
|
// ../api-routes/src/composites.ts
|
|
13656
|
-
import { eq as eq18, and as
|
|
13678
|
+
import { eq as eq18, and as and15, desc as desc9, sql as sql8, like as like2, or as or4, inArray as inArray9 } from "drizzle-orm";
|
|
13657
13679
|
var TOP_INSIGHT_LIMIT = 5;
|
|
13658
13680
|
var SEARCH_HIT_HARD_LIMIT = 50;
|
|
13659
13681
|
var SEARCH_SNIPPET_RADIUS = 80;
|
|
@@ -13671,7 +13693,7 @@ async function compositeRoutes(app) {
|
|
|
13671
13693
|
const project = resolveProject(app.db, request.params.name);
|
|
13672
13694
|
const filterLocation = (request.query.location ?? "").trim() || null;
|
|
13673
13695
|
const sinceIso = parseSinceFilter(request.query.since);
|
|
13674
|
-
const allRunsRaw = app.db.select().from(runs).where(
|
|
13696
|
+
const allRunsRaw = app.db.select().from(runs).where(and15(eq18(runs.projectId, project.id), notProbeRun())).orderBy(desc9(runs.createdAt), desc9(runs.id)).all();
|
|
13675
13697
|
const allRuns = allRunsRaw.filter((r) => runMatchesFilters(r, filterLocation, sinceIso));
|
|
13676
13698
|
const totalRuns = allRuns.length;
|
|
13677
13699
|
const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
|
|
@@ -13827,7 +13849,7 @@ async function compositeRoutes(app) {
|
|
|
13827
13849
|
rawResponse: querySnapshots.rawResponse,
|
|
13828
13850
|
createdAt: querySnapshots.createdAt
|
|
13829
13851
|
}).from(querySnapshots).innerJoin(queries, eq18(querySnapshots.queryId, queries.id)).where(
|
|
13830
|
-
|
|
13852
|
+
and15(
|
|
13831
13853
|
eq18(queries.projectId, project.id),
|
|
13832
13854
|
or4(
|
|
13833
13855
|
sql8`${querySnapshots.answerText} LIKE ${pattern} ESCAPE '\\'`,
|
|
@@ -13838,7 +13860,7 @@ async function compositeRoutes(app) {
|
|
|
13838
13860
|
)
|
|
13839
13861
|
).orderBy(desc9(querySnapshots.createdAt)).limit(limit + 1).all());
|
|
13840
13862
|
const insightMatches = app.db.select().from(insights).where(
|
|
13841
|
-
|
|
13863
|
+
and15(
|
|
13842
13864
|
eq18(insights.projectId, project.id),
|
|
13843
13865
|
or4(
|
|
13844
13866
|
like2(insights.title, pattern),
|
|
@@ -14055,7 +14077,7 @@ function buildSuggestedQueriesFromGsc(app, projectId, trackedQueries) {
|
|
|
14055
14077
|
// NULLIF guards the degenerate impressions=0 case (SQLite returns NULL,
|
|
14056
14078
|
// which the JS coerces to 0 — caught by the impression floor anyway).
|
|
14057
14079
|
avgPosition: sql8`COALESCE(SUM(${gscSearchData.position} * ${gscSearchData.impressions}) * 1.0 / NULLIF(SUM(${gscSearchData.impressions}), 0), 0)`
|
|
14058
|
-
}).from(gscSearchData).where(
|
|
14080
|
+
}).from(gscSearchData).where(and15(
|
|
14059
14081
|
eq18(gscSearchData.projectId, projectId),
|
|
14060
14082
|
sql8`${gscSearchData.date} >= ${cutoff}`,
|
|
14061
14083
|
sql8`${gscSearchData.impressions} > 0`
|
|
@@ -14570,6 +14592,13 @@ var queryIdParameter = {
|
|
|
14570
14592
|
description: "Query ID.",
|
|
14571
14593
|
schema: stringSchema
|
|
14572
14594
|
};
|
|
14595
|
+
var competitorIdParameter = {
|
|
14596
|
+
name: "id",
|
|
14597
|
+
in: "path",
|
|
14598
|
+
required: true,
|
|
14599
|
+
description: "Competitor ID.",
|
|
14600
|
+
schema: stringSchema
|
|
14601
|
+
};
|
|
14573
14602
|
var notificationIdParameter = {
|
|
14574
14603
|
name: "id",
|
|
14575
14604
|
in: "path",
|
|
@@ -15258,6 +15287,17 @@ var routeCatalog = [
|
|
|
15258
15287
|
400: errorResponse("Invalid competitor delete request.")
|
|
15259
15288
|
}
|
|
15260
15289
|
},
|
|
15290
|
+
{
|
|
15291
|
+
method: "delete",
|
|
15292
|
+
path: "/api/v1/projects/{name}/competitors/{id}",
|
|
15293
|
+
summary: "Delete competitor",
|
|
15294
|
+
tags: ["competitors"],
|
|
15295
|
+
parameters: [nameParameter, competitorIdParameter],
|
|
15296
|
+
responses: {
|
|
15297
|
+
204: { description: "Competitor deleted." },
|
|
15298
|
+
404: errorResponse("Project or competitor not found.")
|
|
15299
|
+
}
|
|
15300
|
+
},
|
|
15261
15301
|
{
|
|
15262
15302
|
method: "post",
|
|
15263
15303
|
path: "/api/v1/projects/{name}/runs",
|
|
@@ -18979,7 +19019,7 @@ async function telemetryRoutes(app, opts) {
|
|
|
18979
19019
|
|
|
18980
19020
|
// ../api-routes/src/schedules.ts
|
|
18981
19021
|
import crypto13 from "crypto";
|
|
18982
|
-
import { and as
|
|
19022
|
+
import { and as and16, eq as eq20 } from "drizzle-orm";
|
|
18983
19023
|
function parseKindParam(raw) {
|
|
18984
19024
|
if (raw === void 0 || raw === null || raw === "") return SchedulableRunKinds["answer-visibility"];
|
|
18985
19025
|
const parsed = schedulableRunKindSchema.safeParse(raw);
|
|
@@ -19051,7 +19091,7 @@ async function scheduleRoutes(app, opts) {
|
|
|
19051
19091
|
}
|
|
19052
19092
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
19053
19093
|
const enabledBool = enabled !== false;
|
|
19054
|
-
const existing = app.db.select().from(schedules).where(
|
|
19094
|
+
const existing = app.db.select().from(schedules).where(and16(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
|
|
19055
19095
|
if (existing) {
|
|
19056
19096
|
app.db.update(schedules).set({
|
|
19057
19097
|
cronExpr,
|
|
@@ -19085,13 +19125,13 @@ async function scheduleRoutes(app, opts) {
|
|
|
19085
19125
|
diff: { kind, cronExpr, preset, timezone, providers, sourceId }
|
|
19086
19126
|
});
|
|
19087
19127
|
opts.onScheduleUpdated?.("upsert", project.id, kind);
|
|
19088
|
-
const schedule = app.db.select().from(schedules).where(
|
|
19128
|
+
const schedule = app.db.select().from(schedules).where(and16(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
|
|
19089
19129
|
return reply.status(existing ? 200 : 201).send(formatSchedule(schedule));
|
|
19090
19130
|
});
|
|
19091
19131
|
app.get("/projects/:name/schedule", async (request, reply) => {
|
|
19092
19132
|
const project = resolveProject(app.db, request.params.name);
|
|
19093
19133
|
const kind = parseKindParam(request.query?.kind);
|
|
19094
|
-
const schedule = app.db.select().from(schedules).where(
|
|
19134
|
+
const schedule = app.db.select().from(schedules).where(and16(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
|
|
19095
19135
|
if (!schedule) {
|
|
19096
19136
|
throw notFound("Schedule", `${request.params.name} (kind=${kind})`);
|
|
19097
19137
|
}
|
|
@@ -19100,7 +19140,7 @@ async function scheduleRoutes(app, opts) {
|
|
|
19100
19140
|
app.delete("/projects/:name/schedule", async (request, reply) => {
|
|
19101
19141
|
const project = resolveProject(app.db, request.params.name);
|
|
19102
19142
|
const kind = parseKindParam(request.query?.kind);
|
|
19103
|
-
const schedule = app.db.select().from(schedules).where(
|
|
19143
|
+
const schedule = app.db.select().from(schedules).where(and16(eq20(schedules.projectId, project.id), eq20(schedules.kind, kind))).get();
|
|
19104
19144
|
if (!schedule) {
|
|
19105
19145
|
throw notFound("Schedule", `${request.params.name} (kind=${kind})`);
|
|
19106
19146
|
}
|
|
@@ -19257,7 +19297,7 @@ function formatNotification(row) {
|
|
|
19257
19297
|
|
|
19258
19298
|
// ../api-routes/src/google.ts
|
|
19259
19299
|
import crypto18 from "crypto";
|
|
19260
|
-
import { eq as eq22, and as
|
|
19300
|
+
import { eq as eq22, and as and17, desc as desc11, sql as sql9, inArray as inArray10 } from "drizzle-orm";
|
|
19261
19301
|
|
|
19262
19302
|
// ../api-routes/src/gbp-summary.ts
|
|
19263
19303
|
function computeMetricTotals(rows) {
|
|
@@ -21237,7 +21277,7 @@ async function googleRoutes(app, opts) {
|
|
|
21237
21277
|
if (page) conditions.push(sql9`${gscSearchData.page} LIKE ${"%" + escapeLikePattern(page) + "%"} ESCAPE '\\'`);
|
|
21238
21278
|
const limitVal = Math.max(parseInt(limit ?? "500", 10) || 0, 1);
|
|
21239
21279
|
const offsetVal = Math.max(parseInt(offset ?? "0", 10) || 0, 0);
|
|
21240
|
-
const rows = app.db.select().from(gscSearchData).where(
|
|
21280
|
+
const rows = app.db.select().from(gscSearchData).where(and17(...conditions)).orderBy(desc11(gscSearchData.date)).limit(limitVal).offset(offsetVal).all();
|
|
21241
21281
|
return rows.map((r) => ({
|
|
21242
21282
|
date: r.date,
|
|
21243
21283
|
query: r.query,
|
|
@@ -21265,7 +21305,7 @@ async function googleRoutes(app, opts) {
|
|
|
21265
21305
|
date: gscSearchData.date,
|
|
21266
21306
|
clicks: sql9`COALESCE(SUM(${gscSearchData.clicks}), 0)`,
|
|
21267
21307
|
impressions: sql9`COALESCE(SUM(${gscSearchData.impressions}), 0)`
|
|
21268
|
-
}).from(gscSearchData).where(
|
|
21308
|
+
}).from(gscSearchData).where(and17(...conditions)).groupBy(gscSearchData.date).orderBy(gscSearchData.date).all();
|
|
21269
21309
|
const daily = mergeGscDailyTotalsWithFallback(
|
|
21270
21310
|
dailyTotals,
|
|
21271
21311
|
dimensionedRows.map((r) => ({
|
|
@@ -21358,7 +21398,7 @@ async function googleRoutes(app, opts) {
|
|
|
21358
21398
|
const { url, limit } = request.query;
|
|
21359
21399
|
const conditions = [eq22(gscUrlInspections.projectId, project.id)];
|
|
21360
21400
|
if (url) conditions.push(eq22(gscUrlInspections.url, url));
|
|
21361
|
-
const rows = app.db.select().from(gscUrlInspections).where(
|
|
21401
|
+
const rows = app.db.select().from(gscUrlInspections).where(and17(...conditions)).orderBy(desc11(gscUrlInspections.inspectedAt)).limit(parseInt(limit ?? "100", 10)).all();
|
|
21362
21402
|
return rows.map((r) => ({
|
|
21363
21403
|
id: r.id,
|
|
21364
21404
|
url: r.url,
|
|
@@ -21853,7 +21893,7 @@ async function googleRoutes(app, opts) {
|
|
|
21853
21893
|
app.db.transaction((tx) => {
|
|
21854
21894
|
if (switching) clearGbpProjectData(tx, project.id);
|
|
21855
21895
|
for (const remote of remoteLocations) {
|
|
21856
|
-
const existing = tx.select().from(gbpLocations).where(
|
|
21896
|
+
const existing = tx.select().from(gbpLocations).where(and17(eq22(gbpLocations.projectId, project.id), eq22(gbpLocations.locationName, remote.name))).get();
|
|
21857
21897
|
const profile = buildLocationProfileFields(remote);
|
|
21858
21898
|
if (existing) {
|
|
21859
21899
|
tx.update(gbpLocations).set({
|
|
@@ -21950,7 +21990,7 @@ async function googleRoutes(app, opts) {
|
|
|
21950
21990
|
throw validationError(parsed.error.issues[0]?.message ?? "Invalid selection request");
|
|
21951
21991
|
}
|
|
21952
21992
|
const { selected } = parsed.data;
|
|
21953
|
-
const existing = app.db.select().from(gbpLocations).where(
|
|
21993
|
+
const existing = app.db.select().from(gbpLocations).where(and17(eq22(gbpLocations.projectId, project.id), eq22(gbpLocations.locationName, locationName))).get();
|
|
21954
21994
|
if (!existing) throw notFound("GBP location", locationName);
|
|
21955
21995
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21956
21996
|
app.db.transaction((tx) => {
|
|
@@ -22010,7 +22050,7 @@ async function googleRoutes(app, opts) {
|
|
|
22010
22050
|
const conditions = [eq22(gbpDailyMetrics.projectId, project.id)];
|
|
22011
22051
|
if (request.query.locationName) conditions.push(eq22(gbpDailyMetrics.locationName, request.query.locationName));
|
|
22012
22052
|
if (request.query.metric) conditions.push(eq22(gbpDailyMetrics.metric, request.query.metric));
|
|
22013
|
-
const rows = app.db.select().from(gbpDailyMetrics).where(
|
|
22053
|
+
const rows = app.db.select().from(gbpDailyMetrics).where(and17(...conditions)).orderBy(desc11(gbpDailyMetrics.date)).all();
|
|
22014
22054
|
return {
|
|
22015
22055
|
metrics: rows.map((r) => ({ locationName: r.locationName, date: r.date, metric: r.metric, value: r.value })),
|
|
22016
22056
|
total: rows.length
|
|
@@ -22020,7 +22060,7 @@ async function googleRoutes(app, opts) {
|
|
|
22020
22060
|
const project = resolveProject(app.db, request.params.name);
|
|
22021
22061
|
const conditions = [eq22(gbpKeywordImpressions.projectId, project.id)];
|
|
22022
22062
|
if (request.query.locationName) conditions.push(eq22(gbpKeywordImpressions.locationName, request.query.locationName));
|
|
22023
|
-
const rows = app.db.select().from(gbpKeywordImpressions).where(
|
|
22063
|
+
const rows = app.db.select().from(gbpKeywordImpressions).where(and17(...conditions)).all();
|
|
22024
22064
|
rows.sort((a, b) => (b.valueCount ?? -1) - (a.valueCount ?? -1));
|
|
22025
22065
|
const thresholded = rows.filter((r) => r.valueThreshold !== null).length;
|
|
22026
22066
|
return {
|
|
@@ -22040,7 +22080,7 @@ async function googleRoutes(app, opts) {
|
|
|
22040
22080
|
const project = resolveProject(app.db, request.params.name);
|
|
22041
22081
|
const conditions = [eq22(gbpPlaceActions.projectId, project.id)];
|
|
22042
22082
|
if (request.query.locationName) conditions.push(eq22(gbpPlaceActions.locationName, request.query.locationName));
|
|
22043
|
-
const rows = app.db.select().from(gbpPlaceActions).where(
|
|
22083
|
+
const rows = app.db.select().from(gbpPlaceActions).where(and17(...conditions)).all();
|
|
22044
22084
|
return {
|
|
22045
22085
|
placeActions: rows.map((r) => ({
|
|
22046
22086
|
locationName: r.locationName,
|
|
@@ -22057,7 +22097,7 @@ async function googleRoutes(app, opts) {
|
|
|
22057
22097
|
const project = resolveProject(app.db, request.params.name);
|
|
22058
22098
|
const conditions = [eq22(gbpLodgingSnapshots.projectId, project.id)];
|
|
22059
22099
|
if (request.query.locationName) conditions.push(eq22(gbpLodgingSnapshots.locationName, request.query.locationName));
|
|
22060
|
-
const rows = app.db.select().from(gbpLodgingSnapshots).where(
|
|
22100
|
+
const rows = app.db.select().from(gbpLodgingSnapshots).where(and17(...conditions)).orderBy(desc11(gbpLodgingSnapshots.syncedAt)).all();
|
|
22061
22101
|
const latestByLocation = /* @__PURE__ */ new Map();
|
|
22062
22102
|
for (const row of rows) {
|
|
22063
22103
|
if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
|
|
@@ -22074,7 +22114,7 @@ async function googleRoutes(app, opts) {
|
|
|
22074
22114
|
const project = resolveProject(app.db, request.params.name);
|
|
22075
22115
|
const conditions = [eq22(gbpAttributesSnapshots.projectId, project.id)];
|
|
22076
22116
|
if (request.query.locationName) conditions.push(eq22(gbpAttributesSnapshots.locationName, request.query.locationName));
|
|
22077
|
-
const rows = app.db.select().from(gbpAttributesSnapshots).where(
|
|
22117
|
+
const rows = app.db.select().from(gbpAttributesSnapshots).where(and17(...conditions)).orderBy(desc11(gbpAttributesSnapshots.syncedAt)).all();
|
|
22078
22118
|
const latestByLocation = /* @__PURE__ */ new Map();
|
|
22079
22119
|
for (const row of rows) {
|
|
22080
22120
|
if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
|
|
@@ -22094,7 +22134,7 @@ async function googleRoutes(app, opts) {
|
|
|
22094
22134
|
const project = resolveProject(app.db, request.params.name);
|
|
22095
22135
|
const conditions = [eq22(gbpPlaceDetails.projectId, project.id)];
|
|
22096
22136
|
if (request.query.locationName) conditions.push(eq22(gbpPlaceDetails.locationName, request.query.locationName));
|
|
22097
|
-
const rows = app.db.select().from(gbpPlaceDetails).where(
|
|
22137
|
+
const rows = app.db.select().from(gbpPlaceDetails).where(and17(...conditions)).orderBy(desc11(gbpPlaceDetails.syncedAt)).all();
|
|
22098
22138
|
const latestByLocation = /* @__PURE__ */ new Map();
|
|
22099
22139
|
for (const row of rows) {
|
|
22100
22140
|
if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
|
|
@@ -22113,7 +22153,7 @@ async function googleRoutes(app, opts) {
|
|
|
22113
22153
|
app.get("/projects/:name/gbp/summary", async (request) => {
|
|
22114
22154
|
const project = resolveProject(app.db, request.params.name);
|
|
22115
22155
|
const locationName = request.query.locationName ?? null;
|
|
22116
|
-
const locationNames = locationName ? [locationName] : app.db.select({ n: gbpLocations.locationName }).from(gbpLocations).where(
|
|
22156
|
+
const locationNames = locationName ? [locationName] : app.db.select({ n: gbpLocations.locationName }).from(gbpLocations).where(and17(eq22(gbpLocations.projectId, project.id), eq22(gbpLocations.selected, true))).all().map((r) => r.n);
|
|
22117
22157
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
22118
22158
|
if (locationNames.length === 0) {
|
|
22119
22159
|
return buildGbpSummary({
|
|
@@ -22127,10 +22167,10 @@ async function googleRoutes(app, opts) {
|
|
|
22127
22167
|
locationProfiles: []
|
|
22128
22168
|
});
|
|
22129
22169
|
}
|
|
22130
|
-
const metricRows = app.db.select().from(gbpDailyMetrics).where(
|
|
22131
|
-
const keywordRows = app.db.select().from(gbpKeywordImpressions).where(
|
|
22132
|
-
const placeActionRows = app.db.select().from(gbpPlaceActions).where(
|
|
22133
|
-
const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(
|
|
22170
|
+
const metricRows = app.db.select().from(gbpDailyMetrics).where(and17(eq22(gbpDailyMetrics.projectId, project.id), inArray10(gbpDailyMetrics.locationName, locationNames))).all();
|
|
22171
|
+
const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and17(eq22(gbpKeywordImpressions.projectId, project.id), inArray10(gbpKeywordImpressions.locationName, locationNames))).all();
|
|
22172
|
+
const placeActionRows = app.db.select().from(gbpPlaceActions).where(and17(eq22(gbpPlaceActions.projectId, project.id), inArray10(gbpPlaceActions.locationName, locationNames))).all();
|
|
22173
|
+
const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and17(eq22(gbpLodgingSnapshots.projectId, project.id), inArray10(gbpLodgingSnapshots.locationName, locationNames))).orderBy(desc11(gbpLodgingSnapshots.syncedAt)).all();
|
|
22134
22174
|
const latestLodgingByLocation = /* @__PURE__ */ new Map();
|
|
22135
22175
|
for (const row of lodgingRows) {
|
|
22136
22176
|
if (!latestLodgingByLocation.has(row.locationName)) {
|
|
@@ -22144,7 +22184,7 @@ async function googleRoutes(app, opts) {
|
|
|
22144
22184
|
regularHours: gbpLocations.regularHours,
|
|
22145
22185
|
primaryPhone: gbpLocations.primaryPhone,
|
|
22146
22186
|
openStatus: gbpLocations.openStatus
|
|
22147
|
-
}).from(gbpLocations).where(
|
|
22187
|
+
}).from(gbpLocations).where(and17(eq22(gbpLocations.projectId, project.id), inArray10(gbpLocations.locationName, locationNames))).all();
|
|
22148
22188
|
return buildGbpSummary({
|
|
22149
22189
|
locationName,
|
|
22150
22190
|
locationCount: locationNames.length,
|
|
@@ -22160,7 +22200,7 @@ async function googleRoutes(app, opts) {
|
|
|
22160
22200
|
|
|
22161
22201
|
// ../api-routes/src/ads.ts
|
|
22162
22202
|
import crypto19 from "crypto";
|
|
22163
|
-
import { eq as eq23, and as
|
|
22203
|
+
import { eq as eq23, and as and18, asc as asc3, gte as gte3, lte as lte2, inArray as inArray11 } from "drizzle-orm";
|
|
22164
22204
|
function statusDto(row) {
|
|
22165
22205
|
if (!row) return { connected: false };
|
|
22166
22206
|
return {
|
|
@@ -22276,7 +22316,7 @@ async function adsRoutes(app, opts) {
|
|
|
22276
22316
|
if (!row) {
|
|
22277
22317
|
throw validationError('No ads connection for this project. Run "canonry ads connect" first.');
|
|
22278
22318
|
}
|
|
22279
|
-
const inFlight = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(
|
|
22319
|
+
const inFlight = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and18(
|
|
22280
22320
|
eq23(runs.projectId, project.id),
|
|
22281
22321
|
eq23(runs.kind, RunKinds["ads-sync"]),
|
|
22282
22322
|
inArray11(runs.status, [RunStatuses.queued, RunStatuses.running])
|
|
@@ -22361,7 +22401,7 @@ async function adsRoutes(app, opts) {
|
|
|
22361
22401
|
if (entityId) conditions.push(eq23(adsInsightsDaily.entityId, entityId));
|
|
22362
22402
|
if (from) conditions.push(gte3(adsInsightsDaily.date, from));
|
|
22363
22403
|
if (to) conditions.push(lte2(adsInsightsDaily.date, to));
|
|
22364
|
-
const rows = app.db.select().from(adsInsightsDaily).where(
|
|
22404
|
+
const rows = app.db.select().from(adsInsightsDaily).where(and18(...conditions)).orderBy(asc3(adsInsightsDaily.date)).all();
|
|
22365
22405
|
const dtoRows = rows.map((row) => ({
|
|
22366
22406
|
level: row.level,
|
|
22367
22407
|
entityId: row.entityId,
|
|
@@ -22383,7 +22423,7 @@ async function adsRoutes(app, opts) {
|
|
|
22383
22423
|
const campaignCount = app.db.select().from(adsCampaigns).where(eq23(adsCampaigns.projectId, project.id)).all().length;
|
|
22384
22424
|
const adGroupCount = app.db.select().from(adsAdGroups).where(eq23(adsAdGroups.projectId, project.id)).all().length;
|
|
22385
22425
|
const adCount = app.db.select().from(adsAds).where(eq23(adsAds.projectId, project.id)).all().length;
|
|
22386
|
-
const campaignInsights = app.db.select().from(adsInsightsDaily).where(
|
|
22426
|
+
const campaignInsights = app.db.select().from(adsInsightsDaily).where(and18(
|
|
22387
22427
|
eq23(adsInsightsDaily.projectId, project.id),
|
|
22388
22428
|
eq23(adsInsightsDaily.level, "campaign")
|
|
22389
22429
|
)).all();
|
|
@@ -22425,7 +22465,7 @@ async function adsRoutes(app, opts) {
|
|
|
22425
22465
|
|
|
22426
22466
|
// ../api-routes/src/bing.ts
|
|
22427
22467
|
import crypto20 from "crypto";
|
|
22428
|
-
import { eq as eq24, and as
|
|
22468
|
+
import { eq as eq24, and as and19, desc as desc12 } from "drizzle-orm";
|
|
22429
22469
|
|
|
22430
22470
|
// ../integration-bing/src/constants.ts
|
|
22431
22471
|
var BING_WMT_API_BASE = "https://ssl.bing.com/webmaster/api.svc/json";
|
|
@@ -22900,7 +22940,7 @@ async function bingRoutes(app, opts) {
|
|
|
22900
22940
|
requireConnectionStore();
|
|
22901
22941
|
const project = resolveProject(app.db, request.params.name);
|
|
22902
22942
|
const { url, limit } = request.query;
|
|
22903
|
-
const whereClause = url ?
|
|
22943
|
+
const whereClause = url ? and19(eq24(bingUrlInspections.projectId, project.id), eq24(bingUrlInspections.url, url)) : eq24(bingUrlInspections.projectId, project.id);
|
|
22904
22944
|
const filtered = app.db.select().from(bingUrlInspections).where(whereClause).orderBy(desc12(bingUrlInspections.inspectedAt)).limit(Math.max(1, Math.min(parseInt(limit ?? "100", 10) || 100, 1e3))).all();
|
|
22905
22945
|
return filtered.map((r) => ({
|
|
22906
22946
|
id: r.id,
|
|
@@ -23132,7 +23172,7 @@ async function bingRoutes(app, opts) {
|
|
|
23132
23172
|
import fs from "fs";
|
|
23133
23173
|
import path from "path";
|
|
23134
23174
|
import os from "os";
|
|
23135
|
-
import { eq as eq25, and as
|
|
23175
|
+
import { eq as eq25, and as and20 } from "drizzle-orm";
|
|
23136
23176
|
function getScreenshotDir() {
|
|
23137
23177
|
return path.join(os.homedir(), ".canonry", "screenshots");
|
|
23138
23178
|
}
|
|
@@ -23207,7 +23247,7 @@ async function cdpRoutes(app, opts) {
|
|
|
23207
23247
|
async (request, reply) => {
|
|
23208
23248
|
const project = resolveProject(app.db, request.params.name);
|
|
23209
23249
|
const { runId } = request.params;
|
|
23210
|
-
const run = app.db.select().from(runs).where(
|
|
23250
|
+
const run = app.db.select().from(runs).where(and20(eq25(runs.id, runId), eq25(runs.projectId, project.id))).get();
|
|
23211
23251
|
if (!run) {
|
|
23212
23252
|
const err = notFound("Run", runId);
|
|
23213
23253
|
return reply.code(err.statusCode).send(err.toJSON());
|
|
@@ -23304,7 +23344,7 @@ async function cdpRoutes(app, opts) {
|
|
|
23304
23344
|
|
|
23305
23345
|
// ../api-routes/src/ga.ts
|
|
23306
23346
|
import crypto21 from "crypto";
|
|
23307
|
-
import { eq as eq26, desc as desc13, and as
|
|
23347
|
+
import { eq as eq26, desc as desc13, and as and21, sql as sql10 } from "drizzle-orm";
|
|
23308
23348
|
function gaLog(level, action, ctx) {
|
|
23309
23349
|
const entry = { ts: (/* @__PURE__ */ new Date()).toISOString(), level, module: "GA4Routes", action, ...ctx };
|
|
23310
23350
|
const stream = level === "error" ? process.stderr : process.stdout;
|
|
@@ -23599,7 +23639,7 @@ async function ga4Routes(app, opts) {
|
|
|
23599
23639
|
app.db.transaction((tx) => {
|
|
23600
23640
|
if (syncTraffic) {
|
|
23601
23641
|
tx.delete(gaTrafficSnapshots).where(
|
|
23602
|
-
|
|
23642
|
+
and21(
|
|
23603
23643
|
eq26(gaTrafficSnapshots.projectId, project.id),
|
|
23604
23644
|
sql10`${gaTrafficSnapshots.date} >= ${summary.periodStart}`,
|
|
23605
23645
|
sql10`${gaTrafficSnapshots.date} <= ${summary.periodEnd}`
|
|
@@ -23623,7 +23663,7 @@ async function ga4Routes(app, opts) {
|
|
|
23623
23663
|
}
|
|
23624
23664
|
if (syncAi) {
|
|
23625
23665
|
tx.delete(gaAiReferrals).where(
|
|
23626
|
-
|
|
23666
|
+
and21(
|
|
23627
23667
|
eq26(gaAiReferrals.projectId, project.id),
|
|
23628
23668
|
sql10`${gaAiReferrals.date} >= ${summary.periodStart}`,
|
|
23629
23669
|
sql10`${gaAiReferrals.date} <= ${summary.periodEnd}`
|
|
@@ -23649,7 +23689,7 @@ async function ga4Routes(app, opts) {
|
|
|
23649
23689
|
}
|
|
23650
23690
|
if (syncSocial) {
|
|
23651
23691
|
tx.delete(gaSocialReferrals).where(
|
|
23652
|
-
|
|
23692
|
+
and21(
|
|
23653
23693
|
eq26(gaSocialReferrals.projectId, project.id),
|
|
23654
23694
|
sql10`${gaSocialReferrals.date} >= ${summary.periodStart}`,
|
|
23655
23695
|
sql10`${gaSocialReferrals.date} <= ${summary.periodEnd}`
|
|
@@ -23753,7 +23793,7 @@ async function ga4Routes(app, opts) {
|
|
|
23753
23793
|
totalDirectSessions: gaTrafficWindowSummaries.totalDirectSessions,
|
|
23754
23794
|
totalUsers: gaTrafficWindowSummaries.totalUsers
|
|
23755
23795
|
}).from(gaTrafficWindowSummaries).where(
|
|
23756
|
-
|
|
23796
|
+
and21(
|
|
23757
23797
|
eq26(gaTrafficWindowSummaries.projectId, project.id),
|
|
23758
23798
|
eq26(gaTrafficWindowSummaries.windowKey, window)
|
|
23759
23799
|
)
|
|
@@ -23762,7 +23802,7 @@ async function ga4Routes(app, opts) {
|
|
|
23762
23802
|
totalSessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)`,
|
|
23763
23803
|
totalOrganicSessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)`,
|
|
23764
23804
|
totalUsers: sql10`COALESCE(SUM(${gaTrafficSnapshots.users}), 0)`
|
|
23765
|
-
}).from(gaTrafficSnapshots).where(
|
|
23805
|
+
}).from(gaTrafficSnapshots).where(and21(...snapshotConditions)).get() : null;
|
|
23766
23806
|
const summaryRow = cutoffDate ? windowSummaryRow ?? snapshotTotalsRow : app.db.select({
|
|
23767
23807
|
totalSessions: gaTrafficSummaries.totalSessions,
|
|
23768
23808
|
totalOrganicSessions: gaTrafficSummaries.totalOrganicSessions,
|
|
@@ -23770,7 +23810,7 @@ async function ga4Routes(app, opts) {
|
|
|
23770
23810
|
}).from(gaTrafficSummaries).where(eq26(gaTrafficSummaries.projectId, project.id)).get();
|
|
23771
23811
|
const directTotalRow = windowSummaryRow ? { totalDirectSessions: windowSummaryRow.totalDirectSessions } : app.db.select({
|
|
23772
23812
|
totalDirectSessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`
|
|
23773
|
-
}).from(gaTrafficSnapshots).where(
|
|
23813
|
+
}).from(gaTrafficSnapshots).where(and21(...snapshotConditions)).get();
|
|
23774
23814
|
const summaryMeta = app.db.select({
|
|
23775
23815
|
periodStart: gaTrafficSummaries.periodStart,
|
|
23776
23816
|
periodEnd: gaTrafficSummaries.periodEnd
|
|
@@ -23781,14 +23821,14 @@ async function ga4Routes(app, opts) {
|
|
|
23781
23821
|
organicSessions: sql10`SUM(${gaTrafficSnapshots.organicSessions})`,
|
|
23782
23822
|
directSessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`,
|
|
23783
23823
|
users: sql10`SUM(${gaTrafficSnapshots.users})`
|
|
23784
|
-
}).from(gaTrafficSnapshots).where(
|
|
23824
|
+
}).from(gaTrafficSnapshots).where(and21(...snapshotConditions)).groupBy(sql10`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`).orderBy(sql10`SUM(${gaTrafficSnapshots.sessions}) DESC`).limit(limit).all();
|
|
23785
23825
|
const aiReferralRows = app.db.select({
|
|
23786
23826
|
source: gaAiReferrals.source,
|
|
23787
23827
|
medium: gaAiReferrals.medium,
|
|
23788
23828
|
sourceDimension: gaAiReferrals.sourceDimension,
|
|
23789
23829
|
sessions: sql10`SUM(${gaAiReferrals.sessions})`,
|
|
23790
23830
|
users: sql10`SUM(${gaAiReferrals.users})`
|
|
23791
|
-
}).from(gaAiReferrals).where(
|
|
23831
|
+
}).from(gaAiReferrals).where(and21(...aiConditions)).groupBy(gaAiReferrals.source, gaAiReferrals.medium, gaAiReferrals.sourceDimension).all();
|
|
23792
23832
|
const aiReferralLandingPageRows = app.db.select({
|
|
23793
23833
|
source: gaAiReferrals.source,
|
|
23794
23834
|
medium: gaAiReferrals.medium,
|
|
@@ -23796,7 +23836,7 @@ async function ga4Routes(app, opts) {
|
|
|
23796
23836
|
landingPage: sql10`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`,
|
|
23797
23837
|
sessions: sql10`SUM(${gaAiReferrals.sessions})`,
|
|
23798
23838
|
users: sql10`SUM(${gaAiReferrals.users})`
|
|
23799
|
-
}).from(gaAiReferrals).where(
|
|
23839
|
+
}).from(gaAiReferrals).where(and21(...aiConditions)).groupBy(
|
|
23800
23840
|
gaAiReferrals.source,
|
|
23801
23841
|
gaAiReferrals.medium,
|
|
23802
23842
|
gaAiReferrals.sourceDimension,
|
|
@@ -23833,7 +23873,7 @@ async function ga4Routes(app, opts) {
|
|
|
23833
23873
|
channelGroup: gaAiReferrals.channelGroup,
|
|
23834
23874
|
sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)`,
|
|
23835
23875
|
users: sql10`COALESCE(SUM(${gaAiReferrals.users}), 0)`
|
|
23836
|
-
}).from(gaAiReferrals).where(
|
|
23876
|
+
}).from(gaAiReferrals).where(and21(...aiConditions, eq26(gaAiReferrals.sourceDimension, "session"))).groupBy(gaAiReferrals.channelGroup).all();
|
|
23837
23877
|
const aiSessionsByChannelGroup = /* @__PURE__ */ new Map();
|
|
23838
23878
|
let aiBySessionUsers = 0;
|
|
23839
23879
|
for (const row of aiBySessionRows) {
|
|
@@ -23847,11 +23887,11 @@ async function ga4Routes(app, opts) {
|
|
|
23847
23887
|
channelGroup: gaSocialReferrals.channelGroup,
|
|
23848
23888
|
sessions: sql10`SUM(${gaSocialReferrals.sessions})`,
|
|
23849
23889
|
users: sql10`SUM(${gaSocialReferrals.users})`
|
|
23850
|
-
}).from(gaSocialReferrals).where(
|
|
23890
|
+
}).from(gaSocialReferrals).where(and21(...socialConditions)).groupBy(gaSocialReferrals.source, gaSocialReferrals.medium, gaSocialReferrals.channelGroup).orderBy(sql10`SUM(${gaSocialReferrals.sessions}) DESC`).all();
|
|
23851
23891
|
const socialTotals = app.db.select({
|
|
23852
23892
|
sessions: sql10`SUM(${gaSocialReferrals.sessions})`,
|
|
23853
23893
|
users: sql10`SUM(${gaSocialReferrals.users})`
|
|
23854
|
-
}).from(gaSocialReferrals).where(
|
|
23894
|
+
}).from(gaSocialReferrals).where(and21(...socialConditions)).get();
|
|
23855
23895
|
const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq26(gaTrafficSummaries.projectId, project.id)).orderBy(desc13(gaTrafficSummaries.syncedAt)).limit(1).get();
|
|
23856
23896
|
const total = summaryRow?.totalSessions ?? 0;
|
|
23857
23897
|
const totalDirectSessions = directTotalRow?.totalDirectSessions ?? 0;
|
|
@@ -23942,7 +23982,7 @@ async function ga4Routes(app, opts) {
|
|
|
23942
23982
|
sourceDimension: gaAiReferrals.sourceDimension,
|
|
23943
23983
|
sessions: sql10`SUM(${gaAiReferrals.sessions})`,
|
|
23944
23984
|
users: sql10`SUM(${gaAiReferrals.users})`
|
|
23945
|
-
}).from(gaAiReferrals).where(
|
|
23985
|
+
}).from(gaAiReferrals).where(and21(...conditions)).groupBy(
|
|
23946
23986
|
gaAiReferrals.date,
|
|
23947
23987
|
gaAiReferrals.source,
|
|
23948
23988
|
gaAiReferrals.medium,
|
|
@@ -23964,7 +24004,7 @@ async function ga4Routes(app, opts) {
|
|
|
23964
24004
|
channelGroup: gaSocialReferrals.channelGroup,
|
|
23965
24005
|
sessions: gaSocialReferrals.sessions,
|
|
23966
24006
|
users: gaSocialReferrals.users
|
|
23967
|
-
}).from(gaSocialReferrals).where(
|
|
24007
|
+
}).from(gaSocialReferrals).where(and21(...conditions)).orderBy(gaSocialReferrals.date).all();
|
|
23968
24008
|
return rows;
|
|
23969
24009
|
});
|
|
23970
24010
|
app.get("/projects/:name/ga/social-referral-trend", async (request, _reply) => {
|
|
@@ -23977,7 +24017,7 @@ async function ga4Routes(app, opts) {
|
|
|
23977
24017
|
d.setDate(d.getDate() - n);
|
|
23978
24018
|
return fmt(d);
|
|
23979
24019
|
};
|
|
23980
|
-
const sumSocial = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(
|
|
24020
|
+
const sumSocial = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and21(
|
|
23981
24021
|
eq26(gaSocialReferrals.projectId, project.id),
|
|
23982
24022
|
sql10`${gaSocialReferrals.date} >= ${from}`,
|
|
23983
24023
|
sql10`${gaSocialReferrals.date} < ${to}`
|
|
@@ -23990,7 +24030,7 @@ async function ga4Routes(app, opts) {
|
|
|
23990
24030
|
const sourceCurrent = app.db.select({
|
|
23991
24031
|
source: gaSocialReferrals.source,
|
|
23992
24032
|
sessions: sql10`SUM(${gaSocialReferrals.sessions})`
|
|
23993
|
-
}).from(gaSocialReferrals).where(
|
|
24033
|
+
}).from(gaSocialReferrals).where(and21(
|
|
23994
24034
|
eq26(gaSocialReferrals.projectId, project.id),
|
|
23995
24035
|
sql10`${gaSocialReferrals.date} >= ${daysAgo(7)}`,
|
|
23996
24036
|
sql10`${gaSocialReferrals.date} < ${fmt(today)}`
|
|
@@ -23998,7 +24038,7 @@ async function ga4Routes(app, opts) {
|
|
|
23998
24038
|
const sourcePrev = app.db.select({
|
|
23999
24039
|
source: gaSocialReferrals.source,
|
|
24000
24040
|
sessions: sql10`SUM(${gaSocialReferrals.sessions})`
|
|
24001
|
-
}).from(gaSocialReferrals).where(
|
|
24041
|
+
}).from(gaSocialReferrals).where(and21(
|
|
24002
24042
|
eq26(gaSocialReferrals.projectId, project.id),
|
|
24003
24043
|
sql10`${gaSocialReferrals.date} >= ${daysAgo(14)}`,
|
|
24004
24044
|
sql10`${gaSocialReferrals.date} < ${daysAgo(7)}`
|
|
@@ -24040,16 +24080,16 @@ async function ga4Routes(app, opts) {
|
|
|
24040
24080
|
return fmt(d);
|
|
24041
24081
|
};
|
|
24042
24082
|
const pct = (cur, prev) => prev === 0 ? null : Math.round((cur - prev) / prev * 100);
|
|
24043
|
-
const sumTotal = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)` }).from(gaTrafficSnapshots).where(
|
|
24044
|
-
const sumOrganic = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)` }).from(gaTrafficSnapshots).where(
|
|
24045
|
-
const sumDirect = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)` }).from(gaTrafficSnapshots).where(
|
|
24046
|
-
const sumAi = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(
|
|
24083
|
+
const sumTotal = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)` }).from(gaTrafficSnapshots).where(and21(eq26(gaTrafficSnapshots.projectId, project.id), sql10`${gaTrafficSnapshots.date} >= ${from}`, sql10`${gaTrafficSnapshots.date} < ${to}`)).get();
|
|
24084
|
+
const sumOrganic = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)` }).from(gaTrafficSnapshots).where(and21(eq26(gaTrafficSnapshots.projectId, project.id), sql10`${gaTrafficSnapshots.date} >= ${from}`, sql10`${gaTrafficSnapshots.date} < ${to}`)).get();
|
|
24085
|
+
const sumDirect = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)` }).from(gaTrafficSnapshots).where(and21(eq26(gaTrafficSnapshots.projectId, project.id), sql10`${gaTrafficSnapshots.date} >= ${from}`, sql10`${gaTrafficSnapshots.date} < ${to}`)).get();
|
|
24086
|
+
const sumAi = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and21(
|
|
24047
24087
|
eq26(gaAiReferrals.projectId, project.id),
|
|
24048
24088
|
sql10`${gaAiReferrals.date} >= ${from}`,
|
|
24049
24089
|
sql10`${gaAiReferrals.date} < ${to}`,
|
|
24050
24090
|
eq26(gaAiReferrals.sourceDimension, "session")
|
|
24051
24091
|
)).get();
|
|
24052
|
-
const sumSocial = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(
|
|
24092
|
+
const sumSocial = (from, to) => app.db.select({ sessions: sql10`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and21(eq26(gaSocialReferrals.projectId, project.id), sql10`${gaSocialReferrals.date} >= ${from}`, sql10`${gaSocialReferrals.date} < ${to}`)).get();
|
|
24053
24093
|
const todayStr = fmt(today);
|
|
24054
24094
|
const buildTrend = (sum) => {
|
|
24055
24095
|
const c7 = sum(daysAgo(7), todayStr)?.sessions ?? 0;
|
|
@@ -24058,13 +24098,13 @@ async function ga4Routes(app, opts) {
|
|
|
24058
24098
|
const p30 = sum(daysAgo(60), daysAgo(30))?.sessions ?? 0;
|
|
24059
24099
|
return { sessions7d: c7, sessionsPrev7d: p7, trend7dPct: pct(c7, p7), sessions30d: c30, sessionsPrev30d: p30, trend30dPct: pct(c30, p30) };
|
|
24060
24100
|
};
|
|
24061
|
-
const aiSourceCurrent = app.db.select({ source: gaAiReferrals.source, sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(
|
|
24101
|
+
const aiSourceCurrent = app.db.select({ source: gaAiReferrals.source, sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and21(
|
|
24062
24102
|
eq26(gaAiReferrals.projectId, project.id),
|
|
24063
24103
|
sql10`${gaAiReferrals.date} >= ${daysAgo(7)}`,
|
|
24064
24104
|
sql10`${gaAiReferrals.date} < ${todayStr}`,
|
|
24065
24105
|
eq26(gaAiReferrals.sourceDimension, "session")
|
|
24066
24106
|
)).groupBy(gaAiReferrals.source).all();
|
|
24067
|
-
const aiSourcePrev = app.db.select({ source: gaAiReferrals.source, sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(
|
|
24107
|
+
const aiSourcePrev = app.db.select({ source: gaAiReferrals.source, sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and21(
|
|
24068
24108
|
eq26(gaAiReferrals.projectId, project.id),
|
|
24069
24109
|
sql10`${gaAiReferrals.date} >= ${daysAgo(14)}`,
|
|
24070
24110
|
sql10`${gaAiReferrals.date} < ${daysAgo(7)}`,
|
|
@@ -24084,8 +24124,8 @@ async function ga4Routes(app, opts) {
|
|
|
24084
24124
|
}
|
|
24085
24125
|
return mover;
|
|
24086
24126
|
};
|
|
24087
|
-
const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions: sql10`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(
|
|
24088
|
-
const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions: sql10`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(
|
|
24127
|
+
const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions: sql10`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and21(eq26(gaSocialReferrals.projectId, project.id), sql10`${gaSocialReferrals.date} >= ${daysAgo(7)}`, sql10`${gaSocialReferrals.date} < ${todayStr}`)).groupBy(gaSocialReferrals.source).all();
|
|
24128
|
+
const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions: sql10`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and21(eq26(gaSocialReferrals.projectId, project.id), sql10`${gaSocialReferrals.date} >= ${daysAgo(14)}`, sql10`${gaSocialReferrals.date} < ${daysAgo(7)}`)).groupBy(gaSocialReferrals.source).all();
|
|
24089
24129
|
return {
|
|
24090
24130
|
total: buildTrend(sumTotal),
|
|
24091
24131
|
organic: buildTrend(sumOrganic),
|
|
@@ -24107,7 +24147,7 @@ async function ga4Routes(app, opts) {
|
|
|
24107
24147
|
sessions: sql10`SUM(${gaTrafficSnapshots.sessions})`,
|
|
24108
24148
|
organicSessions: sql10`SUM(${gaTrafficSnapshots.organicSessions})`,
|
|
24109
24149
|
users: sql10`SUM(${gaTrafficSnapshots.users})`
|
|
24110
|
-
}).from(gaTrafficSnapshots).where(
|
|
24150
|
+
}).from(gaTrafficSnapshots).where(and21(...conditions)).groupBy(gaTrafficSnapshots.date).orderBy(gaTrafficSnapshots.date).all();
|
|
24111
24151
|
return rows.map((r) => ({
|
|
24112
24152
|
date: r.date,
|
|
24113
24153
|
sessions: r.sessions ?? 0,
|
|
@@ -25771,7 +25811,7 @@ async function wordpressRoutes(app, opts) {
|
|
|
25771
25811
|
|
|
25772
25812
|
// ../api-routes/src/backlinks.ts
|
|
25773
25813
|
import crypto23 from "crypto";
|
|
25774
|
-
import { and as
|
|
25814
|
+
import { and as and23, asc as asc4, desc as desc14, eq as eq27, sql as sql11 } from "drizzle-orm";
|
|
25775
25815
|
|
|
25776
25816
|
// ../integration-commoncrawl/src/constants.ts
|
|
25777
25817
|
import os2 from "os";
|
|
@@ -26174,7 +26214,7 @@ function pruneCachedRelease(release, opts = {}) {
|
|
|
26174
26214
|
}
|
|
26175
26215
|
|
|
26176
26216
|
// ../api-routes/src/backlinks-filter.ts
|
|
26177
|
-
import { and as
|
|
26217
|
+
import { and as and22, ne as ne3, notLike } from "drizzle-orm";
|
|
26178
26218
|
var BACKLINK_FILTER_PATTERNS = [
|
|
26179
26219
|
"*.google.com",
|
|
26180
26220
|
"*.googleusercontent.com",
|
|
@@ -26197,7 +26237,7 @@ function backlinkCrawlerExclusionClause() {
|
|
|
26197
26237
|
conditions.push(ne3(backlinkDomains.linkingDomain, pattern));
|
|
26198
26238
|
}
|
|
26199
26239
|
}
|
|
26200
|
-
const combined =
|
|
26240
|
+
const combined = and22(...conditions);
|
|
26201
26241
|
if (!combined) throw new Error("BACKLINK_FILTER_PATTERNS is unexpectedly empty");
|
|
26202
26242
|
return combined;
|
|
26203
26243
|
}
|
|
@@ -26272,7 +26312,7 @@ function latestSummaryForProject(db, projectId, source, release) {
|
|
|
26272
26312
|
eq27(backlinkSummaries.source, source)
|
|
26273
26313
|
];
|
|
26274
26314
|
if (release) conditions.push(eq27(backlinkSummaries.release, release));
|
|
26275
|
-
return db.select().from(backlinkSummaries).where(
|
|
26315
|
+
return db.select().from(backlinkSummaries).where(and23(...conditions)).orderBy(desc14(backlinkSummaries.queriedAt)).limit(1).get();
|
|
26276
26316
|
}
|
|
26277
26317
|
function parseExcludeCrawlers(value) {
|
|
26278
26318
|
if (!value) return false;
|
|
@@ -26280,12 +26320,12 @@ function parseExcludeCrawlers(value) {
|
|
|
26280
26320
|
return lower === "1" || lower === "true" || lower === "yes";
|
|
26281
26321
|
}
|
|
26282
26322
|
function computeFilteredSummary(db, base) {
|
|
26283
|
-
const baseDomainCondition =
|
|
26323
|
+
const baseDomainCondition = and23(
|
|
26284
26324
|
eq27(backlinkDomains.projectId, base.projectId),
|
|
26285
26325
|
eq27(backlinkDomains.source, base.source),
|
|
26286
26326
|
eq27(backlinkDomains.release, base.release)
|
|
26287
26327
|
);
|
|
26288
|
-
const filteredCondition =
|
|
26328
|
+
const filteredCondition = and23(baseDomainCondition, backlinkCrawlerExclusionClause());
|
|
26289
26329
|
const unfilteredAgg = db.select({
|
|
26290
26330
|
count: sql11`count(*)`,
|
|
26291
26331
|
total: sql11`coalesce(sum(${backlinkDomains.numHosts}), 0)`
|
|
@@ -26315,10 +26355,10 @@ function computeFilteredSummary(db, base) {
|
|
|
26315
26355
|
};
|
|
26316
26356
|
}
|
|
26317
26357
|
function buildSourceAvailability(db, projectId, source, connected, excludeCrawlers) {
|
|
26318
|
-
const summary = db.select().from(backlinkSummaries).where(
|
|
26358
|
+
const summary = db.select().from(backlinkSummaries).where(and23(eq27(backlinkSummaries.projectId, projectId), eq27(backlinkSummaries.source, source))).orderBy(desc14(backlinkSummaries.queriedAt)).limit(1).get();
|
|
26319
26359
|
let totalLinkingDomains = summary?.totalLinkingDomains ?? 0;
|
|
26320
26360
|
if (summary && excludeCrawlers) {
|
|
26321
|
-
const filtered = db.select({ count: sql11`count(*)` }).from(backlinkDomains).where(
|
|
26361
|
+
const filtered = db.select({ count: sql11`count(*)` }).from(backlinkDomains).where(and23(
|
|
26322
26362
|
eq27(backlinkDomains.projectId, projectId),
|
|
26323
26363
|
eq27(backlinkDomains.source, source),
|
|
26324
26364
|
eq27(backlinkDomains.release, summary.release),
|
|
@@ -26501,12 +26541,12 @@ async function backlinksRoutes(app, opts) {
|
|
|
26501
26541
|
const limit = Math.min(Math.max(parseInt(request.query.limit ?? "50", 10) || 50, 1), 500);
|
|
26502
26542
|
const offset = Math.max(parseInt(request.query.offset ?? "0", 10) || 0, 0);
|
|
26503
26543
|
const excludeCrawlers = parseExcludeCrawlers(request.query.excludeCrawlers);
|
|
26504
|
-
const baseDomainCondition =
|
|
26544
|
+
const baseDomainCondition = and23(
|
|
26505
26545
|
eq27(backlinkDomains.projectId, project.id),
|
|
26506
26546
|
eq27(backlinkDomains.source, source),
|
|
26507
26547
|
eq27(backlinkDomains.release, targetRelease)
|
|
26508
26548
|
);
|
|
26509
|
-
const domainCondition = excludeCrawlers ?
|
|
26549
|
+
const domainCondition = excludeCrawlers ? and23(baseDomainCondition, backlinkCrawlerExclusionClause()) : baseDomainCondition;
|
|
26510
26550
|
const totalRow = app.db.select({ count: sql11`count(*)` }).from(backlinkDomains).where(domainCondition).get();
|
|
26511
26551
|
const rows = app.db.select({
|
|
26512
26552
|
linkingDomain: backlinkDomains.linkingDomain,
|
|
@@ -26530,7 +26570,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
26530
26570
|
async (request, reply) => {
|
|
26531
26571
|
const project = resolveProject(app.db, request.params.name);
|
|
26532
26572
|
const source = parseSourceParam(request.query.source);
|
|
26533
|
-
const rows = app.db.select().from(backlinkSummaries).where(
|
|
26573
|
+
const rows = app.db.select().from(backlinkSummaries).where(and23(eq27(backlinkSummaries.projectId, project.id), eq27(backlinkSummaries.source, source))).orderBy(asc4(backlinkSummaries.queriedAt)).all();
|
|
26534
26574
|
const response = rows.map((r) => ({
|
|
26535
26575
|
release: r.release,
|
|
26536
26576
|
totalLinkingDomains: r.totalLinkingDomains,
|
|
@@ -26586,7 +26626,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
26586
26626
|
// ../api-routes/src/traffic.ts
|
|
26587
26627
|
import crypto25 from "crypto";
|
|
26588
26628
|
import { Agent as UndiciAgent } from "undici";
|
|
26589
|
-
import { and as
|
|
26629
|
+
import { and as and24, desc as desc15, eq as eq28, gte as gte4, lte as lte3, sql as sql12 } from "drizzle-orm";
|
|
26590
26630
|
|
|
26591
26631
|
// ../integration-cloud-run/src/auth.ts
|
|
26592
26632
|
import crypto24 from "crypto";
|
|
@@ -30445,28 +30485,28 @@ async function runBackfillTask(options) {
|
|
|
30445
30485
|
try {
|
|
30446
30486
|
app.db.transaction((tx) => {
|
|
30447
30487
|
tx.delete(crawlerEventsHourly).where(
|
|
30448
|
-
|
|
30488
|
+
and24(
|
|
30449
30489
|
eq28(crawlerEventsHourly.sourceId, sourceRow.id),
|
|
30450
30490
|
gte4(crawlerEventsHourly.tsHour, windowStartIso),
|
|
30451
30491
|
lte3(crawlerEventsHourly.tsHour, windowEndIso)
|
|
30452
30492
|
)
|
|
30453
30493
|
).run();
|
|
30454
30494
|
tx.delete(aiUserFetchEventsHourly).where(
|
|
30455
|
-
|
|
30495
|
+
and24(
|
|
30456
30496
|
eq28(aiUserFetchEventsHourly.sourceId, sourceRow.id),
|
|
30457
30497
|
gte4(aiUserFetchEventsHourly.tsHour, windowStartIso),
|
|
30458
30498
|
lte3(aiUserFetchEventsHourly.tsHour, windowEndIso)
|
|
30459
30499
|
)
|
|
30460
30500
|
).run();
|
|
30461
30501
|
tx.delete(aiReferralEventsHourly).where(
|
|
30462
|
-
|
|
30502
|
+
and24(
|
|
30463
30503
|
eq28(aiReferralEventsHourly.sourceId, sourceRow.id),
|
|
30464
30504
|
gte4(aiReferralEventsHourly.tsHour, windowStartIso),
|
|
30465
30505
|
lte3(aiReferralEventsHourly.tsHour, windowEndIso)
|
|
30466
30506
|
)
|
|
30467
30507
|
).run();
|
|
30468
30508
|
tx.delete(rawEventSamples).where(
|
|
30469
|
-
|
|
30509
|
+
and24(
|
|
30470
30510
|
eq28(rawEventSamples.sourceId, sourceRow.id),
|
|
30471
30511
|
gte4(rawEventSamples.ts, windowStartIso),
|
|
30472
30512
|
lte3(rawEventSamples.ts, windowEndIso)
|
|
@@ -30849,7 +30889,7 @@ async function trafficRoutes(app, opts) {
|
|
|
30849
30889
|
row = tx.select().from(trafficSources).where(eq28(trafficSources.id, newId)).get();
|
|
30850
30890
|
}
|
|
30851
30891
|
const existingSchedule = tx.select().from(schedules).where(
|
|
30852
|
-
|
|
30892
|
+
and24(
|
|
30853
30893
|
eq28(schedules.projectId, project.id),
|
|
30854
30894
|
eq28(schedules.kind, SchedulableRunKinds["traffic-sync"])
|
|
30855
30895
|
)
|
|
@@ -31571,7 +31611,7 @@ async function trafficRoutes(app, opts) {
|
|
|
31571
31611
|
pathNormalized: crawlerEventsHourly.pathNormalized,
|
|
31572
31612
|
hits: sql12`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
31573
31613
|
}).from(crawlerEventsHourly).where(
|
|
31574
|
-
|
|
31614
|
+
and24(
|
|
31575
31615
|
eq28(crawlerEventsHourly.sourceId, row.id),
|
|
31576
31616
|
gte4(crawlerEventsHourly.tsHour, since)
|
|
31577
31617
|
)
|
|
@@ -31581,25 +31621,25 @@ async function trafficRoutes(app, opts) {
|
|
|
31581
31621
|
);
|
|
31582
31622
|
const crawlerTotal = crawlerSegments.content + crawlerSegments.sitemap + crawlerSegments.robots + crawlerSegments.asset + crawlerSegments.other;
|
|
31583
31623
|
const aiUserFetchTotals = app.db.select({ total: sql12`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
31584
|
-
|
|
31624
|
+
and24(
|
|
31585
31625
|
eq28(aiUserFetchEventsHourly.sourceId, row.id),
|
|
31586
31626
|
gte4(aiUserFetchEventsHourly.tsHour, since)
|
|
31587
31627
|
)
|
|
31588
31628
|
).get();
|
|
31589
31629
|
const aiTotals = app.db.select({ total: sql12`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
31590
|
-
|
|
31630
|
+
and24(
|
|
31591
31631
|
eq28(aiReferralEventsHourly.sourceId, row.id),
|
|
31592
31632
|
gte4(aiReferralEventsHourly.tsHour, since)
|
|
31593
31633
|
)
|
|
31594
31634
|
).get();
|
|
31595
31635
|
const sampleTotals = app.db.select({ total: sql12`COUNT(*)` }).from(rawEventSamples).where(
|
|
31596
|
-
|
|
31636
|
+
and24(
|
|
31597
31637
|
eq28(rawEventSamples.sourceId, row.id),
|
|
31598
31638
|
gte4(rawEventSamples.ts, since)
|
|
31599
31639
|
)
|
|
31600
31640
|
).get();
|
|
31601
31641
|
const latestRun = app.db.select().from(runs).where(
|
|
31602
|
-
|
|
31642
|
+
and24(
|
|
31603
31643
|
eq28(runs.projectId, projectId),
|
|
31604
31644
|
eq28(runs.kind, RunKinds["traffic-sync"]),
|
|
31605
31645
|
eq28(runs.sourceId, row.id)
|
|
@@ -31633,7 +31673,7 @@ async function trafficRoutes(app, opts) {
|
|
|
31633
31673
|
"`advanceToNow` must be `true`. There is no implicit reset."
|
|
31634
31674
|
);
|
|
31635
31675
|
}
|
|
31636
|
-
const sourceRow = app.db.select().from(trafficSources).where(
|
|
31676
|
+
const sourceRow = app.db.select().from(trafficSources).where(and24(eq28(trafficSources.projectId, project.id), eq28(trafficSources.id, request.params.id))).get();
|
|
31637
31677
|
if (!sourceRow) {
|
|
31638
31678
|
throw notFound("traffic source", request.params.id);
|
|
31639
31679
|
}
|
|
@@ -31738,7 +31778,7 @@ async function trafficRoutes(app, opts) {
|
|
|
31738
31778
|
lte3(crawlerEventsHourly.tsHour, untilIso)
|
|
31739
31779
|
];
|
|
31740
31780
|
if (sourceIdParam) crawlerFilters.push(eq28(crawlerEventsHourly.sourceId, sourceIdParam));
|
|
31741
|
-
const crawlerWhere =
|
|
31781
|
+
const crawlerWhere = and24(...crawlerFilters);
|
|
31742
31782
|
const pathTotals = app.db.select({
|
|
31743
31783
|
pathNormalized: crawlerEventsHourly.pathNormalized,
|
|
31744
31784
|
hits: sql12`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
@@ -31770,7 +31810,7 @@ async function trafficRoutes(app, opts) {
|
|
|
31770
31810
|
lte3(aiUserFetchEventsHourly.tsHour, untilIso)
|
|
31771
31811
|
];
|
|
31772
31812
|
if (sourceIdParam) userFetchFilters.push(eq28(aiUserFetchEventsHourly.sourceId, sourceIdParam));
|
|
31773
|
-
const userFetchWhere =
|
|
31813
|
+
const userFetchWhere = and24(...userFetchFilters);
|
|
31774
31814
|
const total = app.db.select({ total: sql12`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(userFetchWhere).get();
|
|
31775
31815
|
aiUserFetchTotal = Number(total?.total ?? 0);
|
|
31776
31816
|
const rows = app.db.select().from(aiUserFetchEventsHourly).where(userFetchWhere).orderBy(desc15(aiUserFetchEventsHourly.tsHour)).limit(limit).all();
|
|
@@ -31795,7 +31835,7 @@ async function trafficRoutes(app, opts) {
|
|
|
31795
31835
|
lte3(aiReferralEventsHourly.tsHour, untilIso)
|
|
31796
31836
|
];
|
|
31797
31837
|
if (sourceIdParam) aiFilters.push(eq28(aiReferralEventsHourly.sourceId, sourceIdParam));
|
|
31798
|
-
const aiWhere =
|
|
31838
|
+
const aiWhere = and24(...aiFilters);
|
|
31799
31839
|
const total = app.db.select({ total: sql12`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(aiWhere).get();
|
|
31800
31840
|
aiReferralTotal = Number(total?.total ?? 0);
|
|
31801
31841
|
const rows = app.db.select().from(aiReferralEventsHourly).where(aiWhere).orderBy(desc15(aiReferralEventsHourly.tsHour)).limit(limit).all();
|
|
@@ -32002,7 +32042,7 @@ function readInstalledManifest(skillDir) {
|
|
|
32002
32042
|
var AGENT_CHECKS = [skillsInstalledCheck, skillsCurrentCheck];
|
|
32003
32043
|
|
|
32004
32044
|
// ../api-routes/src/doctor/checks/backlinks.ts
|
|
32005
|
-
import { and as
|
|
32045
|
+
import { and as and25, eq as eq29 } from "drizzle-orm";
|
|
32006
32046
|
function skippedNoProject() {
|
|
32007
32047
|
return {
|
|
32008
32048
|
status: CheckStatuses.skipped,
|
|
@@ -32034,7 +32074,7 @@ var BACKLINKS_CHECKS = [
|
|
|
32034
32074
|
details: { commoncrawl: ccConnected, bingWebmaster: bingConnected }
|
|
32035
32075
|
};
|
|
32036
32076
|
}
|
|
32037
|
-
const ccHasData = ccConnected ? !!ctx.db.select({ id: backlinkSummaries.id }).from(backlinkSummaries).where(
|
|
32077
|
+
const ccHasData = ccConnected ? !!ctx.db.select({ id: backlinkSummaries.id }).from(backlinkSummaries).where(and25(
|
|
32038
32078
|
eq29(backlinkSummaries.projectId, ctx.project.id),
|
|
32039
32079
|
eq29(backlinkSummaries.source, BacklinkSources.commoncrawl)
|
|
32040
32080
|
)).limit(1).get() : false;
|
|
@@ -32559,7 +32599,7 @@ var ga4ConnectionCheck = {
|
|
|
32559
32599
|
var GA_AUTH_CHECKS = [ga4ConnectionCheck];
|
|
32560
32600
|
|
|
32561
32601
|
// ../api-routes/src/doctor/checks/gbp-auth.ts
|
|
32562
|
-
import { and as
|
|
32602
|
+
import { and as and26, eq as eq32 } from "drizzle-orm";
|
|
32563
32603
|
var RECENT_SYNC_WARN_DAYS2 = 7;
|
|
32564
32604
|
var RECENT_SYNC_FAIL_DAYS2 = 30;
|
|
32565
32605
|
function skippedNoProject3() {
|
|
@@ -32792,7 +32832,7 @@ var recentSyncCheck = {
|
|
|
32792
32832
|
title: "GBP recent sync",
|
|
32793
32833
|
run: (ctx) => {
|
|
32794
32834
|
if (!ctx.project) return skippedNoProject3();
|
|
32795
|
-
const selected = ctx.db.select({ locationName: gbpLocations.locationName, syncedAt: gbpLocations.syncedAt }).from(gbpLocations).where(
|
|
32835
|
+
const selected = ctx.db.select({ locationName: gbpLocations.locationName, syncedAt: gbpLocations.syncedAt }).from(gbpLocations).where(and26(eq32(gbpLocations.projectId, ctx.project.id), eq32(gbpLocations.selected, true))).all();
|
|
32796
32836
|
if (selected.length === 0) {
|
|
32797
32837
|
return {
|
|
32798
32838
|
status: CheckStatuses.skipped,
|
|
@@ -33394,7 +33434,7 @@ var RUNTIME_STATE_CHECKS = [
|
|
|
33394
33434
|
];
|
|
33395
33435
|
|
|
33396
33436
|
// ../api-routes/src/doctor/checks/traffic-source.ts
|
|
33397
|
-
import { and as
|
|
33437
|
+
import { and as and27, eq as eq34, gte as gte5, ne as ne4, sql as sql13 } from "drizzle-orm";
|
|
33398
33438
|
var RECENT_DATA_WARN_DAYS = 7;
|
|
33399
33439
|
var RECENT_DATA_FAIL_DAYS = 30;
|
|
33400
33440
|
function skippedNoProject5() {
|
|
@@ -33408,7 +33448,7 @@ function skippedNoProject5() {
|
|
|
33408
33448
|
function loadProbes(ctx) {
|
|
33409
33449
|
if (!ctx.project) return [];
|
|
33410
33450
|
const rows = ctx.db.select().from(trafficSources).where(
|
|
33411
|
-
|
|
33451
|
+
and27(
|
|
33412
33452
|
eq34(trafficSources.projectId, ctx.project.id),
|
|
33413
33453
|
ne4(trafficSources.status, TrafficSourceStatuses.archived)
|
|
33414
33454
|
)
|
|
@@ -33489,7 +33529,7 @@ var recentDataCheck = {
|
|
|
33489
33529
|
const failCutoff = new Date(now.getTime() - RECENT_DATA_FAIL_DAYS * 24 * 60 * 6e4).toISOString();
|
|
33490
33530
|
const recentCrawlers = Number(
|
|
33491
33531
|
ctx.db.select({ total: sql13`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
33492
|
-
|
|
33532
|
+
and27(
|
|
33493
33533
|
eq34(crawlerEventsHourly.projectId, ctx.project.id),
|
|
33494
33534
|
gte5(crawlerEventsHourly.tsHour, warnCutoff)
|
|
33495
33535
|
)
|
|
@@ -33497,7 +33537,7 @@ var recentDataCheck = {
|
|
|
33497
33537
|
);
|
|
33498
33538
|
const recentReferrals = Number(
|
|
33499
33539
|
ctx.db.select({ total: sql13`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
33500
|
-
|
|
33540
|
+
and27(
|
|
33501
33541
|
eq34(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
33502
33542
|
gte5(aiReferralEventsHourly.tsHour, warnCutoff)
|
|
33503
33543
|
)
|
|
@@ -33513,7 +33553,7 @@ var recentDataCheck = {
|
|
|
33513
33553
|
}
|
|
33514
33554
|
const olderCrawlers = Number(
|
|
33515
33555
|
ctx.db.select({ total: sql13`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
33516
|
-
|
|
33556
|
+
and27(
|
|
33517
33557
|
eq34(crawlerEventsHourly.projectId, ctx.project.id),
|
|
33518
33558
|
gte5(crawlerEventsHourly.tsHour, failCutoff)
|
|
33519
33559
|
)
|
|
@@ -33521,7 +33561,7 @@ var recentDataCheck = {
|
|
|
33521
33561
|
);
|
|
33522
33562
|
const olderReferrals = Number(
|
|
33523
33563
|
ctx.db.select({ total: sql13`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
33524
|
-
|
|
33564
|
+
and27(
|
|
33525
33565
|
eq34(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
33526
33566
|
gte5(aiReferralEventsHourly.tsHour, failCutoff)
|
|
33527
33567
|
)
|
|
@@ -33938,7 +33978,7 @@ async function doctorRoutes(app, opts) {
|
|
|
33938
33978
|
|
|
33939
33979
|
// ../api-routes/src/discovery/routes.ts
|
|
33940
33980
|
import crypto27 from "crypto";
|
|
33941
|
-
import { and as
|
|
33981
|
+
import { and as and28, desc as desc16, eq as eq35, gte as gte6, inArray as inArray12, isNull, or as or5 } from "drizzle-orm";
|
|
33942
33982
|
var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
|
|
33943
33983
|
async function discoveryRoutes(app, opts) {
|
|
33944
33984
|
app.post("/projects/:name/discover/run", async (request, reply) => {
|
|
@@ -33972,7 +34012,7 @@ async function discoveryRoutes(app, opts) {
|
|
|
33972
34012
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
33973
34013
|
const ageFloorIso = new Date(Date.now() - MAX_INFLIGHT_DISCOVERY_AGE_MS).toISOString();
|
|
33974
34014
|
const decision = app.db.transaction((tx) => {
|
|
33975
|
-
const existing = tx.select({ id: discoverySessions.id, runId: discoverySessions.runId }).from(discoverySessions).where(
|
|
34015
|
+
const existing = tx.select({ id: discoverySessions.id, runId: discoverySessions.runId }).from(discoverySessions).where(and28(
|
|
33976
34016
|
eq35(discoverySessions.projectId, project.id),
|
|
33977
34017
|
eq35(discoverySessions.icpDescription, icpDescription),
|
|
33978
34018
|
// Buyer is part of session identity: it changes the seed prompt's
|
|
@@ -34618,7 +34658,7 @@ function dedupeStrings(input) {
|
|
|
34618
34658
|
|
|
34619
34659
|
// ../api-routes/src/technical-aeo.ts
|
|
34620
34660
|
import crypto29 from "crypto";
|
|
34621
|
-
import { and as
|
|
34661
|
+
import { and as and29, asc as asc5, count, desc as desc17, eq as eq37, inArray as inArray13 } from "drizzle-orm";
|
|
34622
34662
|
var SURFACEABLE_STATUSES = [RunStatuses.completed, RunStatuses.partial];
|
|
34623
34663
|
function emptyScore(projectName) {
|
|
34624
34664
|
return {
|
|
@@ -34650,7 +34690,7 @@ function parsePositiveInt(value, fallback, max) {
|
|
|
34650
34690
|
async function technicalAeoRoutes(app, opts) {
|
|
34651
34691
|
app.get("/projects/:name/technical-aeo", async (request) => {
|
|
34652
34692
|
const project = resolveProject(app.db, request.params.name);
|
|
34653
|
-
const rows = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(
|
|
34693
|
+
const rows = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(and29(
|
|
34654
34694
|
eq37(siteAuditSnapshots.projectId, project.id),
|
|
34655
34695
|
eq37(runs.kind, RunKinds["site-audit"]),
|
|
34656
34696
|
inArray13(runs.status, SURFACEABLE_STATUSES),
|
|
@@ -34685,7 +34725,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
34685
34725
|
});
|
|
34686
34726
|
app.get("/projects/:name/technical-aeo/pages", async (request) => {
|
|
34687
34727
|
const project = resolveProject(app.db, request.params.name);
|
|
34688
|
-
const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(
|
|
34728
|
+
const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(and29(
|
|
34689
34729
|
eq37(siteAuditSnapshots.projectId, project.id),
|
|
34690
34730
|
eq37(runs.kind, RunKinds["site-audit"]),
|
|
34691
34731
|
inArray13(runs.status, SURFACEABLE_STATUSES),
|
|
@@ -34697,7 +34737,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
34697
34737
|
const statusFilter = request.query.status === "success" || request.query.status === "error" ? request.query.status : null;
|
|
34698
34738
|
const conds = [eq37(siteAuditPages.runId, latest.runId)];
|
|
34699
34739
|
if (statusFilter) conds.push(eq37(siteAuditPages.status, statusFilter));
|
|
34700
|
-
const where =
|
|
34740
|
+
const where = and29(...conds);
|
|
34701
34741
|
const totalRow = app.db.select({ value: count() }).from(siteAuditPages).where(where).get();
|
|
34702
34742
|
const total = totalRow?.value ?? 0;
|
|
34703
34743
|
const limit = parsePositiveInt(request.query.limit, 100, 500);
|
|
@@ -34721,7 +34761,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
34721
34761
|
auditedAt: siteAuditSnapshots.auditedAt,
|
|
34722
34762
|
aggregateScore: siteAuditSnapshots.aggregateScore,
|
|
34723
34763
|
pagesAudited: siteAuditSnapshots.pagesAudited
|
|
34724
|
-
}).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(
|
|
34764
|
+
}).from(siteAuditSnapshots).innerJoin(runs, eq37(siteAuditSnapshots.runId, runs.id)).where(and29(
|
|
34725
34765
|
eq37(siteAuditSnapshots.projectId, project.id),
|
|
34726
34766
|
eq37(runs.kind, RunKinds["site-audit"]),
|
|
34727
34767
|
inArray13(runs.status, SURFACEABLE_STATUSES),
|
|
@@ -34735,7 +34775,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
34735
34775
|
if (!parsed.success) {
|
|
34736
34776
|
throw validationError(parsed.error.issues[0]?.message ?? "Invalid site-audit request");
|
|
34737
34777
|
}
|
|
34738
|
-
const existing = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(
|
|
34778
|
+
const existing = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and29(
|
|
34739
34779
|
eq37(runs.projectId, project.id),
|
|
34740
34780
|
eq37(runs.kind, RunKinds["site-audit"]),
|
|
34741
34781
|
inArray13(runs.status, [RunStatuses.queued, RunStatuses.running])
|
|
@@ -35329,7 +35369,7 @@ var IntelligenceService = class {
|
|
|
35329
35369
|
*/
|
|
35330
35370
|
analyzeAndPersist(runId, projectId) {
|
|
35331
35371
|
const recentRuns = this.db.select().from(runs).where(
|
|
35332
|
-
|
|
35372
|
+
and30(
|
|
35333
35373
|
eq38(runs.projectId, projectId),
|
|
35334
35374
|
or6(eq38(runs.status, "completed"), eq38(runs.status, "partial")),
|
|
35335
35375
|
// Defensive: RunCoordinator already skips probes before this is
|
|
@@ -35421,7 +35461,7 @@ var IntelligenceService = class {
|
|
|
35421
35461
|
}
|
|
35422
35462
|
const windowStart = runRow.startedAt ?? runRow.createdAt;
|
|
35423
35463
|
const windowEnd = runRow.finishedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
35424
|
-
const selected = this.db.select().from(gbpLocations).where(
|
|
35464
|
+
const selected = this.db.select().from(gbpLocations).where(and30(
|
|
35425
35465
|
eq38(gbpLocations.projectId, projectId),
|
|
35426
35466
|
eq38(gbpLocations.selected, true),
|
|
35427
35467
|
gte7(gbpLocations.syncedAt, windowStart),
|
|
@@ -35458,12 +35498,12 @@ var IntelligenceService = class {
|
|
|
35458
35498
|
}
|
|
35459
35499
|
/** Build the per-location signal bundle the GBP analyzer consumes. */
|
|
35460
35500
|
buildGbpLocationSignals(projectId, locationName, displayName, fallbackDate) {
|
|
35461
|
-
const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(
|
|
35462
|
-
const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(
|
|
35463
|
-
const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(
|
|
35464
|
-
const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(
|
|
35501
|
+
const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(and30(eq38(gbpDailyMetrics.projectId, projectId), eq38(gbpDailyMetrics.locationName, locationName))).all();
|
|
35502
|
+
const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(and30(eq38(gbpPlaceActions.projectId, projectId), eq38(gbpPlaceActions.locationName, locationName))).all();
|
|
35503
|
+
const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and30(eq38(gbpLodgingSnapshots.projectId, projectId), eq38(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc18(gbpLodgingSnapshots.syncedAt)).limit(1).get();
|
|
35504
|
+
const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(and30(eq38(gbpLocations.projectId, projectId), eq38(gbpLocations.locationName, locationName))).get();
|
|
35465
35505
|
const descriptionMissing = !(ownerRow?.description ?? "").trim();
|
|
35466
|
-
const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(
|
|
35506
|
+
const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and30(eq38(gbpPlaceDetails.projectId, projectId), eq38(gbpPlaceDetails.locationName, locationName))).orderBy(desc18(gbpPlaceDetails.syncedAt)).limit(1).get();
|
|
35467
35507
|
const placesAmenities = placeRow ? extractPlaceAmenities(placeRow.attributes) : [];
|
|
35468
35508
|
const summary = buildGbpSummary({
|
|
35469
35509
|
locationName,
|
|
@@ -35499,7 +35539,7 @@ var IntelligenceService = class {
|
|
|
35499
35539
|
/** Build the month-over-month keyword series for a location from the
|
|
35500
35540
|
* accumulating gbp_keyword_monthly table (latest complete month vs prior). */
|
|
35501
35541
|
buildGbpKeywordTrend(projectId, locationName) {
|
|
35502
|
-
const rows = this.db.select({ month: gbpKeywordMonthly.month, keyword: gbpKeywordMonthly.keyword, valueCount: gbpKeywordMonthly.valueCount }).from(gbpKeywordMonthly).where(
|
|
35542
|
+
const rows = this.db.select({ month: gbpKeywordMonthly.month, keyword: gbpKeywordMonthly.keyword, valueCount: gbpKeywordMonthly.valueCount }).from(gbpKeywordMonthly).where(and30(eq38(gbpKeywordMonthly.projectId, projectId), eq38(gbpKeywordMonthly.locationName, locationName))).all();
|
|
35503
35543
|
if (rows.length === 0) return { recentMonth: null, priorMonth: null, points: [] };
|
|
35504
35544
|
const months = [...new Set(rows.map((r) => r.month))].sort().reverse();
|
|
35505
35545
|
const recentMonth = months[0] ?? null;
|
|
@@ -35530,7 +35570,7 @@ var IntelligenceService = class {
|
|
|
35530
35570
|
*/
|
|
35531
35571
|
persistGbpInsights(runId, projectId, gbpInsights, coveredLocationNames) {
|
|
35532
35572
|
const covered = new Set(coveredLocationNames);
|
|
35533
|
-
const existing = this.db.select({ id: insights.id, dismissed: insights.dismissed }).from(insights).where(
|
|
35573
|
+
const existing = this.db.select({ id: insights.id, dismissed: insights.dismissed }).from(insights).where(and30(eq38(insights.projectId, projectId), eq38(insights.provider, GBP_INSIGHT_PROVIDER))).all();
|
|
35534
35574
|
const staleIds = [];
|
|
35535
35575
|
const dismissedSlots = /* @__PURE__ */ new Set();
|
|
35536
35576
|
for (const row of existing) {
|
|
@@ -35632,7 +35672,7 @@ var IntelligenceService = class {
|
|
|
35632
35672
|
sinceTimestamp = parsed;
|
|
35633
35673
|
}
|
|
35634
35674
|
const allRuns = this.db.select().from(runs).where(
|
|
35635
|
-
|
|
35675
|
+
and30(
|
|
35636
35676
|
eq38(runs.projectId, project.id),
|
|
35637
35677
|
or6(eq38(runs.status, "completed"), eq38(runs.status, "partial")),
|
|
35638
35678
|
// Backfill must not replay probe runs as if they were real sweeps.
|
|
@@ -35809,7 +35849,7 @@ var IntelligenceService = class {
|
|
|
35809
35849
|
);
|
|
35810
35850
|
const ROWS_PER_GROUP_BUDGET = Math.max(2, locationCount);
|
|
35811
35851
|
const recentRunRows = this.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
|
|
35812
|
-
|
|
35852
|
+
and30(
|
|
35813
35853
|
eq38(runs.projectId, projectId),
|
|
35814
35854
|
eq38(runs.kind, RunKinds["answer-visibility"]),
|
|
35815
35855
|
or6(eq38(runs.status, "completed"), eq38(runs.status, "partial")),
|
|
@@ -35832,7 +35872,7 @@ var IntelligenceService = class {
|
|
|
35832
35872
|
const haveHistory = recentRunIds.length > 0;
|
|
35833
35873
|
const priorRegressionsByPair = /* @__PURE__ */ new Map();
|
|
35834
35874
|
if (haveHistory) {
|
|
35835
|
-
const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(
|
|
35875
|
+
const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and30(eq38(insights.type, "regression"), inArray14(insights.runId, recentRunIds))).all();
|
|
35836
35876
|
const regressionGroups = /* @__PURE__ */ new Map();
|
|
35837
35877
|
for (const row of priorRows) {
|
|
35838
35878
|
if (!row.runId) continue;
|