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