@canonry/canonry 7.5.0 → 7.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +8 -0
- package/assets/assets/{AuditHistoryPanel-B5aLMnWE.js → AuditHistoryPanel-DZbPVuDn.js} +1 -1
- package/assets/assets/{BacklinksPage-Biq1jrqe.js → BacklinksPage-6iPxcQdF.js} +1 -1
- package/assets/assets/{HistoryPage-CGGkAgnz.js → HistoryPage-DQ4gqs5s.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-BwyWGGBg.js → MeasurementPropertyPage-X4EGa3a5.js} +1 -1
- package/assets/assets/{ProjectPage-DEnKyD3e.js → ProjectPage-qvbLROZz.js} +1 -1
- package/assets/assets/{RunsPage-DNBn0Rau.js → RunsPage-DBfy79uf.js} +1 -1
- package/assets/assets/{SettingsPage-D3m-BLuf.js → SettingsPage-BlNafKGd.js} +1 -1
- package/assets/assets/{SiteHealthSection-CPMu1l-l.js → SiteHealthSection-79l2PnfR.js} +3 -3
- package/assets/assets/{TrafficPage-BCK_V__i.js → TrafficPage-CPZWDxjp.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-DaCehUm8.js → TrafficSourceDetailPage-BIhpWiRg.js} +1 -1
- package/assets/assets/{extract-error-message-CqBLzzuR.js → extract-error-message-C9XX_kMH.js} +1 -1
- package/assets/assets/{index-C2X_UARl.js → index-CUQtRdIf.js} +20 -20
- package/assets/assets/{react-sigma_core.esm.min-BvO4SZKT.js → react-sigma_core.esm.min-FTRP6jVQ.js} +1 -1
- package/assets/assets/{v2-overview-adapter-CgDChBa5.js → v2-overview-adapter-DEuH0zoM.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-6Z5MRX24.js → chunk-7FJZCG7A.js} +2 -2
- package/dist/{chunk-JURAGZOO.js → chunk-B7IT47FE.js} +4 -2
- package/dist/{chunk-OY5QVO34.js → chunk-BLHPFAR6.js} +26 -14
- package/dist/{chunk-ZHI2MCMD.js → chunk-FRSGZYQZ.js} +433 -278
- package/dist/{chunk-E7EWAAH3.js → chunk-HXAGDOYV.js} +3 -3
- package/dist/{chunk-KS66E5H6.js → chunk-P72CWNTU.js} +2 -2
- package/dist/{chunk-3L7QPB37.js → chunk-WO7XJJHH.js} +5505 -5457
- package/dist/cli.js +24 -12
- package/dist/{demo-server-55M7DF3U.js → demo-server-Z7NM6DJT.js} +4 -4
- package/dist/index.js +6 -6
- package/dist/{intelligence-service-HZSRDMFP.js → intelligence-service-P7AOOXLZ.js} +2 -2
- package/dist/mcp.js +4 -4
- package/package.json +10 -10
|
@@ -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-WO7XJJHH.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 = [
|
|
@@ -15288,7 +15304,7 @@ function pruneProviderDispatchModes(modes, providers, revisionProviders) {
|
|
|
15288
15304
|
|
|
15289
15305
|
// ../api-routes/src/run-queue.ts
|
|
15290
15306
|
import crypto10 from "crypto";
|
|
15291
|
-
import { and as and10, eq as eq16, or as or4 } from "drizzle-orm";
|
|
15307
|
+
import { and as and10, desc as desc7, eq as eq16, gt as gt3, inArray as inArray6, or as or4 } from "drizzle-orm";
|
|
15292
15308
|
|
|
15293
15309
|
// ../api-routes/src/measurement-report-adapter.ts
|
|
15294
15310
|
import { and as and8, desc as desc5, eq as eq14, gte as gte2, inArray as inArray5, isNull as isNull4, lt as lt4, lte as lte5, ne as ne4 } from "drizzle-orm";
|
|
@@ -16907,6 +16923,92 @@ function resolveQueueDispatch(tx, params, stamp) {
|
|
|
16907
16923
|
}
|
|
16908
16924
|
return resolution;
|
|
16909
16925
|
}
|
|
16926
|
+
function providersARunWouldCall(roster, runnable) {
|
|
16927
|
+
const listed = normalizeProviders(roster);
|
|
16928
|
+
if (runnable == null) return listed;
|
|
16929
|
+
const available = new Set(normalizeProviders(runnable));
|
|
16930
|
+
return listed.filter((provider) => available.has(provider));
|
|
16931
|
+
}
|
|
16932
|
+
var PROVIDER_ACCOUNT_LOOKBACK = PROVIDER_ACCOUNT_FAILURE_STREAK * 5;
|
|
16933
|
+
function providerSettingsChangeCouldFix(action, diff) {
|
|
16934
|
+
if (action === "provider.created") return true;
|
|
16935
|
+
try {
|
|
16936
|
+
const parsed = JSON.parse(diff ?? "null");
|
|
16937
|
+
if (!parsed) return false;
|
|
16938
|
+
if (parsed.apiKeyRotated) return true;
|
|
16939
|
+
const before = parsed.before ?? {};
|
|
16940
|
+
const after = parsed.after ?? {};
|
|
16941
|
+
return before.configured !== after.configured || before.model !== after.model || before.baseUrl !== after.baseUrl;
|
|
16942
|
+
} catch {
|
|
16943
|
+
return false;
|
|
16944
|
+
}
|
|
16945
|
+
}
|
|
16946
|
+
function providerAccountRefusal(db, params) {
|
|
16947
|
+
if (params.force || params.trigger === RunTriggers.probe) return null;
|
|
16948
|
+
const recent = db.select({
|
|
16949
|
+
id: runs.id,
|
|
16950
|
+
status: runs.status,
|
|
16951
|
+
error: runs.error,
|
|
16952
|
+
createdAt: runs.createdAt,
|
|
16953
|
+
finishedAt: runs.finishedAt
|
|
16954
|
+
}).from(runs).where(and10(
|
|
16955
|
+
eq16(runs.projectId, params.projectId),
|
|
16956
|
+
eq16(runs.kind, RunKinds["answer-visibility"]),
|
|
16957
|
+
inArray6(runs.status, [RunStatuses.completed, RunStatuses.partial, RunStatuses.failed, RunStatuses.cancelled])
|
|
16958
|
+
)).orderBy(desc7(runs.createdAt), desc7(runs.id)).limit(PROVIDER_ACCOUNT_LOOKBACK).all().map((run) => ({ ...run, providers: parseRunError(run.error)?.providers ?? {} }));
|
|
16959
|
+
const withAccountFailure = recent.filter((run) => Object.values(run.providers).some((entry) => isProviderAccountFailure(entry.code)));
|
|
16960
|
+
if (withAccountFailure.length < PROVIDER_ACCOUNT_FAILURE_STREAK) return null;
|
|
16961
|
+
const calling = normalizeProviders(params.providers());
|
|
16962
|
+
if (calling.length === 0) return null;
|
|
16963
|
+
const answered2 = (runId, provider) => db.select({ id: querySnapshots.id }).from(querySnapshots).where(and10(eq16(querySnapshots.runId, runId), eq16(querySnapshots.provider, provider))).limit(1).get() !== void 0;
|
|
16964
|
+
const streaks = /* @__PURE__ */ new Map();
|
|
16965
|
+
for (const provider of calling) {
|
|
16966
|
+
let count4 = 0;
|
|
16967
|
+
let newest2 = null;
|
|
16968
|
+
let oldest = null;
|
|
16969
|
+
let code = null;
|
|
16970
|
+
for (const run of recent) {
|
|
16971
|
+
const entry = run.providers[provider];
|
|
16972
|
+
if (!entry) {
|
|
16973
|
+
if (run.status !== RunStatuses.failed && answered2(run.id, provider)) return null;
|
|
16974
|
+
continue;
|
|
16975
|
+
}
|
|
16976
|
+
if (!isProviderAccountFailure(entry.code)) return null;
|
|
16977
|
+
newest2 ??= run;
|
|
16978
|
+
code ??= entry.code;
|
|
16979
|
+
oldest = run;
|
|
16980
|
+
count4 += 1;
|
|
16981
|
+
if (count4 === PROVIDER_ACCOUNT_FAILURE_STREAK) break;
|
|
16982
|
+
}
|
|
16983
|
+
if (count4 < PROVIDER_ACCOUNT_FAILURE_STREAK) return null;
|
|
16984
|
+
streaks.set(provider, { newest: newest2, oldest, code });
|
|
16985
|
+
}
|
|
16986
|
+
const finished = (run) => Date.parse(run.finishedAt ?? run.createdAt);
|
|
16987
|
+
const newest = [...streaks.values()].map((streak) => streak.newest).sort((a, b) => finished(b) - finished(a))[0];
|
|
16988
|
+
const retryAfterMs = finished(newest) + PROVIDER_ACCOUNT_RETRY_HOURS * 36e5;
|
|
16989
|
+
if (Date.parse(params.now) >= retryAfterMs) return null;
|
|
16990
|
+
const since = [...streaks.values()].map((streak) => streak.oldest.createdAt).sort()[0];
|
|
16991
|
+
const settingsChanges = db.select({ entityId: auditLog.entityId, action: auditLog.action, diff: auditLog.diff, createdAt: auditLog.createdAt }).from(auditLog).where(and10(eq16(auditLog.entityType, "provider"), inArray6(auditLog.entityId, calling), gt3(auditLog.createdAt, since))).all();
|
|
16992
|
+
const fixedSince = settingsChanges.some((change) => {
|
|
16993
|
+
const streak = streaks.get(change.entityId ?? "");
|
|
16994
|
+
return streak !== void 0 && change.createdAt > streak.oldest.createdAt && providerSettingsChangeCouldFix(change.action, change.diff);
|
|
16995
|
+
});
|
|
16996
|
+
if (fixedSince) return null;
|
|
16997
|
+
return {
|
|
16998
|
+
consecutiveRuns: PROVIDER_ACCOUNT_FAILURE_STREAK,
|
|
16999
|
+
latestRunId: newest.id,
|
|
17000
|
+
since,
|
|
17001
|
+
retryAfter: new Date(retryAfterMs).toISOString(),
|
|
17002
|
+
providers: Object.fromEntries(calling.map((provider) => [provider, streaks.get(provider).code]))
|
|
17003
|
+
};
|
|
17004
|
+
}
|
|
17005
|
+
function providersFailingError(projectName, failures) {
|
|
17006
|
+
const named = Object.entries(failures.providers).map(([provider, code]) => `${provider} (${code})`).join(", ");
|
|
17007
|
+
return providersFailing(
|
|
17008
|
+
`Not starting a run for '${projectName}': every provider it would call failed on its account (a rejected key, denied access, or no credit left) in each of its last ${failures.consecutiveRuns} runs: ${named}. Fix it in the provider's console or settings. Saving a new key, model or endpoint for the provider (canonry settings provider <name>) lets the next run through; otherwise one run is let through after ${failures.retryAfter}. Pass force (canonry run --force) to run now.`,
|
|
17009
|
+
{ projectName, ...failures }
|
|
17010
|
+
);
|
|
17011
|
+
}
|
|
16910
17012
|
function queueRunIfProjectIdle(db, params) {
|
|
16911
17013
|
const createdAt = params.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
16912
17014
|
const kind = params.kind ?? "answer-visibility";
|
|
@@ -16947,6 +17049,17 @@ function queueRunIfProjectIdle(db, params) {
|
|
|
16947
17049
|
}
|
|
16948
17050
|
const current = activeRun();
|
|
16949
17051
|
if (current) return { conflict: true, activeRunId: current.id };
|
|
17052
|
+
const refused = kind === RunKinds["answer-visibility"] ? providerAccountRefusal(tx, {
|
|
17053
|
+
projectId: params.projectId,
|
|
17054
|
+
trigger: stamp?.scope ? RunTriggers.probe : trigger,
|
|
17055
|
+
force: params.force ?? false,
|
|
17056
|
+
now: createdAt,
|
|
17057
|
+
providers: () => providersARunWouldCall(
|
|
17058
|
+
stamp?.identity.providers ?? providerRoster(tx, params),
|
|
17059
|
+
params.runnableProviders
|
|
17060
|
+
)
|
|
17061
|
+
}) : null;
|
|
17062
|
+
if (refused) return { conflict: false, refused };
|
|
16950
17063
|
const scoped = params.queries != null || stamp?.scope != null;
|
|
16951
17064
|
const basket = scoped ? null : ensureCurrentQueryBasketRevision(tx, params.projectId, createdAt);
|
|
16952
17065
|
tx.insert(runs).values({
|
|
@@ -16978,7 +17091,7 @@ function queueRunIfProjectIdle(db, params) {
|
|
|
16978
17091
|
}
|
|
16979
17092
|
|
|
16980
17093
|
// ../api-routes/src/provider-batches.ts
|
|
16981
|
-
import { and as and11, asc as asc2, eq as eq17, inArray as
|
|
17094
|
+
import { and as and11, asc as asc2, eq as eq17, inArray as inArray7 } from "drizzle-orm";
|
|
16982
17095
|
function formatProviderBatchSummary(row) {
|
|
16983
17096
|
return {
|
|
16984
17097
|
id: row.id,
|
|
@@ -17001,10 +17114,10 @@ function runHadProviderBatch(db, runId) {
|
|
|
17001
17114
|
return db.select({ id: providerBatches.id }).from(providerBatches).where(eq17(providerBatches.runId, runId)).limit(1).get() !== void 0;
|
|
17002
17115
|
}
|
|
17003
17116
|
function hasOutstandingProviderBatch(db, runId) {
|
|
17004
|
-
return db.select({ id: providerBatches.id }).from(providerBatches).where(and11(eq17(providerBatches.runId, runId),
|
|
17117
|
+
return db.select({ id: providerBatches.id }).from(providerBatches).where(and11(eq17(providerBatches.runId, runId), inArray7(providerBatches.status, [...OUTSTANDING_PROVIDER_BATCH_STATUSES]))).limit(1).get() !== void 0;
|
|
17005
17118
|
}
|
|
17006
17119
|
function readProjectRunsWithOutstandingProviderBatch(db, projectId) {
|
|
17007
|
-
return db.selectDistinct({ runId: providerBatches.runId }).from(providerBatches).where(and11(eq17(providerBatches.projectId, projectId),
|
|
17120
|
+
return db.selectDistinct({ runId: providerBatches.runId }).from(providerBatches).where(and11(eq17(providerBatches.projectId, projectId), inArray7(providerBatches.status, [...OUTSTANDING_PROVIDER_BATCH_STATUSES]))).orderBy(asc2(providerBatches.runId)).all().map((row) => row.runId);
|
|
17008
17121
|
}
|
|
17009
17122
|
|
|
17010
17123
|
// ../api-routes/src/projects.ts
|
|
@@ -17571,13 +17684,13 @@ function aliasArraysEqual(a, b) {
|
|
|
17571
17684
|
|
|
17572
17685
|
// ../api-routes/src/queries.ts
|
|
17573
17686
|
import crypto13 from "crypto";
|
|
17574
|
-
import { and as and14, eq as eq20, inArray as
|
|
17687
|
+
import { and as and14, eq as eq20, inArray as inArray9, sql as sql8 } from "drizzle-orm";
|
|
17575
17688
|
|
|
17576
17689
|
// ../api-routes/src/query-replace.ts
|
|
17577
17690
|
import crypto12 from "crypto";
|
|
17578
|
-
import { and as and13, eq as eq19, inArray as
|
|
17691
|
+
import { and as and13, eq as eq19, inArray as inArray8, isNull as isNull5 } from "drizzle-orm";
|
|
17579
17692
|
function preserveSnapshotQueryText(tx, projectId, queryIds) {
|
|
17580
|
-
const candidates = queryIds && queryIds.length > 0 ? tx.select({ id: queries.id, text: queries.query }).from(queries).where(and13(eq19(queries.projectId, projectId),
|
|
17693
|
+
const candidates = queryIds && queryIds.length > 0 ? tx.select({ id: queries.id, text: queries.query }).from(queries).where(and13(eq19(queries.projectId, projectId), inArray8(queries.id, queryIds))).all() : tx.select({ id: queries.id, text: queries.query }).from(queries).where(eq19(queries.projectId, projectId)).all();
|
|
17581
17694
|
for (const q of candidates) {
|
|
17582
17695
|
tx.update(querySnapshots).set({ queryText: q.text }).where(and13(eq19(querySnapshots.queryId, q.id), isNull5(querySnapshots.queryText))).run();
|
|
17583
17696
|
}
|
|
@@ -17640,7 +17753,7 @@ function assertNoActivePlanlessSweep(tx, scope) {
|
|
|
17640
17753
|
const activeRun = tx.select({ id: runs.id }).from(runs).where(and13(
|
|
17641
17754
|
eq19(runs.projectId, scope.projectId),
|
|
17642
17755
|
eq19(runs.kind, RunKinds["answer-visibility"]),
|
|
17643
|
-
|
|
17756
|
+
inArray8(runs.status, [RunStatuses.queued, RunStatuses.running]),
|
|
17644
17757
|
isNull5(runs.measurementPlanVersionId)
|
|
17645
17758
|
)).get();
|
|
17646
17759
|
if (activeRun) throw runInProgress(scope.projectName, RunKinds["answer-visibility"], activeRun.id);
|
|
@@ -17693,11 +17806,11 @@ function replaceProjectQueries(tx, projectId, incomingTexts, now) {
|
|
|
17693
17806
|
for (const dup of diff.duplicates) {
|
|
17694
17807
|
tx.update(querySnapshots).set({ queryId: dup.keptId }).where(eq19(querySnapshots.queryId, dup.id)).run();
|
|
17695
17808
|
}
|
|
17696
|
-
tx.delete(queries).where(
|
|
17809
|
+
tx.delete(queries).where(inArray8(queries.id, diff.duplicates.map((d) => d.id))).run();
|
|
17697
17810
|
}
|
|
17698
17811
|
if (diff.removed.length > 0) {
|
|
17699
17812
|
const removedIds = diff.removed.map((r) => r.id);
|
|
17700
|
-
tx.delete(queries).where(
|
|
17813
|
+
tx.delete(queries).where(inArray8(queries.id, removedIds)).run();
|
|
17701
17814
|
}
|
|
17702
17815
|
for (const keptRow of diff.kept) {
|
|
17703
17816
|
if (keptRow.currentText !== keptRow.incomingText) {
|
|
@@ -17721,7 +17834,11 @@ function generationFailure(err, fallbackMessage) {
|
|
|
17721
17834
|
if (err instanceof AppError) return err;
|
|
17722
17835
|
const message = err instanceof Error ? describeError(err) : fallbackMessage;
|
|
17723
17836
|
switch (classifyProviderErrorMessage(message)) {
|
|
17837
|
+
// Billing has no error code of its own on the wire. It is an account
|
|
17838
|
+
// problem the operator fixes in the provider's console, as with a bad key,
|
|
17839
|
+
// and not a limit to wait out; the message names which one it is.
|
|
17724
17840
|
case "PROVIDER_AUTH":
|
|
17841
|
+
case "PROVIDER_BILLING":
|
|
17725
17842
|
return providerAuthError(message);
|
|
17726
17843
|
case "RATE_LIMITED":
|
|
17727
17844
|
return quotaExceeded("provider requests", { message });
|
|
@@ -17788,9 +17905,9 @@ async function queryRoutes(app, opts) {
|
|
|
17788
17905
|
let snapshotsDetached = 0;
|
|
17789
17906
|
let affectedQueries = 0;
|
|
17790
17907
|
if (removedIds.length > 0) {
|
|
17791
|
-
const snapshotCount = app.db.select({ n: sql8`count(*)` }).from(querySnapshots).where(
|
|
17908
|
+
const snapshotCount = app.db.select({ n: sql8`count(*)` }).from(querySnapshots).where(inArray9(querySnapshots.queryId, removedIds)).get();
|
|
17792
17909
|
snapshotsDetached = snapshotCount?.n ?? 0;
|
|
17793
|
-
const distinctAffected = app.db.select({ n: sql8`count(distinct ${querySnapshots.queryId})` }).from(querySnapshots).where(
|
|
17910
|
+
const distinctAffected = app.db.select({ n: sql8`count(distinct ${querySnapshots.queryId})` }).from(querySnapshots).where(inArray9(querySnapshots.queryId, removedIds)).get();
|
|
17794
17911
|
affectedQueries = distinctAffected?.n ?? 0;
|
|
17795
17912
|
}
|
|
17796
17913
|
return reply.send({
|
|
@@ -18240,7 +18357,7 @@ function parseBody(schema, value, message) {
|
|
|
18240
18357
|
}
|
|
18241
18358
|
|
|
18242
18359
|
// ../api-routes/src/competitor-landscape.ts
|
|
18243
|
-
import { and as and17, desc as
|
|
18360
|
+
import { and as and17, desc as desc8, eq as eq24, gte as gte3, inArray as inArray10, isNull as isNull6 } from "drizzle-orm";
|
|
18244
18361
|
|
|
18245
18362
|
// ../api-routes/src/mention-share-inputs.ts
|
|
18246
18363
|
import { eq as eq22 } from "drizzle-orm";
|
|
@@ -19053,11 +19170,11 @@ function latestSweepRuns(db, projectId) {
|
|
|
19053
19170
|
const candidates = db.select().from(runs).where(and17(
|
|
19054
19171
|
eq24(runs.projectId, projectId),
|
|
19055
19172
|
eq24(runs.kind, RunKinds["answer-visibility"]),
|
|
19056
|
-
|
|
19173
|
+
inArray10(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
19057
19174
|
notProbeRun(),
|
|
19058
19175
|
// A scoped spot check is never the latest sweep.
|
|
19059
19176
|
isNull6(runs.measurementScope)
|
|
19060
|
-
)).orderBy(
|
|
19177
|
+
)).orderBy(desc8(runs.createdAt), desc8(runs.id)).all();
|
|
19061
19178
|
for (const group of groupRunsByCreatedAt(candidates)) {
|
|
19062
19179
|
const whole = group.filter((run) => measurementRunCompleteness(db, run.id).complete);
|
|
19063
19180
|
if (whole.length > 0) return whole;
|
|
@@ -19082,8 +19199,8 @@ function readCompetitorLandscape(app, projectName, query, selection) {
|
|
|
19082
19199
|
const candidateRuns = app.db.select().from(runs).where(and17(
|
|
19083
19200
|
eq24(runs.projectId, project.id),
|
|
19084
19201
|
eq24(runs.kind, RunKinds["answer-visibility"]),
|
|
19085
|
-
selection ?
|
|
19086
|
-
latestRunIds ?
|
|
19202
|
+
selection ? inArray10(runs.id, [...selection.runIds]) : void 0,
|
|
19203
|
+
latestRunIds ? inArray10(runs.id, latestRunIds) : filters.runId ? eq24(runs.id, filters.runId) : void 0,
|
|
19087
19204
|
cutoff ? gte3(runs.createdAt, cutoff) : void 0
|
|
19088
19205
|
)).all();
|
|
19089
19206
|
const advanced = filters.groupKey || filters.scope === "all-markets" ? resolveAdvancedScope(app, project.id, filters.groupKey ? "group" : "all-markets", filters.groupKey, candidateRuns) : null;
|
|
@@ -19111,7 +19228,7 @@ function readCompetitorLandscape(app, projectName, query, selection) {
|
|
|
19111
19228
|
location: querySnapshots.location,
|
|
19112
19229
|
measurementExecutionId: querySnapshots.measurementExecutionId,
|
|
19113
19230
|
createdAt: querySnapshots.createdAt
|
|
19114
|
-
}).from(querySnapshots).where(
|
|
19231
|
+
}).from(querySnapshots).where(inArray10(querySnapshots.runId, candidateRuns.map((run) => run.id))).all();
|
|
19115
19232
|
const runById = new Map(candidateRuns.map((run) => [run.id, run]));
|
|
19116
19233
|
const selectedIds = selection?.snapshotIds ? new Set(selection.snapshotIds) : null;
|
|
19117
19234
|
const inScope = allSnapshots.filter((snapshot) => (!selectedIds || selectedIds.has(snapshot.id)) && snapshotMatchesFilters({
|
|
@@ -19295,7 +19412,7 @@ function frozenRunScopes(db, projectId, kind, groupKey, candidateRuns) {
|
|
|
19295
19412
|
const planVersionIds = [...new Set(candidateRuns.map((run) => run.measurementPlanVersionId).filter((id) => typeof id === "string" && id.length > 0))];
|
|
19296
19413
|
const historicalVersions = planVersionIds.length === 0 ? [] : db.select().from(measurementPlanVersions).where(and17(
|
|
19297
19414
|
eq24(measurementPlanVersions.projectId, projectId),
|
|
19298
|
-
|
|
19415
|
+
inArray10(measurementPlanVersions.id, planVersionIds)
|
|
19299
19416
|
)).all();
|
|
19300
19417
|
const frozenByVersionId = new Map(historicalVersions.map((version) => [
|
|
19301
19418
|
version.id,
|
|
@@ -19433,12 +19550,12 @@ function mergePins(...collections) {
|
|
|
19433
19550
|
|
|
19434
19551
|
// ../api-routes/src/runs.ts
|
|
19435
19552
|
import crypto15 from "crypto";
|
|
19436
|
-
import { and as and19, eq as eq26, asc as asc3, desc as
|
|
19553
|
+
import { and as and19, eq as eq26, asc as asc3, desc as desc10, inArray as inArray12, or as or6, sql as sql10 } from "drizzle-orm";
|
|
19437
19554
|
import { gte as gte4 } from "drizzle-orm";
|
|
19438
19555
|
|
|
19439
19556
|
// ../api-routes/src/run-fill.ts
|
|
19440
19557
|
import crypto14 from "crypto";
|
|
19441
|
-
import { and as and18, desc as
|
|
19558
|
+
import { and as and18, desc as desc9, eq as eq25, gt as gt4, inArray as inArray11, isNull as isNull7, ne as ne5, or as or5, sql as sql9 } from "drizzle-orm";
|
|
19442
19559
|
var ACTIVE_STATUSES = ["queued", "running"];
|
|
19443
19560
|
function normalizeProvider(value) {
|
|
19444
19561
|
return value.trim().toLocaleLowerCase("en");
|
|
@@ -19466,12 +19583,12 @@ function newerFullSweep(db, run) {
|
|
|
19466
19583
|
ne5(runs.trigger, RunTriggers.probe),
|
|
19467
19584
|
isNull7(runs.measurementScope),
|
|
19468
19585
|
isNull7(runs.queries),
|
|
19469
|
-
|
|
19586
|
+
gt4(runs.createdAt, run.createdAt),
|
|
19470
19587
|
or5(
|
|
19471
|
-
|
|
19588
|
+
inArray11(runs.status, ["queued", "running", "completed", "partial"]),
|
|
19472
19589
|
sql9`EXISTS (SELECT 1 FROM ${querySnapshots} WHERE ${querySnapshots.runId} = ${runs.id})`
|
|
19473
19590
|
)
|
|
19474
|
-
)).orderBy(
|
|
19591
|
+
)).orderBy(desc9(runs.createdAt)).get();
|
|
19475
19592
|
}
|
|
19476
19593
|
function measuredOnRetiredModel(run, provider, missing) {
|
|
19477
19594
|
const recorded = run.measurementExecutionIdentity?.models[provider];
|
|
@@ -19607,16 +19724,16 @@ function evaluateRunFill(db, run, input = {}) {
|
|
|
19607
19724
|
return { kind: "fillable", slots, providers, missing };
|
|
19608
19725
|
}
|
|
19609
19726
|
function latestFillFor(db, runId) {
|
|
19610
|
-
return db.select().from(runFills).where(eq25(runFills.runId, runId)).orderBy(
|
|
19727
|
+
return db.select().from(runFills).where(eq25(runFills.runId, runId)).orderBy(desc9(runFills.createdAt), desc9(runFills.id)).get();
|
|
19611
19728
|
}
|
|
19612
19729
|
function activeFillFor(db, projectId) {
|
|
19613
|
-
return db.select().from(runFills).where(and18(eq25(runFills.projectId, projectId),
|
|
19730
|
+
return db.select().from(runFills).where(and18(eq25(runFills.projectId, projectId), inArray11(runFills.status, [...ACTIVE_STATUSES]))).get();
|
|
19614
19731
|
}
|
|
19615
19732
|
function activeSweepFor(db, projectId) {
|
|
19616
19733
|
return db.select({ id: runs.id }).from(runs).where(and18(
|
|
19617
19734
|
eq25(runs.projectId, projectId),
|
|
19618
19735
|
eq25(runs.kind, RunKinds["answer-visibility"]),
|
|
19619
|
-
|
|
19736
|
+
inArray11(runs.status, [...ACTIVE_STATUSES])
|
|
19620
19737
|
)).get();
|
|
19621
19738
|
}
|
|
19622
19739
|
function readRunCompleteness(db, run, input = {}) {
|
|
@@ -19789,6 +19906,22 @@ async function runRoutes(app, opts) {
|
|
|
19789
19906
|
if (activeRun) {
|
|
19790
19907
|
return { conflict: true, activeRunId: activeRun.id };
|
|
19791
19908
|
}
|
|
19909
|
+
const refused = providerAccountRefusal(tx, {
|
|
19910
|
+
projectId: project.id,
|
|
19911
|
+
trigger,
|
|
19912
|
+
force: body.force ?? false,
|
|
19913
|
+
now,
|
|
19914
|
+
providers: () => {
|
|
19915
|
+
const runnable = opts.getRunnableProviderNames?.();
|
|
19916
|
+
const roster = resolveRunnableProviderSelection({
|
|
19917
|
+
requestedProviders: providers,
|
|
19918
|
+
projectProviders: project.providers,
|
|
19919
|
+
runnableProviders: runnable
|
|
19920
|
+
}).selectedProviders;
|
|
19921
|
+
return providersARunWouldCall(roster, runnable);
|
|
19922
|
+
}
|
|
19923
|
+
});
|
|
19924
|
+
if (refused) return { conflict: false, refused };
|
|
19792
19925
|
const inserted = [];
|
|
19793
19926
|
for (const loc of projectLocations) {
|
|
19794
19927
|
const runId2 = crypto15.randomUUID();
|
|
@@ -19809,6 +19942,7 @@ async function runRoutes(app, opts) {
|
|
|
19809
19942
|
if (result.conflict) {
|
|
19810
19943
|
throw runInProgress(project.name, kind, result.activeRunId);
|
|
19811
19944
|
}
|
|
19945
|
+
if (result.refused) throw providersFailingError(project.name, result.refused);
|
|
19812
19946
|
const results = [];
|
|
19813
19947
|
for (const { runId: runId2, loc } of result.inserted) {
|
|
19814
19948
|
writeAuditLog(app.db, {
|
|
@@ -19839,9 +19973,11 @@ async function runRoutes(app, opts) {
|
|
|
19839
19973
|
providerModels: opts.getEffectiveProviderModels?.(),
|
|
19840
19974
|
measurementScope: body.measurementScope ?? null,
|
|
19841
19975
|
dispatchMode: body.dispatchMode ?? null,
|
|
19842
|
-
batchEligibleProviders: opts.getBatchEligibleProviderNames?.() ?? null
|
|
19976
|
+
batchEligibleProviders: opts.getBatchEligibleProviderNames?.() ?? null,
|
|
19977
|
+
force: body.force ?? false
|
|
19843
19978
|
});
|
|
19844
19979
|
if (queueResult.conflict) throw runInProgress(project.name, kind, queueResult.activeRunId);
|
|
19980
|
+
if (queueResult.refused) throw providersFailingError(project.name, queueResult.refused);
|
|
19845
19981
|
const runId = queueResult.runId;
|
|
19846
19982
|
writeAuditLog(app.db, {
|
|
19847
19983
|
projectId: project.id,
|
|
@@ -19865,14 +20001,14 @@ async function runRoutes(app, opts) {
|
|
|
19865
20001
|
if (kind) filters.push(eq26(runs.kind, kind));
|
|
19866
20002
|
if (status) filters.push(eq26(runs.status, status));
|
|
19867
20003
|
const where = and19(...filters);
|
|
19868
|
-
const rows = limit == null ? app.db.select().from(runs).where(where).orderBy(asc3(runs.createdAt)).all() : app.db.select().from(runs).where(where).orderBy(
|
|
20004
|
+
const rows = limit == null ? app.db.select().from(runs).where(where).orderBy(asc3(runs.createdAt)).all() : app.db.select().from(runs).where(where).orderBy(desc10(runs.createdAt)).limit(limit).all().reverse();
|
|
19869
20005
|
return reply.send(rows.map(formatRun));
|
|
19870
20006
|
});
|
|
19871
20007
|
app.get("/projects/:name/runs/latest", async (request, reply) => {
|
|
19872
20008
|
const project = resolveProject(app.db, request.params.name);
|
|
19873
20009
|
const countRow = app.db.select({ count: sql10`count(*)` }).from(runs).where(and19(eq26(runs.projectId, project.id), notProbeRun())).get();
|
|
19874
20010
|
const totalRuns = countRow?.count ?? 0;
|
|
19875
|
-
const latestRun = app.db.select().from(runs).where(and19(eq26(runs.projectId, project.id), notProbeRun())).orderBy(
|
|
20011
|
+
const latestRun = app.db.select().from(runs).where(and19(eq26(runs.projectId, project.id), notProbeRun())).orderBy(desc10(runs.createdAt), desc10(runs.id)).limit(1).get();
|
|
19876
20012
|
if (!latestRun) {
|
|
19877
20013
|
return reply.send({ totalRuns: 0, run: null });
|
|
19878
20014
|
}
|
|
@@ -19892,7 +20028,7 @@ async function runRoutes(app, opts) {
|
|
|
19892
20028
|
if (status) filters.push(eq26(runs.status, status));
|
|
19893
20029
|
const scopedProjectId = request.apiKey?.projectId;
|
|
19894
20030
|
if (scopedProjectId) filters.push(eq26(runs.projectId, scopedProjectId));
|
|
19895
|
-
const rows = app.db.select().from(runs).where(and19(...filters)).orderBy(
|
|
20031
|
+
const rows = app.db.select().from(runs).where(and19(...filters)).orderBy(desc10(runs.createdAt), desc10(runs.id)).limit(limit).all();
|
|
19896
20032
|
return reply.send(rows.map(formatRun));
|
|
19897
20033
|
});
|
|
19898
20034
|
app.post("/runs", async (request, reply) => {
|
|
@@ -19909,6 +20045,8 @@ async function runRoutes(app, opts) {
|
|
|
19909
20045
|
}
|
|
19910
20046
|
const dispatchMode = parsedDispatchMode.data ?? null;
|
|
19911
20047
|
const batchEligibleProviders = opts.getBatchEligibleProviderNames?.() ?? null;
|
|
20048
|
+
const force = request.body?.force;
|
|
20049
|
+
if (force !== void 0 && typeof force !== "boolean") throw validationError('"force" must be a boolean');
|
|
19912
20050
|
const rawProviders = request.body?.providers;
|
|
19913
20051
|
if (rawProviders?.length) {
|
|
19914
20052
|
const normalized = rawProviders.map((p) => p.trim().toLowerCase()).filter(Boolean);
|
|
@@ -20004,12 +20142,18 @@ async function runRoutes(app, opts) {
|
|
|
20004
20142
|
runnableProviders: runnableProviderNames,
|
|
20005
20143
|
providerModels: opts.getEffectiveProviderModels?.(),
|
|
20006
20144
|
dispatchMode,
|
|
20007
|
-
batchEligibleProviders
|
|
20145
|
+
batchEligibleProviders,
|
|
20146
|
+
force: force ?? false
|
|
20008
20147
|
});
|
|
20009
20148
|
if (queueResult.conflict) {
|
|
20010
20149
|
results.push({ projectName: project.name, projectId: project.id, status: "conflict", error: "run_in_progress" });
|
|
20011
20150
|
continue;
|
|
20012
20151
|
}
|
|
20152
|
+
if (queueResult.refused) {
|
|
20153
|
+
const refusal = providersFailingError(project.name, queueResult.refused);
|
|
20154
|
+
results.push({ projectName: project.name, projectId: project.id, status: "error", error: refusal.message, errorCode: refusal.code });
|
|
20155
|
+
continue;
|
|
20156
|
+
}
|
|
20013
20157
|
const runId = queueResult.runId;
|
|
20014
20158
|
writeAuditLog(app.db, {
|
|
20015
20159
|
projectId: project.id,
|
|
@@ -20033,7 +20177,7 @@ async function runRoutes(app, opts) {
|
|
|
20033
20177
|
const terminalStatuses = /* @__PURE__ */ new Set(["completed", "partial", "failed", "cancelled"]);
|
|
20034
20178
|
if (terminalStatuses.has(run.status)) throw runNotCancellable(run.id, run.status);
|
|
20035
20179
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
20036
|
-
const cancelled = app.db.update(runs).set({ status: "cancelled", finishedAt: now, error: serializeRunError({ message: "Cancelled by user" }) }).where(and19(eq26(runs.id, run.id),
|
|
20180
|
+
const cancelled = app.db.update(runs).set({ status: "cancelled", finishedAt: now, error: serializeRunError({ message: "Cancelled by user" }) }).where(and19(eq26(runs.id, run.id), inArray12(runs.status, ["queued", "running"]))).run();
|
|
20037
20181
|
if (cancelled.changes === 0) {
|
|
20038
20182
|
const current = app.db.select().from(runs).where(eq26(runs.id, run.id)).get();
|
|
20039
20183
|
if (!current) throw notFound("Run", run.id);
|
|
@@ -20299,7 +20443,7 @@ function loadRunDetail(app, run) {
|
|
|
20299
20443
|
|
|
20300
20444
|
// ../api-routes/src/measurement-plan.ts
|
|
20301
20445
|
import crypto16 from "crypto";
|
|
20302
|
-
import { and as and20, desc as
|
|
20446
|
+
import { and as and20, desc as desc11, eq as eq27 } from "drizzle-orm";
|
|
20303
20447
|
var MEASUREMENT_PLAN_WRITE_SCOPE = "measurement-plan.write";
|
|
20304
20448
|
function parseStoredPlanAnyVersion(canonicalJson3) {
|
|
20305
20449
|
return parseStoredMeasurementPlanAnyVersion(canonicalJson3);
|
|
@@ -20656,7 +20800,7 @@ async function measurementPlanRoutes(app, opts) {
|
|
|
20656
20800
|
app.get("/projects/:name/measurement-plan/versions", async (request) => {
|
|
20657
20801
|
const project = resolveProject(app.db, request.params.name);
|
|
20658
20802
|
const active = activePlanVersion(app, project.id);
|
|
20659
|
-
const versions = app.db.select().from(measurementPlanVersions).where(eq27(measurementPlanVersions.projectId, project.id)).orderBy(
|
|
20803
|
+
const versions = app.db.select().from(measurementPlanVersions).where(eq27(measurementPlanVersions.projectId, project.id)).orderBy(desc11(measurementPlanVersions.revision)).all();
|
|
20660
20804
|
return {
|
|
20661
20805
|
versions: versions.map((version) => versionMetadata(version, active?.version.id ?? null))
|
|
20662
20806
|
};
|
|
@@ -21397,7 +21541,7 @@ async function measurementServiceRoutes(app, opts) {
|
|
|
21397
21541
|
|
|
21398
21542
|
// ../api-routes/src/measurement-draft.ts
|
|
21399
21543
|
import crypto19 from "crypto";
|
|
21400
|
-
import { and as and21, asc as asc4, desc as
|
|
21544
|
+
import { and as and21, asc as asc4, desc as desc12, eq as eq28, inArray as inArray13 } from "drizzle-orm";
|
|
21401
21545
|
|
|
21402
21546
|
// ../api-routes/src/measurement-draft-compile.ts
|
|
21403
21547
|
var MEASUREMENT_DRAFT_MAX_TARGETS = 1e3;
|
|
@@ -23549,7 +23693,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
23549
23693
|
// The comparable chain, not the bare active id: a label-only
|
|
23550
23694
|
// republish must not flip setup back to awaiting_first_run while
|
|
23551
23695
|
// the overview keeps serving the prior run.
|
|
23552
|
-
|
|
23696
|
+
inArray13(runs.measurementPlanVersionId, comparableMeasurementVersionIds(app.db, project.id, active.id)),
|
|
23553
23697
|
eq28(runs.status, RunStatuses.completed)
|
|
23554
23698
|
)).get() : void 0;
|
|
23555
23699
|
const state = activeSchemaVersion === 1 ? "republish_required" : draft ? "setup_in_progress" : active ? completedRun ? "operational" : "awaiting_first_run" : "simple";
|
|
@@ -24034,7 +24178,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
24034
24178
|
}));
|
|
24035
24179
|
return settle(false, active, parseV2Plan(active));
|
|
24036
24180
|
}
|
|
24037
|
-
const latest = tx.select({ revision: measurementPlanVersions.revision }).from(measurementPlanVersions).where(eq28(measurementPlanVersions.projectId, gate.project.id)).orderBy(
|
|
24181
|
+
const latest = tx.select({ revision: measurementPlanVersions.revision }).from(measurementPlanVersions).where(eq28(measurementPlanVersions.projectId, gate.project.id)).orderBy(desc12(measurementPlanVersions.revision)).get();
|
|
24038
24182
|
const revision = (latest?.revision ?? 0) + 1;
|
|
24039
24183
|
const canonicalJson3 = canonicalMeasurementPlanV2Json(compiled.plan);
|
|
24040
24184
|
const versionId = crypto19.randomUUID();
|
|
@@ -24171,7 +24315,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
24171
24315
|
const sets = app.db.select().from(measurementQuerySets).where(eq28(measurementQuerySets.projectId, project.id)).orderBy(asc4(measurementQuerySets.name)).all();
|
|
24172
24316
|
const counts2 = /* @__PURE__ */ new Map();
|
|
24173
24317
|
if (sets.length) {
|
|
24174
|
-
for (const item2 of app.db.select({ querySetId: measurementQuerySetItems.querySetId }).from(measurementQuerySetItems).where(
|
|
24318
|
+
for (const item2 of app.db.select({ querySetId: measurementQuerySetItems.querySetId }).from(measurementQuerySetItems).where(inArray13(measurementQuerySetItems.querySetId, sets.map((set) => set.id))).all()) {
|
|
24175
24319
|
counts2.set(item2.querySetId, (counts2.get(item2.querySetId) ?? 0) + 1);
|
|
24176
24320
|
}
|
|
24177
24321
|
}
|
|
@@ -24400,7 +24544,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
24400
24544
|
diff: { created: created.length, existing: existing.length }
|
|
24401
24545
|
}));
|
|
24402
24546
|
if (!querySet) return;
|
|
24403
|
-
const highest = tx.select({ position: measurementQuerySetItems.position }).from(measurementQuerySetItems).where(eq28(measurementQuerySetItems.querySetId, querySet.id)).orderBy(
|
|
24547
|
+
const highest = tx.select({ position: measurementQuerySetItems.position }).from(measurementQuerySetItems).where(eq28(measurementQuerySetItems.querySetId, querySet.id)).orderBy(desc12(measurementQuerySetItems.position)).get();
|
|
24404
24548
|
let position = (highest?.position ?? -1) + 1;
|
|
24405
24549
|
const present = new Set(tx.select({ queryId: measurementQuerySetItems.queryId }).from(measurementQuerySetItems).where(eq28(measurementQuerySetItems.querySetId, querySet.id)).all().map((item2) => item2.queryId));
|
|
24406
24550
|
for (const entry of ordered) {
|
|
@@ -25073,10 +25217,10 @@ async function measurementPropertyEvidenceRoutes(app) {
|
|
|
25073
25217
|
}
|
|
25074
25218
|
|
|
25075
25219
|
// ../api-routes/src/measurement-portfolio-reads.ts
|
|
25076
|
-
import { and as and25, desc as
|
|
25220
|
+
import { and as and25, desc as desc13, eq as eq32, inArray as inArray15, lt as lt5, or as or7 } from "drizzle-orm";
|
|
25077
25221
|
|
|
25078
25222
|
// ../api-routes/src/measurement-question-reads.ts
|
|
25079
|
-
import { and as and24, eq as eq31, getTableColumns, inArray as
|
|
25223
|
+
import { and as and24, eq as eq31, getTableColumns, inArray as inArray14, sql as sql11 } from "drizzle-orm";
|
|
25080
25224
|
var DEFAULT_LIMIT2 = 50;
|
|
25081
25225
|
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
25082
25226
|
RunStatuses.completed,
|
|
@@ -25192,7 +25336,7 @@ function selectedQuestionSnapshots(db, runId, manifest, scope) {
|
|
|
25192
25336
|
if (scope !== void 0) {
|
|
25193
25337
|
const executionIds = [...new Set(manifest.expectedSlots.map((slot) => slot.executionId))];
|
|
25194
25338
|
if (executionIds.length === 0) return [];
|
|
25195
|
-
conditions.push(
|
|
25339
|
+
conditions.push(inArray14(querySnapshots.measurementExecutionId, executionIds));
|
|
25196
25340
|
}
|
|
25197
25341
|
if (scope?.provider !== void 0) {
|
|
25198
25342
|
conditions.push(sql11`lower(trim(${querySnapshots.provider})) = ${normalizeText(scope.provider)}`);
|
|
@@ -25207,7 +25351,7 @@ function rawResponsesForLegacyQuestionSnapshots(db, runId, snapshots) {
|
|
|
25207
25351
|
rawResponse: querySnapshots.rawResponse
|
|
25208
25352
|
}).from(querySnapshots).where(and24(
|
|
25209
25353
|
eq31(querySnapshots.runId, runId),
|
|
25210
|
-
|
|
25354
|
+
inArray14(querySnapshots.id, legacyIds)
|
|
25211
25355
|
)).all().map((snapshot) => [snapshot.id, snapshot.rawResponse]));
|
|
25212
25356
|
}
|
|
25213
25357
|
function withLegacyRawEvidence(db, runId, snapshots) {
|
|
@@ -26136,14 +26280,14 @@ function previousComparableRun(db, active, current) {
|
|
|
26136
26280
|
// republish: a run pinned to a comparable prior revision measured exactly
|
|
26137
26281
|
// the questions the active revision asks. The execution-identity and scope
|
|
26138
26282
|
// checks below still gate what actually compares.
|
|
26139
|
-
|
|
26283
|
+
inArray15(runs.measurementPlanVersionId, comparableMeasurementVersionIds(db, current.projectId, active.version.id)),
|
|
26140
26284
|
eq32(runs.kind, RunKinds["answer-visibility"]),
|
|
26141
|
-
|
|
26285
|
+
inArray15(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
26142
26286
|
or7(
|
|
26143
26287
|
lt5(runs.createdAt, current.createdAt),
|
|
26144
26288
|
and25(eq32(runs.createdAt, current.createdAt), lt5(runs.id, current.id))
|
|
26145
26289
|
)
|
|
26146
|
-
)).orderBy(
|
|
26290
|
+
)).orderBy(desc13(runs.createdAt), desc13(runs.id)).all().filter((candidate) => (
|
|
26147
26291
|
// Full reporting never admits probes. A plan slice is itself stored as a
|
|
26148
26292
|
// probe, so an explicitly selected slice compares only with other slices;
|
|
26149
26293
|
// the exact frozen scope check below then keeps the population identical.
|
|
@@ -26395,7 +26539,7 @@ function unattributedByClass(plan, run, materialized) {
|
|
|
26395
26539
|
return { branded: read("branded"), nonBrand: read("non-brand") };
|
|
26396
26540
|
}
|
|
26397
26541
|
function latestRunFill(db, runId) {
|
|
26398
|
-
const fill = db.select().from(runFills).where(eq32(runFills.runId, runId)).orderBy(
|
|
26542
|
+
const fill = db.select().from(runFills).where(eq32(runFills.runId, runId)).orderBy(desc13(runFills.createdAt), desc13(runFills.id)).get();
|
|
26399
26543
|
if (!fill) return null;
|
|
26400
26544
|
const { status, providers, expected, filled, createdAt, finishedAt } = formatRunFill(fill);
|
|
26401
26545
|
return { status, providers, expected, filled, createdAt, finishedAt };
|
|
@@ -26547,7 +26691,7 @@ async function measurementPortfolioReadRoutes(app) {
|
|
|
26547
26691
|
|
|
26548
26692
|
// ../api-routes/src/visibility-report.ts
|
|
26549
26693
|
import { createHash as createHash7 } from "crypto";
|
|
26550
|
-
import { and as and26, desc as
|
|
26694
|
+
import { and as and26, desc as desc14, eq as eq33, gte as gte5, inArray as inArray16, isNotNull as isNotNull4, isNull as isNull8, lt as lt6, lte as lte6, or as or8 } from "drizzle-orm";
|
|
26551
26695
|
|
|
26552
26696
|
// ../api-routes/src/measurement-scope-options.ts
|
|
26553
26697
|
function marketLinks(keys, settings) {
|
|
@@ -27366,7 +27510,7 @@ function loadVisibilitySnapshots(db, runIds) {
|
|
|
27366
27510
|
requestedContext: querySnapshots.requestedContext,
|
|
27367
27511
|
supportedContext: querySnapshots.supportedContext,
|
|
27368
27512
|
createdAt: querySnapshots.createdAt
|
|
27369
|
-
}).from(querySnapshots).where(
|
|
27513
|
+
}).from(querySnapshots).where(inArray16(querySnapshots.runId, [...runIds])).all();
|
|
27370
27514
|
for (const row of rows) {
|
|
27371
27515
|
const snapshots = byRun.get(row.runId) ?? [];
|
|
27372
27516
|
snapshots.push(row);
|
|
@@ -27779,7 +27923,7 @@ function completedVisibilityRuns(db, projectId, planless, query) {
|
|
|
27779
27923
|
return db.select().from(runs).where(and26(
|
|
27780
27924
|
eq33(runs.projectId, projectId),
|
|
27781
27925
|
eq33(runs.kind, RunKinds["answer-visibility"]),
|
|
27782
|
-
|
|
27926
|
+
inArray16(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
27783
27927
|
notProbeRun(),
|
|
27784
27928
|
planless ? isNull8(runs.measurementPlanVersionId) : isNotNull4(runs.measurementPlanVersionId),
|
|
27785
27929
|
// A scoped spot check is never a whole-project sweep. It can be inspected
|
|
@@ -27788,13 +27932,13 @@ function completedVisibilityRuns(db, projectId, planless, query) {
|
|
|
27788
27932
|
query.runId === void 0 ? void 0 : eq33(runs.id, query.runId),
|
|
27789
27933
|
query.from === void 0 ? void 0 : gte5(runs.createdAt, query.from),
|
|
27790
27934
|
query.to === void 0 ? void 0 : lte6(runs.createdAt, query.to)
|
|
27791
|
-
)).orderBy(
|
|
27935
|
+
)).orderBy(desc14(runs.createdAt), desc14(runs.id)).limit(VISIBILITY_REPORT_MAX_RUNS).all();
|
|
27792
27936
|
}
|
|
27793
27937
|
function previousEligibleVisibilityRun(db, projectId, planless, selected) {
|
|
27794
27938
|
return db.select().from(runs).where(and26(
|
|
27795
27939
|
eq33(runs.projectId, projectId),
|
|
27796
27940
|
eq33(runs.kind, RunKinds["answer-visibility"]),
|
|
27797
|
-
|
|
27941
|
+
inArray16(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
27798
27942
|
notProbeRun(),
|
|
27799
27943
|
planless ? isNull8(runs.measurementPlanVersionId) : isNotNull4(runs.measurementPlanVersionId),
|
|
27800
27944
|
isNull8(runs.measurementScope),
|
|
@@ -27802,7 +27946,7 @@ function previousEligibleVisibilityRun(db, projectId, planless, selected) {
|
|
|
27802
27946
|
lt6(runs.createdAt, selected.createdAt),
|
|
27803
27947
|
and26(eq33(runs.createdAt, selected.createdAt), lt6(runs.id, selected.id))
|
|
27804
27948
|
)
|
|
27805
|
-
)).orderBy(
|
|
27949
|
+
)).orderBy(desc14(runs.createdAt), desc14(runs.id)).limit(1).get();
|
|
27806
27950
|
}
|
|
27807
27951
|
function readPreviousSweep(read) {
|
|
27808
27952
|
try {
|
|
@@ -27933,7 +28077,7 @@ function frozenSimpleDefinitions(db, projectId, runIds) {
|
|
|
27933
28077
|
if (runIds.length === 0) return /* @__PURE__ */ new Map();
|
|
27934
28078
|
return new Map(db.select().from(simpleMeasurementDefinitions).where(and26(
|
|
27935
28079
|
eq33(simpleMeasurementDefinitions.projectId, projectId),
|
|
27936
|
-
|
|
28080
|
+
inArray16(simpleMeasurementDefinitions.runId, [...runIds])
|
|
27937
28081
|
)).all().map((row) => [row.runId, row.definition]));
|
|
27938
28082
|
}
|
|
27939
28083
|
function simpleRunInput(db, project, run, definition, includeEvidence) {
|
|
@@ -28002,7 +28146,7 @@ function readVisibilityComparisonRuns(db, projectId, since, until, includeEviden
|
|
|
28002
28146
|
const sourceRuns = db.select().from(runs).where(and26(
|
|
28003
28147
|
eq33(runs.projectId, projectId),
|
|
28004
28148
|
eq33(runs.kind, RunKinds["answer-visibility"]),
|
|
28005
|
-
|
|
28149
|
+
inArray16(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
28006
28150
|
notProbeRun(),
|
|
28007
28151
|
isNotNull4(runs.measurementPlanVersionId),
|
|
28008
28152
|
isNull8(runs.measurementScope),
|
|
@@ -28032,7 +28176,7 @@ function readVisibilityComparisonRuns(db, projectId, since, until, includeEviden
|
|
|
28032
28176
|
|
|
28033
28177
|
// ../api-routes/src/query-tracking.ts
|
|
28034
28178
|
import crypto21 from "crypto";
|
|
28035
|
-
import { and as and27, desc as
|
|
28179
|
+
import { and as and27, desc as desc15, eq as eq34, inArray as inArray17, isNotNull as isNotNull5, isNull as isNull9, ne as ne6 } from "drizzle-orm";
|
|
28036
28180
|
var SOURCE_LIMIT = 100;
|
|
28037
28181
|
var MAX_REVIEW_AGE_MS = 15 * 60 * 1e3;
|
|
28038
28182
|
var MAX_REVIEW_FUTURE_SKEW_MS = 60 * 1e3;
|
|
@@ -28218,11 +28362,11 @@ function simpleMeasuredAtByQuery(db, project, queryRows2, opts) {
|
|
|
28218
28362
|
}).from(runs).where(and27(
|
|
28219
28363
|
eq34(runs.projectId, project.id),
|
|
28220
28364
|
eq34(runs.kind, RunKinds["answer-visibility"]),
|
|
28221
|
-
|
|
28365
|
+
inArray17(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
28222
28366
|
ne6(runs.trigger, RunTriggers.probe),
|
|
28223
28367
|
isNull9(runs.measurementScope),
|
|
28224
28368
|
isNull9(runs.measurementPlanVersionId)
|
|
28225
|
-
)).orderBy(
|
|
28369
|
+
)).orderBy(desc15(runs.createdAt), desc15(runs.id)).limit(SOURCE_LIMIT).all();
|
|
28226
28370
|
if (eligibleRuns.length === 0) return /* @__PURE__ */ new Map();
|
|
28227
28371
|
const frozenByRun = /* @__PURE__ */ new Map();
|
|
28228
28372
|
for (const row of db.select({
|
|
@@ -28230,7 +28374,7 @@ function simpleMeasuredAtByQuery(db, project, queryRows2, opts) {
|
|
|
28230
28374
|
definition: simpleMeasurementDefinitions.definition
|
|
28231
28375
|
}).from(simpleMeasurementDefinitions).where(and27(
|
|
28232
28376
|
eq34(simpleMeasurementDefinitions.projectId, project.id),
|
|
28233
|
-
|
|
28377
|
+
inArray17(simpleMeasurementDefinitions.runId, eligibleRuns.map((run) => run.id))
|
|
28234
28378
|
)).all()) {
|
|
28235
28379
|
const parsed = simpleMeasurementDefinitionSchema.safeParse(row.definition);
|
|
28236
28380
|
if (parsed.success) frozenByRun.set(row.runId, parsed.data);
|
|
@@ -28242,7 +28386,7 @@ function simpleMeasuredAtByQuery(db, project, queryRows2, opts) {
|
|
|
28242
28386
|
queryId: querySnapshots.queryId,
|
|
28243
28387
|
queryText: querySnapshots.queryText,
|
|
28244
28388
|
provider: querySnapshots.provider
|
|
28245
|
-
}).from(querySnapshots).where(
|
|
28389
|
+
}).from(querySnapshots).where(inArray17(querySnapshots.runId, [...frozenByRun.keys()])).all()) {
|
|
28246
28390
|
if (!snapshot.queryId) continue;
|
|
28247
28391
|
const byQuery = snapshotsByRunQuery.get(snapshot.runId) ?? /* @__PURE__ */ new Map();
|
|
28248
28392
|
const rows = byQuery.get(snapshot.queryId) ?? [];
|
|
@@ -28340,11 +28484,11 @@ function measuredAtByQuery(db, state, opts) {
|
|
|
28340
28484
|
const eligibleRuns = db.select().from(runs).where(and27(
|
|
28341
28485
|
eq34(runs.projectId, project.id),
|
|
28342
28486
|
eq34(runs.kind, RunKinds["answer-visibility"]),
|
|
28343
|
-
|
|
28487
|
+
inArray17(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
28344
28488
|
ne6(runs.trigger, RunTriggers.probe),
|
|
28345
28489
|
isNull9(runs.measurementScope),
|
|
28346
28490
|
isNotNull5(runs.measurementPlanVersionId)
|
|
28347
|
-
)).orderBy(
|
|
28491
|
+
)).orderBy(desc15(runs.createdAt), desc15(runs.id)).limit(SOURCE_LIMIT).all();
|
|
28348
28492
|
if (eligibleRuns.length === 0) return /* @__PURE__ */ new Map();
|
|
28349
28493
|
const versionIds = unique2(eligibleRuns.flatMap((run) => run.measurementPlanVersionId ? [run.measurementPlanVersionId] : []));
|
|
28350
28494
|
const versionPlans = new Map(db.select({
|
|
@@ -28353,7 +28497,7 @@ function measuredAtByQuery(db, state, opts) {
|
|
|
28353
28497
|
canonicalJson: measurementPlanVersions.canonicalJson
|
|
28354
28498
|
}).from(measurementPlanVersions).where(and27(
|
|
28355
28499
|
eq34(measurementPlanVersions.projectId, project.id),
|
|
28356
|
-
|
|
28500
|
+
inArray17(measurementPlanVersions.id, versionIds)
|
|
28357
28501
|
)).all().flatMap((row) => {
|
|
28358
28502
|
const parsed = parseStoredMeasurementPlanAnyVersion(row.canonicalJson);
|
|
28359
28503
|
return parsed.schemaVersion === 2 ? [[row.id, { revision: row.revision, plan: parsed }]] : [];
|
|
@@ -28385,7 +28529,7 @@ function measuredAtByQuery(db, state, opts) {
|
|
|
28385
28529
|
measurementExecutionId: querySnapshots.measurementExecutionId,
|
|
28386
28530
|
requestedContext: querySnapshots.requestedContext,
|
|
28387
28531
|
supportedContext: querySnapshots.supportedContext
|
|
28388
|
-
}).from(querySnapshots).where(
|
|
28532
|
+
}).from(querySnapshots).where(inArray17(querySnapshots.runId, eligibleRuns.map((run) => run.id))).all();
|
|
28389
28533
|
for (const snapshot of snapshotRows) {
|
|
28390
28534
|
const snapshots = snapshotsByRun.get(snapshot.runId) ?? [];
|
|
28391
28535
|
snapshots.push(snapshot);
|
|
@@ -28533,13 +28677,13 @@ function savedSources(db, projectId) {
|
|
|
28533
28677
|
researchRunQueryId: researchRunQueries.id,
|
|
28534
28678
|
queryText: researchRunQueries.queryText,
|
|
28535
28679
|
createdAt: researchRunQueries.createdAt
|
|
28536
|
-
}).from(researchRunQueries).innerJoin(researchRuns, eq34(researchRunQueries.researchRunId, researchRuns.id)).where(eq34(researchRuns.projectId, projectId)).orderBy(
|
|
28680
|
+
}).from(researchRunQueries).innerJoin(researchRuns, eq34(researchRunQueries.researchRunId, researchRuns.id)).where(eq34(researchRuns.projectId, projectId)).orderBy(desc15(researchRunQueries.createdAt)).limit(SOURCE_LIMIT).all().filter((row) => row.queryText.trim().length > 0);
|
|
28537
28681
|
const discovery = db.select({
|
|
28538
28682
|
discoverySessionId: discoverySessions.id,
|
|
28539
28683
|
discoveryProbeId: discoveryProbes.id,
|
|
28540
28684
|
queryText: discoveryProbes.query,
|
|
28541
28685
|
createdAt: discoveryProbes.createdAt
|
|
28542
|
-
}).from(discoveryProbes).innerJoin(discoverySessions, eq34(discoveryProbes.sessionId, discoverySessions.id)).where(eq34(discoverySessions.projectId, projectId)).orderBy(
|
|
28686
|
+
}).from(discoveryProbes).innerJoin(discoverySessions, eq34(discoveryProbes.sessionId, discoverySessions.id)).where(eq34(discoverySessions.projectId, projectId)).orderBy(desc15(discoveryProbes.createdAt)).limit(SOURCE_LIMIT).all().filter((row) => row.queryText.trim().length > 0);
|
|
28543
28687
|
return { research, discovery };
|
|
28544
28688
|
}
|
|
28545
28689
|
function workspaceDto(db, state, opts) {
|
|
@@ -29394,7 +29538,7 @@ function writeAdvancedCandidate(tx, candidate, request, now) {
|
|
|
29394
29538
|
const removed = current.filter((row) => !candidate.queryRows.has(row.id));
|
|
29395
29539
|
if (removed.length > 0) {
|
|
29396
29540
|
preserveSnapshotQueryText(tx, candidate.state.project.id, removed.map((row) => row.id));
|
|
29397
|
-
tx.delete(queries).where(
|
|
29541
|
+
tx.delete(queries).where(inArray17(queries.id, removed.map((row) => row.id))).run();
|
|
29398
29542
|
}
|
|
29399
29543
|
for (const row of candidate.queryRows.values()) {
|
|
29400
29544
|
const previous = currentById.get(row.id);
|
|
@@ -29413,7 +29557,7 @@ function writeAdvancedCandidate(tx, candidate, request, now) {
|
|
|
29413
29557
|
if (!candidate.planChanged) return active;
|
|
29414
29558
|
const plan = candidate.plan;
|
|
29415
29559
|
const canonicalJson3 = canonicalMeasurementPlanV2Json(plan);
|
|
29416
|
-
const latest = tx.select().from(measurementPlanVersions).where(eq34(measurementPlanVersions.projectId, candidate.state.project.id)).orderBy(
|
|
29560
|
+
const latest = tx.select().from(measurementPlanVersions).where(eq34(measurementPlanVersions.projectId, candidate.state.project.id)).orderBy(desc15(measurementPlanVersions.revision)).get();
|
|
29417
29561
|
const revision = (latest?.revision ?? 0) + 1;
|
|
29418
29562
|
const versionId = crypto21.randomUUID();
|
|
29419
29563
|
tx.insert(measurementPlanVersions).values({
|
|
@@ -30222,7 +30366,7 @@ function aliasArraysEqual2(a, b) {
|
|
|
30222
30366
|
}
|
|
30223
30367
|
|
|
30224
30368
|
// ../api-routes/src/history.ts
|
|
30225
|
-
import { and as and29, asc as asc5, count, desc as
|
|
30369
|
+
import { and as and29, asc as asc5, count, desc as desc16, eq as eq36, gte as gte6, inArray as inArray18, like as like2, ne as ne7, or as or9 } from "drizzle-orm";
|
|
30226
30370
|
|
|
30227
30371
|
// ../api-routes/src/notification-redaction.ts
|
|
30228
30372
|
var REDACTED_URL = {
|
|
@@ -30274,27 +30418,27 @@ async function historyRoutes(app) {
|
|
|
30274
30418
|
if (!parsed.success) throw validationError("Invalid history cleanup request", { issues: parsed.error.issues });
|
|
30275
30419
|
const input = parsed.data;
|
|
30276
30420
|
return app.db.transaction((tx) => {
|
|
30277
|
-
const active = tx.select({ id: runs.id }).from(runs).where(and29(eq36(runs.projectId, project.id), eq36(runs.kind, RunKinds["answer-visibility"]),
|
|
30278
|
-
const activeResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and29(eq36(researchRuns.projectId, project.id),
|
|
30421
|
+
const active = tx.select({ id: runs.id }).from(runs).where(and29(eq36(runs.projectId, project.id), eq36(runs.kind, RunKinds["answer-visibility"]), inArray18(runs.status, ["queued", "running"]))).get();
|
|
30422
|
+
const activeResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and29(eq36(researchRuns.projectId, project.id), inArray18(researchRuns.status, ["queued", "running"]))).get();
|
|
30279
30423
|
if (active || activeResearch) throw runInProgress(project.name, active ? "answer-visibility" : "research", (active ?? activeResearch).id);
|
|
30280
|
-
const activeFill = tx.select({ id: runFills.id, runId: runFills.runId }).from(runFills).where(and29(eq36(runFills.projectId, project.id),
|
|
30424
|
+
const activeFill = tx.select({ id: runFills.id, runId: runFills.runId }).from(runFills).where(and29(eq36(runFills.projectId, project.id), inArray18(runFills.status, ["queued", "running"]))).get();
|
|
30281
30425
|
if (activeFill) throw runFillInProgress(activeFill.runId, activeFill.id);
|
|
30282
|
-
const selectedRuns = tx.select({ id: runs.id, kind: runs.kind }).from(runs).where(and29(eq36(runs.projectId, project.id),
|
|
30283
|
-
const selectedResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and29(eq36(researchRuns.projectId, project.id),
|
|
30426
|
+
const selectedRuns = tx.select({ id: runs.id, kind: runs.kind }).from(runs).where(and29(eq36(runs.projectId, project.id), inArray18(runs.id, input.runIds))).all();
|
|
30427
|
+
const selectedResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and29(eq36(researchRuns.projectId, project.id), inArray18(researchRuns.id, input.researchRunIds))).all();
|
|
30284
30428
|
if (selectedRuns.length !== input.runIds.length || selectedResearch.length !== input.researchRunIds.length) throw notFound("Selected saved run in project", project.name);
|
|
30285
30429
|
if (selectedRuns.some((run) => run.kind !== RunKinds["answer-visibility"])) throw validationError("Only answer-visibility runs and research batches can be cleared. Site Health and integration runs are preserved.");
|
|
30286
30430
|
const result = {
|
|
30287
30431
|
dryRun: !input.confirm,
|
|
30288
30432
|
runIds: input.runIds,
|
|
30289
30433
|
researchRunIds: input.researchRunIds,
|
|
30290
|
-
querySnapshots: tx.select({ value: count() }).from(querySnapshots).where(
|
|
30291
|
-
researchQueries: tx.select({ value: count() }).from(researchRunQueries).where(
|
|
30292
|
-
insights: tx.select({ value: count() }).from(insights).where(
|
|
30293
|
-
healthSnapshots: tx.select({ value: count() }).from(healthSnapshots).where(
|
|
30434
|
+
querySnapshots: tx.select({ value: count() }).from(querySnapshots).where(inArray18(querySnapshots.runId, input.runIds)).get().value,
|
|
30435
|
+
researchQueries: tx.select({ value: count() }).from(researchRunQueries).where(inArray18(researchRunQueries.researchRunId, input.researchRunIds)).get().value,
|
|
30436
|
+
insights: tx.select({ value: count() }).from(insights).where(inArray18(insights.runId, input.runIds)).get().value,
|
|
30437
|
+
healthSnapshots: tx.select({ value: count() }).from(healthSnapshots).where(inArray18(healthSnapshots.runId, input.runIds)).get().value
|
|
30294
30438
|
};
|
|
30295
30439
|
if (input.confirm) {
|
|
30296
|
-
tx.delete(researchRuns).where(and29(eq36(researchRuns.projectId, project.id),
|
|
30297
|
-
tx.delete(runs).where(and29(eq36(runs.projectId, project.id),
|
|
30440
|
+
tx.delete(researchRuns).where(and29(eq36(researchRuns.projectId, project.id), inArray18(researchRuns.id, input.researchRunIds))).run();
|
|
30441
|
+
tx.delete(runs).where(and29(eq36(runs.projectId, project.id), inArray18(runs.id, input.runIds))).run();
|
|
30298
30442
|
writeAuditLog(tx, { projectId: project.id, actor: "api", action: "results.cleared", entityType: "project", entityId: project.id, diff: result });
|
|
30299
30443
|
}
|
|
30300
30444
|
return result;
|
|
@@ -30305,7 +30449,7 @@ async function historyRoutes(app) {
|
|
|
30305
30449
|
const filters = [eq36(auditLog.projectId, project.id)];
|
|
30306
30450
|
if (request.operatorAccess !== true) filters.push(ne7(auditLog.entityType, "telemetry"));
|
|
30307
30451
|
addAuditHistoryFilters(filters, request.query);
|
|
30308
|
-
const rows = app.db.select().from(auditLog).where(and29(...filters)).orderBy(
|
|
30452
|
+
const rows = app.db.select().from(auditLog).where(and29(...filters)).orderBy(desc16(auditLog.createdAt), desc16(auditLog.id)).limit(parseBoundedInt(request.query.limit, 100, 500)).offset(parseBoundedInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER)).all();
|
|
30309
30453
|
return reply.send(rows.map(formatAuditEntry));
|
|
30310
30454
|
});
|
|
30311
30455
|
app.get("/history", async (request, reply) => {
|
|
@@ -30313,7 +30457,7 @@ async function historyRoutes(app) {
|
|
|
30313
30457
|
const filters = scopedProjectId ? [eq36(auditLog.projectId, scopedProjectId)] : [];
|
|
30314
30458
|
if (request.operatorAccess !== true) filters.push(ne7(auditLog.entityType, "telemetry"));
|
|
30315
30459
|
addAuditHistoryFilters(filters, request.query);
|
|
30316
|
-
const rows = app.db.select().from(auditLog).where(filters.length > 0 ? and29(...filters) : void 0).orderBy(
|
|
30460
|
+
const rows = app.db.select().from(auditLog).where(filters.length > 0 ? and29(...filters) : void 0).orderBy(desc16(auditLog.createdAt), desc16(auditLog.id)).limit(parseBoundedInt(request.query.limit, 100, 500)).offset(parseBoundedInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER)).all();
|
|
30317
30461
|
return reply.send(rows.map(formatAuditEntry));
|
|
30318
30462
|
});
|
|
30319
30463
|
app.get("/projects/:name/snapshots", async (request, reply) => {
|
|
@@ -30346,7 +30490,7 @@ async function historyRoutes(app) {
|
|
|
30346
30490
|
location: querySnapshots.location,
|
|
30347
30491
|
rawResponse: querySnapshots.rawResponse,
|
|
30348
30492
|
createdAt: querySnapshots.createdAt
|
|
30349
|
-
}).from(querySnapshots).leftJoin(queries, eq36(querySnapshots.queryId, queries.id)).where(
|
|
30493
|
+
}).from(querySnapshots).leftJoin(queries, eq36(querySnapshots.queryId, queries.id)).where(inArray18(querySnapshots.runId, projectRuns.map((r) => r.id))).orderBy(desc16(querySnapshots.createdAt)).all();
|
|
30350
30494
|
const locationFilter = request.query.location;
|
|
30351
30495
|
const filtered = locationFilter !== void 0 ? allSnapshots.filter((s) => s.location === (locationFilter || null)) : allSnapshots;
|
|
30352
30496
|
const total = filtered.length;
|
|
@@ -30401,12 +30545,12 @@ async function historyRoutes(app) {
|
|
|
30401
30545
|
eq36(runs.kind, RunKinds["answer-visibility"])
|
|
30402
30546
|
);
|
|
30403
30547
|
const requestedLimit = parseOptionalPositiveInt(request.query.limit, 100);
|
|
30404
|
-
const projectRuns = requestedLimit == null ? app.db.select().from(runs).where(runKindFilter).orderBy(asc5(runs.createdAt)).all() : app.db.select().from(runs).where(runKindFilter).orderBy(
|
|
30548
|
+
const projectRuns = requestedLimit == null ? app.db.select().from(runs).where(runKindFilter).orderBy(asc5(runs.createdAt)).all() : app.db.select().from(runs).where(runKindFilter).orderBy(desc16(runs.createdAt)).limit(requestedLimit).all().reverse();
|
|
30405
30549
|
if (projectRuns.length === 0 || projectQueries.length === 0) {
|
|
30406
30550
|
return reply.send([]);
|
|
30407
30551
|
}
|
|
30408
30552
|
const runIds = new Set(projectRuns.map((r) => r.id));
|
|
30409
|
-
const rawSnapshots = app.db.select().from(querySnapshots).where(
|
|
30553
|
+
const rawSnapshots = app.db.select().from(querySnapshots).where(inArray18(querySnapshots.runId, [...runIds])).all();
|
|
30410
30554
|
const timelineLocationFilter = request.query.location;
|
|
30411
30555
|
const filteredSnapshots = timelineLocationFilter !== void 0 ? rawSnapshots.filter((s) => s.location === (timelineLocationFilter || null)) : rawSnapshots;
|
|
30412
30556
|
const allSnapshots = filteredSnapshots.map((snapshot) => ({
|
|
@@ -30527,7 +30671,7 @@ async function historyRoutes(app) {
|
|
|
30527
30671
|
throw validationError("Both run1 and run2 query params are required");
|
|
30528
30672
|
}
|
|
30529
30673
|
const requestedRunIds = [.../* @__PURE__ */ new Set([run1, run2])];
|
|
30530
|
-
const runRows = app.db.select({ id: runs.id, projectId: runs.projectId }).from(runs).where(
|
|
30674
|
+
const runRows = app.db.select({ id: runs.id, projectId: runs.projectId }).from(runs).where(inArray18(runs.id, requestedRunIds)).all();
|
|
30531
30675
|
const runsById = new Map(runRows.map((row) => [row.id, row]));
|
|
30532
30676
|
for (const runId of requestedRunIds) {
|
|
30533
30677
|
const run = runsById.get(runId);
|
|
@@ -30632,7 +30776,7 @@ function parseOptionalPositiveInt(value, max2) {
|
|
|
30632
30776
|
}
|
|
30633
30777
|
|
|
30634
30778
|
// ../api-routes/src/analytics.ts
|
|
30635
|
-
import { and as and30, desc as
|
|
30779
|
+
import { and as and30, desc as desc17, eq as eq37, gte as gte7, inArray as inArray19, lt as lt7 } from "drizzle-orm";
|
|
30636
30780
|
|
|
30637
30781
|
// ../api-routes/src/analytics-model-attribution.ts
|
|
30638
30782
|
function logicalSweeps(observations) {
|
|
@@ -30728,10 +30872,10 @@ async function analyticsRoutes(app) {
|
|
|
30728
30872
|
const projectRuns = app.db.select().from(runs).where(and30(
|
|
30729
30873
|
eq37(runs.projectId, project.id),
|
|
30730
30874
|
eq37(runs.kind, RunKinds["answer-visibility"]),
|
|
30731
|
-
|
|
30875
|
+
inArray19(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
30732
30876
|
notProbeRun(),
|
|
30733
30877
|
cutoff ? gte7(runs.createdAt, cutoff) : void 0
|
|
30734
|
-
)).orderBy(
|
|
30878
|
+
)).orderBy(desc17(runs.createdAt)).all().filter((r) => measuredWhole(app.db, r)).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
30735
30879
|
if (projectRuns.length === 0) {
|
|
30736
30880
|
return reply.send({
|
|
30737
30881
|
window,
|
|
@@ -30773,7 +30917,7 @@ async function analyticsRoutes(app) {
|
|
|
30773
30917
|
citationState: querySnapshots.citationState,
|
|
30774
30918
|
answerMentioned: querySnapshots.answerMentioned,
|
|
30775
30919
|
answerText: querySnapshots.answerText
|
|
30776
|
-
}).from(querySnapshots).where(
|
|
30920
|
+
}).from(querySnapshots).where(inArray19(querySnapshots.runId, runIds)).all();
|
|
30777
30921
|
const rawSnapshots = referenceBasket ? loadedSnapshots.filter(
|
|
30778
30922
|
(s) => s.queryId !== null || s.queryText !== null && referenceBasket.has(normalizeQueryText(s.queryText))
|
|
30779
30923
|
) : filterTrackedSnapshots(loadedSnapshots);
|
|
@@ -30823,11 +30967,11 @@ async function analyticsRoutes(app) {
|
|
|
30823
30967
|
const anchorRunPredicate = and30(
|
|
30824
30968
|
eq37(runs.projectId, project.id),
|
|
30825
30969
|
eq37(runs.kind, RunKinds["answer-visibility"]),
|
|
30826
|
-
|
|
30970
|
+
inArray19(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
30827
30971
|
notProbeRun(),
|
|
30828
30972
|
lt7(runs.createdAt, cutoff)
|
|
30829
30973
|
);
|
|
30830
|
-
const anchorSweepTimes = app.db.selectDistinct({ createdAt: runs.createdAt }).from(runs).where(anchorRunPredicate).orderBy(
|
|
30974
|
+
const anchorSweepTimes = app.db.selectDistinct({ createdAt: runs.createdAt }).from(runs).where(anchorRunPredicate).orderBy(desc17(runs.createdAt)).limit(ANCHOR_SWEEP_SCAN_LIMIT + 1).all().map((row) => row.createdAt);
|
|
30831
30975
|
const anchorScanTruncated = anchorSweepTimes.length > ANCHOR_SWEEP_SCAN_LIMIT;
|
|
30832
30976
|
if (anchorScanTruncated) anchorSweepTimes.length = ANCHOR_SWEEP_SCAN_LIMIT;
|
|
30833
30977
|
if (anchorSweepTimes.length > 0) {
|
|
@@ -30853,7 +30997,7 @@ async function analyticsRoutes(app) {
|
|
|
30853
30997
|
provider: querySnapshots.provider,
|
|
30854
30998
|
model: querySnapshots.model,
|
|
30855
30999
|
servedModel: querySnapshots.servedModel
|
|
30856
|
-
}).from(querySnapshots).where(
|
|
31000
|
+
}).from(querySnapshots).where(inArray19(querySnapshots.runId, runIds2)).all())) {
|
|
30857
31001
|
if (pending.has(snapshot.provider)) {
|
|
30858
31002
|
const models = modelsByProvider.get(snapshot.provider) ?? [];
|
|
30859
31003
|
models.push(snapshot.model);
|
|
@@ -30982,7 +31126,7 @@ async function analyticsRoutes(app) {
|
|
|
30982
31126
|
const project = resolveProject(app.db, request.params.name);
|
|
30983
31127
|
const window = parseWindow(request.query.window);
|
|
30984
31128
|
const cutoff = windowCutoff(window);
|
|
30985
|
-
const completedRuns = app.db.select().from(runs).where(and30(eq37(runs.projectId, project.id), eq37(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(
|
|
31129
|
+
const completedRuns = app.db.select().from(runs).where(and30(eq37(runs.projectId, project.id), eq37(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc17(runs.createdAt), desc17(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => measuredWhole(app.db, r));
|
|
30986
31130
|
const latestGroup = groupRunsByCreatedAt(completedRuns)[0] ?? [];
|
|
30987
31131
|
const latestGroupRunIds = latestGroup.map((r) => r.id);
|
|
30988
31132
|
const latestRun = pickGroupRepresentative(latestGroup);
|
|
@@ -31005,7 +31149,7 @@ async function analyticsRoutes(app) {
|
|
|
31005
31149
|
citationState: querySnapshots.citationState,
|
|
31006
31150
|
answerMentioned: querySnapshots.answerMentioned,
|
|
31007
31151
|
answerText: querySnapshots.answerText
|
|
31008
|
-
}).from(querySnapshots).where(
|
|
31152
|
+
}).from(querySnapshots).where(inArray19(querySnapshots.runId, windowRunIds)).all());
|
|
31009
31153
|
for (const s of allWindowSnaps) {
|
|
31010
31154
|
const timePoint = runIdToCreatedAt.get(s.runId) ?? s.runId;
|
|
31011
31155
|
let entry = consistencyMap.get(s.queryId);
|
|
@@ -31026,7 +31170,7 @@ async function analyticsRoutes(app) {
|
|
|
31026
31170
|
answerMentioned: querySnapshots.answerMentioned,
|
|
31027
31171
|
answerText: querySnapshots.answerText,
|
|
31028
31172
|
citedDomains: querySnapshots.citedDomains
|
|
31029
|
-
}).from(querySnapshots).leftJoin(queries, eq37(querySnapshots.queryId, queries.id)).where(
|
|
31173
|
+
}).from(querySnapshots).leftJoin(queries, eq37(querySnapshots.queryId, queries.id)).where(inArray19(querySnapshots.runId, latestGroupRunIds)).all());
|
|
31030
31174
|
const snapshots = rawSnapshots.map((s) => ({
|
|
31031
31175
|
...s,
|
|
31032
31176
|
resolvedMentioned: resolveSnapshotAnswerMentioned(s, project)
|
|
@@ -31193,8 +31337,8 @@ async function analyticsRoutes(app) {
|
|
|
31193
31337
|
eq37(runs.projectId, project.id),
|
|
31194
31338
|
eq37(runs.kind, RunKinds["answer-visibility"]),
|
|
31195
31339
|
notProbeRun(),
|
|
31196
|
-
latestRuns ?
|
|
31197
|
-
)).orderBy(
|
|
31340
|
+
latestRuns ? inArray19(runs.id, latestRuns.map((run) => run.id)) : requestedRunId ? eq37(runs.id, requestedRunId) : void 0
|
|
31341
|
+
)).orderBy(desc17(runs.createdAt), desc17(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => measuredWhole(app.db, r)).filter((r) => !cutoff || r.createdAt >= cutoff);
|
|
31198
31342
|
if (windowRuns.length === 0) {
|
|
31199
31343
|
return reply.send({
|
|
31200
31344
|
ranked: buildRankedList(/* @__PURE__ */ new Map(), limit, 0, 0),
|
|
@@ -31226,7 +31370,7 @@ async function analyticsRoutes(app) {
|
|
|
31226
31370
|
citedDomains: querySnapshots.citedDomains,
|
|
31227
31371
|
citedUrls: querySnapshots.citedUrls,
|
|
31228
31372
|
measurementExecutionId: querySnapshots.measurementExecutionId
|
|
31229
|
-
}).from(querySnapshots).leftJoin(queries, eq37(querySnapshots.queryId, queries.id)).where(
|
|
31373
|
+
}).from(querySnapshots).leftJoin(queries, eq37(querySnapshots.queryId, queries.id)).where(inArray19(querySnapshots.runId, windowRunIds)).all();
|
|
31230
31374
|
let unclassifiedAnswers = 0;
|
|
31231
31375
|
let snapshots = loadedSnapshots;
|
|
31232
31376
|
if (splitByClass) {
|
|
@@ -31579,7 +31723,7 @@ function buildCategoryCounts(counts2) {
|
|
|
31579
31723
|
}
|
|
31580
31724
|
|
|
31581
31725
|
// ../api-routes/src/intelligence.ts
|
|
31582
|
-
import { eq as eq38, desc as
|
|
31726
|
+
import { eq as eq38, desc as desc18, and as and31, inArray as inArray20, like as like3 } from "drizzle-orm";
|
|
31583
31727
|
var SEVERITY_RANK = { low: 0, medium: 1, high: 2, critical: 3 };
|
|
31584
31728
|
function severitiesAtOrAbove(min2) {
|
|
31585
31729
|
const floor = SEVERITY_RANK[min2];
|
|
@@ -31709,7 +31853,7 @@ async function intelligenceRoutes(app) {
|
|
|
31709
31853
|
}
|
|
31710
31854
|
const severityFilter = request.query.severity?.trim();
|
|
31711
31855
|
if (severityFilter) {
|
|
31712
|
-
conditions.push(
|
|
31856
|
+
conditions.push(inArray20(insights.severity, severitiesAtOrAbove(severityFilter)));
|
|
31713
31857
|
}
|
|
31714
31858
|
let limit;
|
|
31715
31859
|
if (request.query.limit !== void 0) {
|
|
@@ -31719,7 +31863,7 @@ async function intelligenceRoutes(app) {
|
|
|
31719
31863
|
}
|
|
31720
31864
|
limit = parsed;
|
|
31721
31865
|
}
|
|
31722
|
-
const rows = app.db.select().from(insights).where(conditions.length === 1 ? conditions[0] : and31(...conditions)).orderBy(
|
|
31866
|
+
const rows = app.db.select().from(insights).where(conditions.length === 1 ? conditions[0] : and31(...conditions)).orderBy(desc18(insights.createdAt)).all();
|
|
31723
31867
|
const showDismissed = request.query.dismissed === "true";
|
|
31724
31868
|
let result = rows.filter((r) => showDismissed || !r.dismissed).map(mapInsightRow);
|
|
31725
31869
|
if (limit !== void 0) result = result.slice(0, limit);
|
|
@@ -31747,23 +31891,23 @@ async function intelligenceRoutes(app) {
|
|
|
31747
31891
|
const projectVisRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and31(
|
|
31748
31892
|
eq38(runs.projectId, project.id),
|
|
31749
31893
|
eq38(runs.kind, RunKinds["answer-visibility"]),
|
|
31750
|
-
|
|
31894
|
+
inArray20(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
31751
31895
|
// Health-latest is the dashboard headline; probe runs must not
|
|
31752
31896
|
// displace the most recent real visibility sweep.
|
|
31753
31897
|
notProbeRun()
|
|
31754
|
-
)).orderBy(
|
|
31898
|
+
)).orderBy(desc18(runs.createdAt), desc18(runs.id)).all();
|
|
31755
31899
|
const latestGroup = groupRunsByCreatedAt(projectVisRuns)[0] ?? [];
|
|
31756
31900
|
const latestGroupRunIds = latestGroup.map((r) => r.id);
|
|
31757
31901
|
if (latestGroupRunIds.length > 0) {
|
|
31758
31902
|
const groupRows = app.db.select().from(healthSnapshots).where(and31(
|
|
31759
31903
|
eq38(healthSnapshots.projectId, project.id),
|
|
31760
|
-
|
|
31904
|
+
inArray20(healthSnapshots.runId, latestGroupRunIds)
|
|
31761
31905
|
)).all();
|
|
31762
31906
|
if (groupRows.length > 0) {
|
|
31763
31907
|
return reply.send(aggregateHealthSnapshots(project.id, groupRows));
|
|
31764
31908
|
}
|
|
31765
31909
|
}
|
|
31766
|
-
const fallback = app.db.select().from(healthSnapshots).where(eq38(healthSnapshots.projectId, project.id)).orderBy(
|
|
31910
|
+
const fallback = app.db.select().from(healthSnapshots).where(eq38(healthSnapshots.projectId, project.id)).orderBy(desc18(healthSnapshots.createdAt)).limit(1).get();
|
|
31767
31911
|
if (!fallback) {
|
|
31768
31912
|
return reply.send(emptyHealthSnapshot(project.id));
|
|
31769
31913
|
}
|
|
@@ -31773,13 +31917,13 @@ async function intelligenceRoutes(app) {
|
|
|
31773
31917
|
const project = resolveProject(app.db, request.params.name);
|
|
31774
31918
|
const parsed = request.query.limit ? parseInt(request.query.limit, 10) : NaN;
|
|
31775
31919
|
const limit = Number.isNaN(parsed) ? 30 : Math.min(Math.max(parsed, 1), 100);
|
|
31776
|
-
const rows = app.db.select().from(healthSnapshots).where(eq38(healthSnapshots.projectId, project.id)).orderBy(
|
|
31920
|
+
const rows = app.db.select().from(healthSnapshots).where(eq38(healthSnapshots.projectId, project.id)).orderBy(desc18(healthSnapshots.createdAt)).limit(limit).all();
|
|
31777
31921
|
return reply.send(rows.map(mapHealthRow));
|
|
31778
31922
|
});
|
|
31779
31923
|
}
|
|
31780
31924
|
|
|
31781
31925
|
// ../api-routes/src/traffic-analytics.ts
|
|
31782
|
-
import { and as and33, desc as
|
|
31926
|
+
import { and as and33, desc as desc19, eq as eq39, gte as gte8, lt as lt8, lte as lte7, ne as ne8, sql as sql13 } from "drizzle-orm";
|
|
31783
31927
|
|
|
31784
31928
|
// ../api-routes/src/ai-referral-status.ts
|
|
31785
31929
|
import { and as and32, sql as sql12 } from "drizzle-orm";
|
|
@@ -31989,7 +32133,7 @@ function readTrafficActivity(db, projectId, windowDays2) {
|
|
|
31989
32133
|
gte8(crawlerEventsHourly.tsHour, headlineStart),
|
|
31990
32134
|
lte7(crawlerEventsHourly.tsHour, headlineEnd)
|
|
31991
32135
|
)
|
|
31992
|
-
).groupBy(crawlerEventsHourly.pathNormalized).orderBy(
|
|
32136
|
+
).groupBy(crawlerEventsHourly.pathNormalized).orderBy(desc19(sql13`SUM(${crawlerEventsHourly.hits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
|
|
31993
32137
|
const topCrawledPaths = topPathsRows.map((r) => ({
|
|
31994
32138
|
path: r.path,
|
|
31995
32139
|
verifiedHits: Number(r.verifiedHits),
|
|
@@ -32007,7 +32151,7 @@ function readTrafficActivity(db, projectId, windowDays2) {
|
|
|
32007
32151
|
gte8(aiReferralEventsHourly.tsHour, headlineStart),
|
|
32008
32152
|
lte7(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
32009
32153
|
)
|
|
32010
|
-
).groupBy(aiReferralEventsHourly.product).orderBy(
|
|
32154
|
+
).groupBy(aiReferralEventsHourly.product).orderBy(desc19(sql13`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).all();
|
|
32011
32155
|
const referralProducts = referralProductsRows.map((r) => ({
|
|
32012
32156
|
product: r.product,
|
|
32013
32157
|
arrivals: Number(r.arrivals),
|
|
@@ -32024,7 +32168,7 @@ function readTrafficActivity(db, projectId, windowDays2) {
|
|
|
32024
32168
|
gte8(aiReferralEventsHourly.tsHour, headlineStart),
|
|
32025
32169
|
lte7(aiReferralEventsHourly.tsHour, headlineEnd)
|
|
32026
32170
|
)
|
|
32027
|
-
).groupBy(aiReferralEventsHourly.landingPathNormalized).orderBy(
|
|
32171
|
+
).groupBy(aiReferralEventsHourly.landingPathNormalized).orderBy(desc19(sql13`SUM(${aiReferralEventsHourly.sessionsOrHits})`)).limit(SERVER_ACTIVITY_TOP_PATHS_LIMIT).all();
|
|
32028
32172
|
const topReferralLandingPaths = topReferralRows.map((r) => ({
|
|
32029
32173
|
path: r.path,
|
|
32030
32174
|
arrivals: Number(r.arrivals),
|
|
@@ -32143,7 +32287,7 @@ async function trafficAnalyticsRoutes(app) {
|
|
|
32143
32287
|
}
|
|
32144
32288
|
|
|
32145
32289
|
// ../api-routes/src/referral-assessment.ts
|
|
32146
|
-
import { and as and34, desc as
|
|
32290
|
+
import { and as and34, desc as desc20, eq as eq40, gte as gte9, lte as lte8, ne as ne9, sql as sql14 } from "drizzle-orm";
|
|
32147
32291
|
|
|
32148
32292
|
// ../api-routes/src/ga-ai-referral-aggregation.ts
|
|
32149
32293
|
function normalizeAiTrafficClass(value) {
|
|
@@ -32292,7 +32436,7 @@ function buildAiReferralDailySeries(rows) {
|
|
|
32292
32436
|
var DEFAULT_BURST_THRESHOLD = 100;
|
|
32293
32437
|
var DEFAULT_RATIO_THRESHOLD = 3;
|
|
32294
32438
|
function latestGaSyncQueriedWindow(db, projectId, startDate, endDate) {
|
|
32295
|
-
const summary3 = db.select({ start: gaTrafficSummaries.periodStart, end: gaTrafficSummaries.periodEnd, syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq40(gaTrafficSummaries.projectId, projectId)).orderBy(
|
|
32439
|
+
const summary3 = db.select({ start: gaTrafficSummaries.periodStart, end: gaTrafficSummaries.periodEnd, syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq40(gaTrafficSummaries.projectId, projectId)).orderBy(desc20(gaTrafficSummaries.syncedAt)).limit(1).get();
|
|
32296
32440
|
if (!summary3 || startDate < summary3.start || endDate > summary3.end) return false;
|
|
32297
32441
|
const leftByAnotherSync = db.select({ id: gaAiReferrals.id }).from(gaAiReferrals).where(and34(
|
|
32298
32442
|
eq40(gaAiReferrals.projectId, projectId),
|
|
@@ -32410,7 +32554,7 @@ async function referralAssessmentRoutes(app) {
|
|
|
32410
32554
|
}
|
|
32411
32555
|
|
|
32412
32556
|
// ../api-routes/src/organic-evidence.ts
|
|
32413
|
-
import { and as and36, desc as
|
|
32557
|
+
import { and as and36, desc as desc21, eq as eq42, gte as gte11, lte as lte10, or as or11, sql as sql16 } from "drizzle-orm";
|
|
32414
32558
|
|
|
32415
32559
|
// ../api-routes/src/ga-measurement-analysis.ts
|
|
32416
32560
|
import { and as and35, eq as eq41, gte as gte10, lte as lte9, or as or10, sql as sql15 } from "drizzle-orm";
|
|
@@ -33132,7 +33276,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
33132
33276
|
eq42(runs.kind, RunKinds["answer-visibility"]),
|
|
33133
33277
|
eq42(runs.status, RunStatuses.completed),
|
|
33134
33278
|
notProbeRun()
|
|
33135
|
-
)).orderBy(
|
|
33279
|
+
)).orderBy(desc21(runs.createdAt)).get();
|
|
33136
33280
|
const snapshots = latest ? db.select().from(querySnapshots).where(eq42(querySnapshots.runId, latest.id)).all() : [];
|
|
33137
33281
|
const completedAt = latest ? latest.finishedAt ?? latest.createdAt : null;
|
|
33138
33282
|
const visibility = latest && completedAt ? {
|
|
@@ -33372,7 +33516,7 @@ async function organicEvidenceRoutes(app) {
|
|
|
33372
33516
|
}
|
|
33373
33517
|
|
|
33374
33518
|
// ../api-routes/src/citations.ts
|
|
33375
|
-
import { and as and37, eq as eq43, inArray as
|
|
33519
|
+
import { and as and37, eq as eq43, inArray as inArray21 } from "drizzle-orm";
|
|
33376
33520
|
async function citationRoutes(app) {
|
|
33377
33521
|
app.get("/projects/:name/citations/visibility", async (request, reply) => {
|
|
33378
33522
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -33396,7 +33540,7 @@ async function citationRoutes(app) {
|
|
|
33396
33540
|
competitorOverlap: querySnapshots.competitorOverlap,
|
|
33397
33541
|
answerMentioned: querySnapshots.answerMentioned,
|
|
33398
33542
|
createdAt: querySnapshots.createdAt
|
|
33399
|
-
}).from(querySnapshots).where(
|
|
33543
|
+
}).from(querySnapshots).where(inArray21(querySnapshots.runId, projectRuns.map((r) => r.id))).all();
|
|
33400
33544
|
if (rawSnapshots.length === 0) {
|
|
33401
33545
|
return reply.send(emptyCitationVisibility("no-runs-yet"));
|
|
33402
33546
|
}
|
|
@@ -33533,7 +33677,7 @@ function computeCitationVisibility(input) {
|
|
|
33533
33677
|
}
|
|
33534
33678
|
|
|
33535
33679
|
// ../api-routes/src/visibility-stats.ts
|
|
33536
|
-
import { and as and38, desc as
|
|
33680
|
+
import { and as and38, desc as desc22, eq as eq44, inArray as inArray22 } from "drizzle-orm";
|
|
33537
33681
|
|
|
33538
33682
|
// ../api-routes/src/visibility-compare.ts
|
|
33539
33683
|
var VISIBILITY_COMPARE_MIN_RUNS = 5;
|
|
@@ -34003,7 +34147,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
34003
34147
|
lastRuns = n;
|
|
34004
34148
|
}
|
|
34005
34149
|
const projectQueries = app.db.select({ id: queries.id, query: queries.query }).from(queries).where(eq44(queries.projectId, project.id)).all();
|
|
34006
|
-
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(
|
|
34150
|
+
let projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(and38(eq44(runs.projectId, project.id), eq44(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc22(runs.createdAt)).all().filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial);
|
|
34007
34151
|
if (sinceMs !== null) projectRuns = projectRuns.filter((r) => Date.parse(r.createdAt) >= sinceMs);
|
|
34008
34152
|
if (untilMs !== null) projectRuns = projectRuns.filter((r) => Date.parse(r.createdAt) <= untilMs);
|
|
34009
34153
|
if (lastRuns !== null) projectRuns = projectRuns.slice(0, lastRuns);
|
|
@@ -34016,7 +34160,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
34016
34160
|
citationState: querySnapshots.citationState,
|
|
34017
34161
|
answerMentioned: querySnapshots.answerMentioned,
|
|
34018
34162
|
createdAt: querySnapshots.createdAt
|
|
34019
|
-
}).from(querySnapshots).where(
|
|
34163
|
+
}).from(querySnapshots).where(inArray22(querySnapshots.runId, runIds)).all() : [];
|
|
34020
34164
|
const stats = computeVisibilityStats({ queries: projectQueries, snapshots, groupBy });
|
|
34021
34165
|
const queryAttribution = buildQueryAttribution(projectQueries);
|
|
34022
34166
|
let shareOfVoice;
|
|
@@ -34027,7 +34171,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
34027
34171
|
queryText: querySnapshots.queryText,
|
|
34028
34172
|
answerMentioned: querySnapshots.answerMentioned,
|
|
34029
34173
|
answerText: querySnapshots.answerText
|
|
34030
|
-
}).from(querySnapshots).where(
|
|
34174
|
+
}).from(querySnapshots).where(inArray22(querySnapshots.runId, runIds)).all() : [];
|
|
34031
34175
|
const attributedSovSnapshots = sovSnapshots.filter((s) => resolveCurrentQuery(queryAttribution, s) !== void 0);
|
|
34032
34176
|
const advanced = activeMeasurementPlan(app.db, project.id)?.plan.schemaVersion === 2;
|
|
34033
34177
|
const queryClass = advanced || projectQueryClassifier(project) ? requestedQueryClass : "all";
|
|
@@ -34124,7 +34268,7 @@ function readVisibilityCompare(db, projectName, query) {
|
|
|
34124
34268
|
answerText: querySnapshots.answerText,
|
|
34125
34269
|
citedDomains: querySnapshots.citedDomains,
|
|
34126
34270
|
location: querySnapshots.location
|
|
34127
|
-
}).from(querySnapshots).where(
|
|
34271
|
+
}).from(querySnapshots).where(inArray22(querySnapshots.runId, runIds)).all() : [];
|
|
34128
34272
|
return {
|
|
34129
34273
|
runCount: runIds.length,
|
|
34130
34274
|
snapshots: snapshots.filter((snapshot) => (providerKey2 === void 0 || normalizeText3(snapshot.provider) === providerKey2) && (locationKey2 === void 0 || (locationKey2 === "none" ? snapshot.location === null : snapshot.location !== null && normalizeText3(snapshot.location) === locationKey2)))
|
|
@@ -34235,7 +34379,7 @@ function readVisibilityContinuity(db, projectName, months) {
|
|
|
34235
34379
|
const trackedQueries = db.select({ id: queries.id, query: queries.query }).from(queries).where(eq44(queries.projectId, project.id)).all();
|
|
34236
34380
|
const loadProjectMonth = (bounds) => {
|
|
34237
34381
|
const runIds = legacyCompareRunIds(db, project.id, bounds);
|
|
34238
|
-
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(
|
|
34382
|
+
const rows = runIds.length > 0 && trackedQueries.length > 0 ? db.select({ queryId: querySnapshots.queryId, queryText: querySnapshots.queryText, provider: querySnapshots.provider, model: querySnapshots.model }).from(querySnapshots).where(inArray22(querySnapshots.runId, runIds)).all() : [];
|
|
34239
34383
|
return { runCount: runIds.length, snapshots: rows.map(bare) };
|
|
34240
34384
|
};
|
|
34241
34385
|
const frames = [{ frame: "project", continuity: gate(trackedQueries, loadProjectMonth(fromBounds), loadProjectMonth(toBounds)) }];
|
|
@@ -34492,7 +34636,7 @@ async function resultsExportRoutes(app) {
|
|
|
34492
34636
|
}
|
|
34493
34637
|
|
|
34494
34638
|
// ../api-routes/src/composites.ts
|
|
34495
|
-
import { eq as eq47, and as and41, desc as
|
|
34639
|
+
import { eq as eq47, and as and41, desc as desc23, sql as sql18, like as like4, or as or12, inArray as inArray23 } from "drizzle-orm";
|
|
34496
34640
|
|
|
34497
34641
|
// ../api-routes/src/gsc-totals.ts
|
|
34498
34642
|
import { and as and40, asc as asc7, eq as eq46, sql as sql17, max, min } from "drizzle-orm";
|
|
@@ -34768,7 +34912,7 @@ async function compositeRoutes(app, options) {
|
|
|
34768
34912
|
const project = resolveProject(app.db, request.params.name);
|
|
34769
34913
|
const filterLocation = (request.query.location ?? "").trim() || null;
|
|
34770
34914
|
const sinceIso = parseSinceFilter(request.query.since);
|
|
34771
|
-
const allRunsRaw = app.db.select().from(runs).where(and41(eq47(runs.projectId, project.id), notProbeRun())).orderBy(
|
|
34915
|
+
const allRunsRaw = app.db.select().from(runs).where(and41(eq47(runs.projectId, project.id), notProbeRun())).orderBy(desc23(runs.createdAt), desc23(runs.id)).all();
|
|
34772
34916
|
const allRuns = allRunsRaw.filter((r) => runMatchesFilters(r, filterLocation, sinceIso));
|
|
34773
34917
|
const totalRuns = allRuns.length;
|
|
34774
34918
|
const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
|
|
@@ -34781,9 +34925,9 @@ async function compositeRoutes(app, options) {
|
|
|
34781
34925
|
const previousVisibilityRun = pickGroupRepresentative(previousVisRunGroup);
|
|
34782
34926
|
const latestRunRow = allRuns[0] ?? null;
|
|
34783
34927
|
const latestRun = latestRunRow ? { totalRuns, run: summarizeRun(latestRunRow) } : { totalRuns: 0, run: null };
|
|
34784
|
-
const healthRow = app.db.select().from(healthSnapshots).where(eq47(healthSnapshots.projectId, project.id)).orderBy(
|
|
34928
|
+
const healthRow = app.db.select().from(healthSnapshots).where(eq47(healthSnapshots.projectId, project.id)).orderBy(desc23(healthSnapshots.createdAt)).limit(1).get();
|
|
34785
34929
|
const health = healthRow ? mapHealthRow2(healthRow) : null;
|
|
34786
|
-
const insightRows = app.db.select().from(insights).where(eq47(insights.projectId, project.id)).orderBy(
|
|
34930
|
+
const insightRows = app.db.select().from(insights).where(eq47(insights.projectId, project.id)).orderBy(desc23(insights.createdAt)).all();
|
|
34787
34931
|
const topInsights = insightRows.filter((row) => !row.dismissed).slice(0, TOP_INSIGHT_LIMIT).map(mapInsightRow2);
|
|
34788
34932
|
const sparklineRunIds = visibilityRuns.slice(0, DEFAULT_RUN_HISTORY_LIMIT).map((r) => r.id);
|
|
34789
34933
|
const snapshotRunIds = new Set(sparklineRunIds);
|
|
@@ -34955,7 +35099,7 @@ async function compositeRoutes(app, options) {
|
|
|
34955
35099
|
like4(queries.query, pattern)
|
|
34956
35100
|
)
|
|
34957
35101
|
)
|
|
34958
|
-
).orderBy(
|
|
35102
|
+
).orderBy(desc23(querySnapshots.createdAt)).limit(limit + 1).all());
|
|
34959
35103
|
const insightMatches = app.db.select().from(insights).where(
|
|
34960
35104
|
and41(
|
|
34961
35105
|
eq47(insights.projectId, project.id),
|
|
@@ -34966,7 +35110,7 @@ async function compositeRoutes(app, options) {
|
|
|
34966
35110
|
sql18`${insights.cause} LIKE ${pattern} ESCAPE '\\'`
|
|
34967
35111
|
)
|
|
34968
35112
|
)
|
|
34969
|
-
).orderBy(
|
|
35113
|
+
).orderBy(desc23(insights.createdAt)).limit(limit + 1).all();
|
|
34970
35114
|
const hits = [];
|
|
34971
35115
|
for (const row of snapshotMatches) {
|
|
34972
35116
|
hits.push(buildSnapshotHit(row, rawQuery));
|
|
@@ -35038,7 +35182,7 @@ function loadSnapshotsByRunIds(app, runIds, queryIdByText) {
|
|
|
35038
35182
|
rawResponse: querySnapshots.rawResponse,
|
|
35039
35183
|
competitorOverlap: querySnapshots.competitorOverlap,
|
|
35040
35184
|
citedDomains: querySnapshots.citedDomains
|
|
35041
|
-
}).from(querySnapshots).where(
|
|
35185
|
+
}).from(querySnapshots).where(inArray23(querySnapshots.runId, [...runIds])).all();
|
|
35042
35186
|
for (const row of rows) {
|
|
35043
35187
|
const queryText = row.queryText?.trim() || null;
|
|
35044
35188
|
let queryId;
|
|
@@ -35190,8 +35334,8 @@ function buildIndexCoverageScore(app, projectId) {
|
|
|
35190
35334
|
tooltip,
|
|
35191
35335
|
trend: []
|
|
35192
35336
|
};
|
|
35193
|
-
const gscRow = app.db.select().from(gscCoverageSnapshots).where(eq47(gscCoverageSnapshots.projectId, projectId)).orderBy(
|
|
35194
|
-
const bingRow = app.db.select().from(bingCoverageSnapshots).where(eq47(bingCoverageSnapshots.projectId, projectId)).orderBy(
|
|
35337
|
+
const gscRow = app.db.select().from(gscCoverageSnapshots).where(eq47(gscCoverageSnapshots.projectId, projectId)).orderBy(desc23(gscCoverageSnapshots.date)).limit(1).get();
|
|
35338
|
+
const bingRow = app.db.select().from(bingCoverageSnapshots).where(eq47(bingCoverageSnapshots.projectId, projectId)).orderBy(desc23(bingCoverageSnapshots.date)).limit(1).get();
|
|
35195
35339
|
const chosen = pickIndexCoverageRow(gscRow, bingRow);
|
|
35196
35340
|
if (!chosen) return empty;
|
|
35197
35341
|
const total = chosen.indexed + chosen.notIndexed;
|
|
@@ -35217,7 +35361,7 @@ function countGoogleDeindexedUrls(app, projectId) {
|
|
|
35217
35361
|
url: gscUrlInspections.url,
|
|
35218
35362
|
indexingState: gscUrlInspections.indexingState,
|
|
35219
35363
|
inspectedAt: gscUrlInspections.inspectedAt
|
|
35220
|
-
}).from(gscUrlInspections).where(eq47(gscUrlInspections.projectId, projectId)).orderBy(
|
|
35364
|
+
}).from(gscUrlInspections).where(eq47(gscUrlInspections.projectId, projectId)).orderBy(desc23(gscUrlInspections.inspectedAt)).all();
|
|
35221
35365
|
if (rows.length === 0) return 0;
|
|
35222
35366
|
const canonicalUrl = (url) => url.replace(/^http:\/\//, "https://");
|
|
35223
35367
|
const historyByUrl = /* @__PURE__ */ new Map();
|
|
@@ -35473,10 +35617,10 @@ function makeSnippet(text2, query) {
|
|
|
35473
35617
|
|
|
35474
35618
|
// ../api-routes/src/content.ts
|
|
35475
35619
|
import crypto24 from "crypto";
|
|
35476
|
-
import { and as and43, desc as
|
|
35620
|
+
import { and as and43, desc as desc25, eq as eq49 } from "drizzle-orm";
|
|
35477
35621
|
|
|
35478
35622
|
// ../api-routes/src/content-data.ts
|
|
35479
|
-
import { and as and42, eq as eq48, desc as
|
|
35623
|
+
import { and as and42, eq as eq48, desc as desc24, gte as gte13, inArray as inArray24, lte as lte12 } from "drizzle-orm";
|
|
35480
35624
|
var RECENT_RUNS_WINDOW = 5;
|
|
35481
35625
|
function loadOrchestratorInput(db, project, locationFilter = void 0, gscWindowDays = DEFAULT_CONTENT_GSC_WINDOW_DAYS) {
|
|
35482
35626
|
const projectId = project.id;
|
|
@@ -35616,12 +35760,12 @@ function listRecentAnswerVisibilityRunIds(db, projectId, limit, locationFilter)
|
|
|
35616
35760
|
// Queued/running/failed/cancelled runs may have partial or no
|
|
35617
35761
|
// snapshots; including them risks pointing latestRunId at a run with
|
|
35618
35762
|
// no usable evidence.
|
|
35619
|
-
|
|
35763
|
+
inArray24(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
35620
35764
|
// Probe runs are operator/agent test runs; they must not poison the
|
|
35621
35765
|
// recent-runs window the content engine uses to recommend actions.
|
|
35622
35766
|
notProbeRun()
|
|
35623
35767
|
)
|
|
35624
|
-
).orderBy(
|
|
35768
|
+
).orderBy(desc24(runs.createdAt)).all();
|
|
35625
35769
|
const filtered = locationFilter === void 0 ? rows : rows.filter((r) => (r.location ?? null) === locationFilter);
|
|
35626
35770
|
return filtered.slice(0, limit).map((r) => r.id);
|
|
35627
35771
|
}
|
|
@@ -35656,7 +35800,7 @@ function buildGaTrafficByPage(db, projectId, window) {
|
|
|
35656
35800
|
return map;
|
|
35657
35801
|
}
|
|
35658
35802
|
function resolveContentGaWindow(db, projectId, windowDays2) {
|
|
35659
|
-
const latest = db.select({ date: gaTrafficSnapshots.date }).from(gaTrafficSnapshots).where(eq48(gaTrafficSnapshots.projectId, projectId)).orderBy(
|
|
35803
|
+
const latest = db.select({ date: gaTrafficSnapshots.date }).from(gaTrafficSnapshots).where(eq48(gaTrafficSnapshots.projectId, projectId)).orderBy(desc24(gaTrafficSnapshots.date)).limit(1).get();
|
|
35660
35804
|
if (!latest?.date) return null;
|
|
35661
35805
|
const end = /* @__PURE__ */ new Date(`${latest.date}T00:00:00Z`);
|
|
35662
35806
|
end.setUTCDate(end.getUTCDate() - (Math.max(1, windowDays2) - 1));
|
|
@@ -35684,7 +35828,7 @@ function buildCandidateQueries(opts) {
|
|
|
35684
35828
|
const queryRows2 = opts.db.select({ id: queries.id, text: queries.query }).from(queries).where(eq48(queries.projectId, opts.projectId)).all();
|
|
35685
35829
|
const queryIdByText = new Map(queryRows2.map((r) => [r.text, r.id]));
|
|
35686
35830
|
const candidateQueryIds = opts.candidateQueryStrings.map((q) => queryIdByText.get(q)).filter((id) => Boolean(id));
|
|
35687
|
-
const snapshotRows = filterTrackedSnapshots(opts.db.select().from(querySnapshots).where(
|
|
35831
|
+
const snapshotRows = filterTrackedSnapshots(opts.db.select().from(querySnapshots).where(inArray24(querySnapshots.runId, opts.recentRunIds)).all()).filter((r) => candidateQueryIds.includes(r.queryId));
|
|
35688
35832
|
const snapshotsByQuery = /* @__PURE__ */ new Map();
|
|
35689
35833
|
for (const row of snapshotRows) {
|
|
35690
35834
|
const list = snapshotsByQuery.get(row.queryId) ?? [];
|
|
@@ -36084,7 +36228,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
36084
36228
|
const row = app.db.select().from(recommendationExplanations).where(and43(
|
|
36085
36229
|
eq49(recommendationExplanations.projectId, project.id),
|
|
36086
36230
|
eq49(recommendationExplanations.targetRef, request.params.targetRef)
|
|
36087
|
-
)).orderBy(
|
|
36231
|
+
)).orderBy(desc25(recommendationExplanations.generatedAt)).limit(1).get();
|
|
36088
36232
|
if (!row) {
|
|
36089
36233
|
return reply.status(404).send({ error: { code: "NOT_FOUND", message: "No cached explanation for this targetRef." } });
|
|
36090
36234
|
}
|
|
@@ -36112,7 +36256,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
36112
36256
|
const cached = app.db.select().from(recommendationExplanations).where(and43(
|
|
36113
36257
|
eq49(recommendationExplanations.projectId, project.id),
|
|
36114
36258
|
eq49(recommendationExplanations.targetRef, targetRef)
|
|
36115
|
-
)).orderBy(
|
|
36259
|
+
)).orderBy(desc25(recommendationExplanations.generatedAt)).limit(1).get();
|
|
36116
36260
|
if (cached) return reply.send(formatExplanationRow(cached));
|
|
36117
36261
|
}
|
|
36118
36262
|
const result = await explainer({
|
|
@@ -36242,7 +36386,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
36242
36386
|
});
|
|
36243
36387
|
app.get("/projects/:name/content/domain-classifications", async (request) => {
|
|
36244
36388
|
const project = resolveProject(app.db, request.params.name);
|
|
36245
|
-
const rows = app.db.select().from(domainClassifications).where(eq49(domainClassifications.projectId, project.id)).orderBy(
|
|
36389
|
+
const rows = app.db.select().from(domainClassifications).where(eq49(domainClassifications.projectId, project.id)).orderBy(desc25(domainClassifications.hits)).all();
|
|
36246
36390
|
const response = {
|
|
36247
36391
|
classifications: rows.map((r) => ({
|
|
36248
36392
|
domain: r.domain,
|
|
@@ -36262,7 +36406,7 @@ function lookupCachedBrief(db, projectId, targetRef, promptVersion) {
|
|
|
36262
36406
|
if (promptVersion !== void 0) {
|
|
36263
36407
|
conditions.push(eq49(recommendationBriefs.promptVersion, promptVersion));
|
|
36264
36408
|
}
|
|
36265
|
-
return db.select().from(recommendationBriefs).where(and43(...conditions)).orderBy(
|
|
36409
|
+
return db.select().from(recommendationBriefs).where(and43(...conditions)).orderBy(desc25(recommendationBriefs.generatedAt)).limit(1).get();
|
|
36266
36410
|
}
|
|
36267
36411
|
function parseLimitParam(raw) {
|
|
36268
36412
|
if (raw === void 0) return void 0;
|
|
@@ -38828,7 +38972,11 @@ var routeCatalog = [
|
|
|
38828
38972
|
location: stringSchema,
|
|
38829
38973
|
allLocations: booleanSchema,
|
|
38830
38974
|
noLocation: booleanSchema,
|
|
38831
|
-
dispatchMode: dispatchModeRequestSchema
|
|
38975
|
+
dispatchMode: dispatchModeRequestSchema,
|
|
38976
|
+
force: {
|
|
38977
|
+
type: "boolean",
|
|
38978
|
+
description: "Queue the run even when it would be refused with PROVIDERS_FAILING. Admission only; never stored."
|
|
38979
|
+
}
|
|
38832
38980
|
}
|
|
38833
38981
|
}
|
|
38834
38982
|
}
|
|
@@ -38839,7 +38987,9 @@ var routeCatalog = [
|
|
|
38839
38987
|
400: errorResponse(
|
|
38840
38988
|
'Invalid request: an untracked query, a measurement scope naming a group/target/question the published plan does not contain, a scope combined with a query list, a per-run location on a plan project, a provider roster the plan was not published for, or `dispatchMode: "batch"` when no provider of the run can batch (`details.ineligible` names each provider\'s reason).'
|
|
38841
38989
|
),
|
|
38842
|
-
422: errorResponse(
|
|
38990
|
+
422: errorResponse(
|
|
38991
|
+
`NO_QUERIES: the project has no tracked queries. PROVIDERS_FAILING: every provider the run would call failed on its account (rejected key, denied access, no credit) in each of its last ${PROVIDER_ACCOUNT_FAILURE_STREAK} runs. \`details.providers\` names each provider's code and \`details.retryAfter\` when one run is let through again (${PROVIDER_ACCOUNT_RETRY_HOURS}h after the newest failure). Saving a new key, model or endpoint in a provider's settings lets the next run through at once, a probe is never refused, and \`force: true\` overrides.`
|
|
38992
|
+
),
|
|
38843
38993
|
409: errorResponse("Run already in progress."),
|
|
38844
38994
|
503: errorResponse("No runnable answer provider is configured.")
|
|
38845
38995
|
}
|
|
@@ -38893,7 +39043,11 @@ var routeCatalog = [
|
|
|
38893
39043
|
properties: {
|
|
38894
39044
|
kind: stringSchema,
|
|
38895
39045
|
providers: stringArraySchema,
|
|
38896
|
-
dispatchMode: dispatchModeRequestSchema
|
|
39046
|
+
dispatchMode: dispatchModeRequestSchema,
|
|
39047
|
+
force: {
|
|
39048
|
+
type: "boolean",
|
|
39049
|
+
description: "Queue projects that would be refused with PROVIDERS_FAILING. Admission only; never stored."
|
|
39050
|
+
}
|
|
38897
39051
|
}
|
|
38898
39052
|
}
|
|
38899
39053
|
}
|
|
@@ -38902,7 +39056,7 @@ var routeCatalog = [
|
|
|
38902
39056
|
responses: {
|
|
38903
39057
|
// TODO: Add `TriggerAllRunsResponse` Zod schema in contracts.
|
|
38904
39058
|
207: rawJsonResponse(
|
|
38905
|
-
"One row per project: either a queued run or an error for that project alone. A project that cannot be measured (for example one whose published measurement plan expects a different number of answers per question) never prevents or hides the others.",
|
|
39059
|
+
"One row per project: either a queued run or an error for that project alone. A project that cannot be measured (for example one whose published measurement plan expects a different number of answers per question, or one whose providers all keep failing on their accounts: `errorCode: PROVIDERS_FAILING`) never prevents or hides the others.",
|
|
38906
39060
|
{ type: "array", items: looseObjectSchema }
|
|
38907
39061
|
),
|
|
38908
39062
|
400: errorResponse("Invalid request: an unknown provider name, or an unsupported run kind.")
|
|
@@ -44150,7 +44304,7 @@ function buildOperationId(method, path8) {
|
|
|
44150
44304
|
|
|
44151
44305
|
// ../api-routes/src/keys.ts
|
|
44152
44306
|
import crypto25 from "crypto";
|
|
44153
|
-
import { desc as
|
|
44307
|
+
import { desc as desc26, eq as eq50 } from "drizzle-orm";
|
|
44154
44308
|
var KEYS_WRITE_SCOPE = "keys.write";
|
|
44155
44309
|
function toApiKeyDto(row, projectNames) {
|
|
44156
44310
|
const scopes = Array.isArray(row.scopes) ? row.scopes : [];
|
|
@@ -44175,7 +44329,7 @@ async function keysRoutes(app) {
|
|
|
44175
44329
|
app.get("/keys", async (request) => {
|
|
44176
44330
|
requireAdminSession(request);
|
|
44177
44331
|
const scopedProjectId = request.apiKey?.projectId;
|
|
44178
|
-
const rows = scopedProjectId ? app.db.select().from(apiKeys).where(eq50(apiKeys.projectId, scopedProjectId)).orderBy(
|
|
44332
|
+
const rows = scopedProjectId ? app.db.select().from(apiKeys).where(eq50(apiKeys.projectId, scopedProjectId)).orderBy(desc26(apiKeys.createdAt)).all() : app.db.select().from(apiKeys).orderBy(desc26(apiKeys.createdAt)).all();
|
|
44179
44333
|
const names = projectNameById(app.db);
|
|
44180
44334
|
return { keys: rows.map((row) => toApiKeyDto(row, names)) };
|
|
44181
44335
|
});
|
|
@@ -45177,7 +45331,7 @@ function formatNotification(row) {
|
|
|
45177
45331
|
|
|
45178
45332
|
// ../api-routes/src/google.ts
|
|
45179
45333
|
import crypto33 from "crypto";
|
|
45180
|
-
import { eq as eq54, and as and45, desc as
|
|
45334
|
+
import { eq as eq54, and as and45, desc as desc27, sql as sql19, inArray as inArray25 } from "drizzle-orm";
|
|
45181
45335
|
|
|
45182
45336
|
// ../api-routes/src/gsc-period-comparison.ts
|
|
45183
45337
|
var DAY_MS = 864e5;
|
|
@@ -47688,9 +47842,9 @@ async function googleRoutes(app, opts) {
|
|
|
47688
47842
|
const limitVal = Math.max(parseInt(limit ?? "500", 10) || 0, 1);
|
|
47689
47843
|
const offsetVal = Math.max(parseInt(offset ?? "0", 10) || 0, 0);
|
|
47690
47844
|
const orderColumns = {
|
|
47691
|
-
clicks: [
|
|
47692
|
-
impressions: [
|
|
47693
|
-
date: [
|
|
47845
|
+
clicks: [desc27(gscSearchData.clicks), desc27(gscSearchData.date), gscSearchData.query],
|
|
47846
|
+
impressions: [desc27(gscSearchData.impressions), desc27(gscSearchData.date), gscSearchData.query],
|
|
47847
|
+
date: [desc27(gscSearchData.date), desc27(gscSearchData.clicks), gscSearchData.query]
|
|
47694
47848
|
}[orderBy];
|
|
47695
47849
|
const rows = app.db.select().from(gscSearchData).where(and45(...conditions)).orderBy(...orderColumns).limit(limitVal).offset(offsetVal).all();
|
|
47696
47850
|
const totalMatching = app.db.select({ total: sql19`COUNT(*)` }).from(gscSearchData).where(and45(...conditions)).get()?.total ?? 0;
|
|
@@ -47849,7 +48003,7 @@ async function googleRoutes(app, opts) {
|
|
|
47849
48003
|
page: gscSearchData.page,
|
|
47850
48004
|
clicks: sql19`COALESCE(SUM(${gscSearchData.clicks}), 0)`,
|
|
47851
48005
|
impressions: sql19`COALESCE(SUM(${gscSearchData.impressions}), 0)`
|
|
47852
|
-
}).from(gscSearchData).where(and45(...conditions)).groupBy(gscSearchData.page).orderBy(
|
|
48006
|
+
}).from(gscSearchData).where(and45(...conditions)).groupBy(gscSearchData.page).orderBy(desc27(sql19`SUM(${gscSearchData.clicks})`), desc27(sql19`SUM(${gscSearchData.impressions})`)).limit(limitVal).all();
|
|
47853
48007
|
const windowStart = startDate ?? cutoffDate ?? "";
|
|
47854
48008
|
const windowEnd = endDate ?? resolvedWindow.endDate ?? "9999-12-31";
|
|
47855
48009
|
const dailyTotals = readGscDailyTotals(app.db, project.id, windowStart, windowEnd);
|
|
@@ -47992,7 +48146,7 @@ async function googleRoutes(app, opts) {
|
|
|
47992
48146
|
const { url, limit } = request.query;
|
|
47993
48147
|
const conditions = [eq54(gscUrlInspections.projectId, project.id)];
|
|
47994
48148
|
if (url) conditions.push(eq54(gscUrlInspections.url, url));
|
|
47995
|
-
const rows = app.db.select().from(gscUrlInspections).where(and45(...conditions)).orderBy(
|
|
48149
|
+
const rows = app.db.select().from(gscUrlInspections).where(and45(...conditions)).orderBy(desc27(gscUrlInspections.inspectedAt)).limit(parseInt(limit ?? "100", 10)).all();
|
|
47996
48150
|
return rows.map((r) => ({
|
|
47997
48151
|
id: r.id,
|
|
47998
48152
|
url: r.url,
|
|
@@ -48011,7 +48165,7 @@ async function googleRoutes(app, opts) {
|
|
|
48011
48165
|
});
|
|
48012
48166
|
app.get("/projects/:name/google/gsc/deindexed", async (request) => {
|
|
48013
48167
|
const project = resolveProject(app.db, request.params.name);
|
|
48014
|
-
const allInspections = app.db.select().from(gscUrlInspections).where(eq54(gscUrlInspections.projectId, project.id)).orderBy(
|
|
48168
|
+
const allInspections = app.db.select().from(gscUrlInspections).where(eq54(gscUrlInspections.projectId, project.id)).orderBy(desc27(gscUrlInspections.inspectedAt)).all();
|
|
48015
48169
|
const byUrl = /* @__PURE__ */ new Map();
|
|
48016
48170
|
for (const row of allInspections) {
|
|
48017
48171
|
const existing = byUrl.get(row.url);
|
|
@@ -48039,7 +48193,7 @@ async function googleRoutes(app, opts) {
|
|
|
48039
48193
|
});
|
|
48040
48194
|
app.get("/projects/:name/google/gsc/coverage", async (request) => {
|
|
48041
48195
|
const project = resolveProject(app.db, request.params.name);
|
|
48042
|
-
const allInspections = app.db.select().from(gscUrlInspections).where(eq54(gscUrlInspections.projectId, project.id)).orderBy(
|
|
48196
|
+
const allInspections = app.db.select().from(gscUrlInspections).where(eq54(gscUrlInspections.projectId, project.id)).orderBy(desc27(gscUrlInspections.inspectedAt)).all();
|
|
48043
48197
|
const canonicalUrl = (url) => url.replace(/^http:\/\//, "https://");
|
|
48044
48198
|
const latestByUrl = /* @__PURE__ */ new Map();
|
|
48045
48199
|
const historyByUrl = /* @__PURE__ */ new Map();
|
|
@@ -48088,7 +48242,7 @@ async function googleRoutes(app, opts) {
|
|
|
48088
48242
|
const total = latestByUrl.size;
|
|
48089
48243
|
const indexed = indexedUrls.length;
|
|
48090
48244
|
const notIndexed = notIndexedUrls.length;
|
|
48091
|
-
const latestSnapshot = app.db.select({ createdAt: gscCoverageSnapshots.createdAt }).from(gscCoverageSnapshots).where(eq54(gscCoverageSnapshots.projectId, project.id)).orderBy(
|
|
48245
|
+
const latestSnapshot = app.db.select({ createdAt: gscCoverageSnapshots.createdAt }).from(gscCoverageSnapshots).where(eq54(gscCoverageSnapshots.projectId, project.id)).orderBy(desc27(gscCoverageSnapshots.createdAt)).limit(1).get();
|
|
48092
48246
|
const lastSyncedAt = latestSnapshot?.createdAt ?? null;
|
|
48093
48247
|
const formatRow = (r) => ({
|
|
48094
48248
|
id: r.id,
|
|
@@ -48144,7 +48298,7 @@ async function googleRoutes(app, opts) {
|
|
|
48144
48298
|
const project = resolveProject(app.db, request.params.name);
|
|
48145
48299
|
const parsed = parseInt(request.query.limit ?? "90", 10);
|
|
48146
48300
|
const limit = Number.isNaN(parsed) || parsed <= 0 ? 90 : parsed;
|
|
48147
|
-
const rows = app.db.select().from(gscCoverageSnapshots).where(eq54(gscCoverageSnapshots.projectId, project.id)).orderBy(
|
|
48301
|
+
const rows = app.db.select().from(gscCoverageSnapshots).where(eq54(gscCoverageSnapshots.projectId, project.id)).orderBy(desc27(gscCoverageSnapshots.date)).limit(limit).all();
|
|
48148
48302
|
return rows.map((r) => ({
|
|
48149
48303
|
date: r.date,
|
|
48150
48304
|
indexed: r.indexed,
|
|
@@ -48358,7 +48512,7 @@ async function googleRoutes(app, opts) {
|
|
|
48358
48512
|
const { accessToken } = await getValidToken(store, project.canonicalDomain, "gsc", googleClientId, googleClientSecret);
|
|
48359
48513
|
let urlsToNotify = request.body?.urls ?? [];
|
|
48360
48514
|
if (request.body?.allUnindexed) {
|
|
48361
|
-
const allInspections = app.db.select().from(gscUrlInspections).where(eq54(gscUrlInspections.projectId, project.id)).orderBy(
|
|
48515
|
+
const allInspections = app.db.select().from(gscUrlInspections).where(eq54(gscUrlInspections.projectId, project.id)).orderBy(desc27(gscUrlInspections.inspectedAt)).all();
|
|
48362
48516
|
const latestByUrl = /* @__PURE__ */ new Map();
|
|
48363
48517
|
for (const row of allInspections) {
|
|
48364
48518
|
if (!latestByUrl.has(row.url)) {
|
|
@@ -48725,7 +48879,7 @@ async function googleRoutes(app, opts) {
|
|
|
48725
48879
|
const conditions = [eq54(gbpDailyMetrics.projectId, project.id)];
|
|
48726
48880
|
if (request.query.locationName) conditions.push(eq54(gbpDailyMetrics.locationName, request.query.locationName));
|
|
48727
48881
|
if (request.query.metric) conditions.push(eq54(gbpDailyMetrics.metric, request.query.metric));
|
|
48728
|
-
const rows = app.db.select().from(gbpDailyMetrics).where(and45(...conditions)).orderBy(
|
|
48882
|
+
const rows = app.db.select().from(gbpDailyMetrics).where(and45(...conditions)).orderBy(desc27(gbpDailyMetrics.date)).all();
|
|
48729
48883
|
return {
|
|
48730
48884
|
metrics: rows.map((r) => ({ locationName: r.locationName, date: r.date, metric: r.metric, value: r.value })),
|
|
48731
48885
|
total: rows.length
|
|
@@ -48772,7 +48926,7 @@ async function googleRoutes(app, opts) {
|
|
|
48772
48926
|
const project = resolveProject(app.db, request.params.name);
|
|
48773
48927
|
const conditions = [eq54(gbpLodgingSnapshots.projectId, project.id)];
|
|
48774
48928
|
if (request.query.locationName) conditions.push(eq54(gbpLodgingSnapshots.locationName, request.query.locationName));
|
|
48775
|
-
const rows = app.db.select().from(gbpLodgingSnapshots).where(and45(...conditions)).orderBy(
|
|
48929
|
+
const rows = app.db.select().from(gbpLodgingSnapshots).where(and45(...conditions)).orderBy(desc27(gbpLodgingSnapshots.syncedAt)).all();
|
|
48776
48930
|
const latestByLocation = /* @__PURE__ */ new Map();
|
|
48777
48931
|
for (const row of rows) {
|
|
48778
48932
|
if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
|
|
@@ -48789,7 +48943,7 @@ async function googleRoutes(app, opts) {
|
|
|
48789
48943
|
const project = resolveProject(app.db, request.params.name);
|
|
48790
48944
|
const conditions = [eq54(gbpAttributesSnapshots.projectId, project.id)];
|
|
48791
48945
|
if (request.query.locationName) conditions.push(eq54(gbpAttributesSnapshots.locationName, request.query.locationName));
|
|
48792
|
-
const rows = app.db.select().from(gbpAttributesSnapshots).where(and45(...conditions)).orderBy(
|
|
48946
|
+
const rows = app.db.select().from(gbpAttributesSnapshots).where(and45(...conditions)).orderBy(desc27(gbpAttributesSnapshots.syncedAt)).all();
|
|
48793
48947
|
const latestByLocation = /* @__PURE__ */ new Map();
|
|
48794
48948
|
for (const row of rows) {
|
|
48795
48949
|
if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
|
|
@@ -48809,7 +48963,7 @@ async function googleRoutes(app, opts) {
|
|
|
48809
48963
|
const project = resolveProject(app.db, request.params.name);
|
|
48810
48964
|
const conditions = [eq54(gbpPlaceDetails.projectId, project.id)];
|
|
48811
48965
|
if (request.query.locationName) conditions.push(eq54(gbpPlaceDetails.locationName, request.query.locationName));
|
|
48812
|
-
const rows = app.db.select().from(gbpPlaceDetails).where(and45(...conditions)).orderBy(
|
|
48966
|
+
const rows = app.db.select().from(gbpPlaceDetails).where(and45(...conditions)).orderBy(desc27(gbpPlaceDetails.syncedAt)).all();
|
|
48813
48967
|
const latestByLocation = /* @__PURE__ */ new Map();
|
|
48814
48968
|
for (const row of rows) {
|
|
48815
48969
|
if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
|
|
@@ -48836,7 +48990,7 @@ async function googleRoutes(app, opts) {
|
|
|
48836
48990
|
locationName ? eq54(gbpLocations.locationName, locationName) : eq54(gbpLocations.selected, true)
|
|
48837
48991
|
)).orderBy(gbpLocations.displayName).all();
|
|
48838
48992
|
const latestRating = /* @__PURE__ */ new Map();
|
|
48839
|
-
for (const row of app.db.select().from(gbpReviewRatings).where(eq54(gbpReviewRatings.projectId, project.id)).orderBy(
|
|
48993
|
+
for (const row of app.db.select().from(gbpReviewRatings).where(eq54(gbpReviewRatings.projectId, project.id)).orderBy(desc27(gbpReviewRatings.observedAt)).all()) {
|
|
48840
48994
|
if (!latestRating.has(row.locationName)) latestRating.set(row.locationName, row);
|
|
48841
48995
|
}
|
|
48842
48996
|
const locations = locationRows.map((loc) => {
|
|
@@ -48857,7 +49011,7 @@ async function googleRoutes(app, opts) {
|
|
|
48857
49011
|
if (locationName) conditions.push(eq54(gbpReviews.locationName, locationName));
|
|
48858
49012
|
if (negativeOnly) conditions.push(sql19`${gbpReviews.starRating} BETWEEN 1 AND ${negativeMaxStars}`);
|
|
48859
49013
|
const total = app.db.select({ n: sql19`count(*)` }).from(gbpReviews).where(and45(...conditions)).get()?.n ?? 0;
|
|
48860
|
-
const reviews = app.db.select().from(gbpReviews).where(and45(...conditions)).orderBy(
|
|
49014
|
+
const reviews = app.db.select().from(gbpReviews).where(and45(...conditions)).orderBy(desc27(gbpReviews.updateTime), gbpReviews.reviewName).limit(limit).all().map((r) => ({
|
|
48861
49015
|
locationName: r.locationName,
|
|
48862
49016
|
origin: r.origin,
|
|
48863
49017
|
reviewName: r.reviewName,
|
|
@@ -48896,10 +49050,10 @@ async function googleRoutes(app, opts) {
|
|
|
48896
49050
|
locationProfiles: []
|
|
48897
49051
|
});
|
|
48898
49052
|
}
|
|
48899
|
-
const metricRows = app.db.select().from(gbpDailyMetrics).where(and45(eq54(gbpDailyMetrics.projectId, project.id),
|
|
48900
|
-
const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and45(eq54(gbpKeywordImpressions.projectId, project.id),
|
|
48901
|
-
const placeActionRows = app.db.select().from(gbpPlaceActions).where(and45(eq54(gbpPlaceActions.projectId, project.id),
|
|
48902
|
-
const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and45(eq54(gbpLodgingSnapshots.projectId, project.id),
|
|
49053
|
+
const metricRows = app.db.select().from(gbpDailyMetrics).where(and45(eq54(gbpDailyMetrics.projectId, project.id), inArray25(gbpDailyMetrics.locationName, locationNames))).all();
|
|
49054
|
+
const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and45(eq54(gbpKeywordImpressions.projectId, project.id), inArray25(gbpKeywordImpressions.locationName, locationNames))).all();
|
|
49055
|
+
const placeActionRows = app.db.select().from(gbpPlaceActions).where(and45(eq54(gbpPlaceActions.projectId, project.id), inArray25(gbpPlaceActions.locationName, locationNames))).all();
|
|
49056
|
+
const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and45(eq54(gbpLodgingSnapshots.projectId, project.id), inArray25(gbpLodgingSnapshots.locationName, locationNames))).orderBy(desc27(gbpLodgingSnapshots.syncedAt)).all();
|
|
48903
49057
|
const latestLodgingByLocation = /* @__PURE__ */ new Map();
|
|
48904
49058
|
for (const row of lodgingRows) {
|
|
48905
49059
|
if (!latestLodgingByLocation.has(row.locationName)) {
|
|
@@ -48913,7 +49067,7 @@ async function googleRoutes(app, opts) {
|
|
|
48913
49067
|
regularHours: gbpLocations.regularHours,
|
|
48914
49068
|
primaryPhone: gbpLocations.primaryPhone,
|
|
48915
49069
|
openStatus: gbpLocations.openStatus
|
|
48916
|
-
}).from(gbpLocations).where(and45(eq54(gbpLocations.projectId, project.id),
|
|
49070
|
+
}).from(gbpLocations).where(and45(eq54(gbpLocations.projectId, project.id), inArray25(gbpLocations.locationName, locationNames))).all();
|
|
48917
49071
|
return buildGbpSummary({
|
|
48918
49072
|
locationName,
|
|
48919
49073
|
locationCount: locationNames.length,
|
|
@@ -48944,7 +49098,7 @@ function parseReviewLimit(value) {
|
|
|
48944
49098
|
|
|
48945
49099
|
// ../api-routes/src/google-marketing.ts
|
|
48946
49100
|
import crypto34 from "crypto";
|
|
48947
|
-
import { and as and46, desc as
|
|
49101
|
+
import { and as and46, desc as desc28, eq as eq55, isNull as isNull10, lt as lt9, ne as ne10, or as or13, sql as sql20 } from "drizzle-orm";
|
|
48948
49102
|
import { z as z4 } from "zod";
|
|
48949
49103
|
var snapshotPageQuerySchema = z4.object({
|
|
48950
49104
|
limit: z4.coerce.number().int().min(1).max(GOOGLE_MARKETING_STORED_SNAPSHOT_PAGE_MAX).optional(),
|
|
@@ -50160,7 +50314,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
50160
50314
|
eq55(runs.projectId, project.id),
|
|
50161
50315
|
eq55(runs.kind, RunKinds["google-ads-sync"]),
|
|
50162
50316
|
or13(eq55(runs.status, RunStatuses.queued), eq55(runs.status, RunStatuses.running))
|
|
50163
|
-
)).orderBy(
|
|
50317
|
+
)).orderBy(desc28(runs.createdAt)).get();
|
|
50164
50318
|
if (existing) {
|
|
50165
50319
|
run = existing;
|
|
50166
50320
|
return;
|
|
@@ -50196,7 +50350,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
50196
50350
|
eq55(runs.projectId, project.id),
|
|
50197
50351
|
eq55(runs.kind, RunKinds["gtm-sync"]),
|
|
50198
50352
|
or13(eq55(runs.status, RunStatuses.queued), eq55(runs.status, RunStatuses.running))
|
|
50199
|
-
)).orderBy(
|
|
50353
|
+
)).orderBy(desc28(runs.createdAt)).get();
|
|
50200
50354
|
if (existing) {
|
|
50201
50355
|
run = existing;
|
|
50202
50356
|
return;
|
|
@@ -50231,7 +50385,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
50231
50385
|
));
|
|
50232
50386
|
}
|
|
50233
50387
|
const limit = query.limit ?? 50;
|
|
50234
|
-
const rows = app.db.select().from(googleAdsRawSnapshots).where(and46(...conditions)).orderBy(
|
|
50388
|
+
const rows = app.db.select().from(googleAdsRawSnapshots).where(and46(...conditions)).orderBy(desc28(googleAdsRawSnapshots.capturedAt), desc28(googleAdsRawSnapshots.id)).limit(limit + 1).all();
|
|
50235
50389
|
const page3 = rows.slice(0, limit);
|
|
50236
50390
|
const total = app.db.select({ total: sql20`COUNT(*)`.mapWith(Number).as("total") }).from(googleAdsRawSnapshots).where(eq55(googleAdsRawSnapshots.projectId, project.id)).get();
|
|
50237
50391
|
return {
|
|
@@ -50263,7 +50417,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
50263
50417
|
));
|
|
50264
50418
|
}
|
|
50265
50419
|
const limit = query.limit ?? 50;
|
|
50266
|
-
const rows = app.db.select().from(gtmRawSnapshots).where(and46(...conditions)).orderBy(
|
|
50420
|
+
const rows = app.db.select().from(gtmRawSnapshots).where(and46(...conditions)).orderBy(desc28(gtmRawSnapshots.capturedAt), desc28(gtmRawSnapshots.id)).limit(limit + 1).all();
|
|
50267
50421
|
const page3 = rows.slice(0, limit);
|
|
50268
50422
|
const total = app.db.select({ total: sql20`COUNT(*)`.mapWith(Number).as("total") }).from(gtmRawSnapshots).where(eq55(gtmRawSnapshots.projectId, project.id)).get();
|
|
50269
50423
|
return {
|
|
@@ -50534,7 +50688,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
50534
50688
|
|
|
50535
50689
|
// ../api-routes/src/ads.ts
|
|
50536
50690
|
import crypto37 from "crypto";
|
|
50537
|
-
import { eq as eq57, and as and48, asc as asc11, desc as
|
|
50691
|
+
import { eq as eq57, and as and48, asc as asc11, desc as desc29, gt as gt6, gte as gte14, lt as lt10, lte as lte14, ne as ne11, inArray as inArray26, or as or15, isNull as isNull12, isNotNull as isNotNull7, sql as sql22 } from "drizzle-orm";
|
|
50538
50692
|
|
|
50539
50693
|
// ../api-routes/src/ads-activation.ts
|
|
50540
50694
|
import crypto35 from "crypto";
|
|
@@ -51920,7 +52074,7 @@ async function executeApprovedAdsActivation(dependencies, request) {
|
|
|
51920
52074
|
|
|
51921
52075
|
// ../api-routes/src/ads-activation-routes.ts
|
|
51922
52076
|
import crypto36 from "crypto";
|
|
51923
|
-
import { and as and47, asc as asc10, eq as eq56, gt as
|
|
52077
|
+
import { and as and47, asc as asc10, eq as eq56, gt as gt5, isNotNull as isNotNull6, isNull as isNull11, lte as lte13, or as or14, sql as sql21 } from "drizzle-orm";
|
|
51924
52078
|
var MAX_ACTIVATION_GRANT_LIFETIME_MS = 24 * 60 * 60 * 1e3;
|
|
51925
52079
|
var ACTIVATION_LEASE_MS = 5 * 6e4;
|
|
51926
52080
|
var ACTIVATION_REVOCATION_SETTLEMENT_MS = ACTIVATION_LEASE_MS;
|
|
@@ -52141,7 +52295,7 @@ function createActivationStore(app, request) {
|
|
|
52141
52295
|
eq56(adsOperations.id, input.operationId),
|
|
52142
52296
|
eq56(adsOperations.state, AdsOperationStates.pending),
|
|
52143
52297
|
eq56(adsOperations.leaseOwner, input.leaseOwner),
|
|
52144
|
-
|
|
52298
|
+
gt5(adsOperations.leaseExpiresAt, input.now)
|
|
52145
52299
|
)).run();
|
|
52146
52300
|
const operation = loadActivationOperation(tx, input.operationId);
|
|
52147
52301
|
if (!operation) throw internalError("Ads activation receipt was not found");
|
|
@@ -52197,7 +52351,7 @@ function createActivationStore(app, request) {
|
|
|
52197
52351
|
eq56(adsOperations.id, input.operationId),
|
|
52198
52352
|
eq56(adsOperations.state, AdsOperationStates.pending),
|
|
52199
52353
|
eq56(adsOperations.leaseOwner, input.leaseOwner),
|
|
52200
|
-
|
|
52354
|
+
gt5(adsOperations.leaseExpiresAt, input.next.updatedAt)
|
|
52201
52355
|
)).run();
|
|
52202
52356
|
if (lease.changes !== 1 || existing.state !== input.fromState) {
|
|
52203
52357
|
const current2 = loadActivationOperation(tx, input.operationId);
|
|
@@ -52239,7 +52393,7 @@ function createActivationStore(app, request) {
|
|
|
52239
52393
|
eq56(adsOperations.id, input.operationId),
|
|
52240
52394
|
eq56(adsOperations.state, AdsOperationStates.pending),
|
|
52241
52395
|
eq56(adsOperations.leaseOwner, input.leaseOwner),
|
|
52242
|
-
|
|
52396
|
+
gt5(adsOperations.leaseExpiresAt, input.next.updatedAt)
|
|
52243
52397
|
)).run();
|
|
52244
52398
|
if (lease.changes !== 1 || existing.state !== input.fromState) {
|
|
52245
52399
|
const operation2 = loadActivationOperation(tx, input.operationId);
|
|
@@ -52302,7 +52456,7 @@ function createActivationStore(app, request) {
|
|
|
52302
52456
|
eq56(adsOperations.id, input.operationId),
|
|
52303
52457
|
eq56(adsOperations.state, AdsOperationStates.pending),
|
|
52304
52458
|
eq56(adsOperations.leaseOwner, input.leaseOwner),
|
|
52305
|
-
|
|
52459
|
+
gt5(adsOperations.leaseExpiresAt, input.now)
|
|
52306
52460
|
)).run();
|
|
52307
52461
|
if (operationUpdate.changes === 1) {
|
|
52308
52462
|
const grantUpdate = tx.update(adsActivationGrants).set({
|
|
@@ -53578,7 +53732,7 @@ function semanticallyMatchesMaterializedEntity(app, input) {
|
|
|
53578
53732
|
eq57(adsOperations.projectId, input.projectId),
|
|
53579
53733
|
eq57(adsOperations.entityType, input.entityType),
|
|
53580
53734
|
eq57(adsOperations.entityId, input.entityId),
|
|
53581
|
-
|
|
53735
|
+
inArray26(adsOperations.kind, [createKind, updateKind])
|
|
53582
53736
|
)).orderBy(asc11(adsOperations.createdAt), asc11(adsOperations.id)).all();
|
|
53583
53737
|
if (rows.some((row) => row.state === AdsOperationStates.pending || row.state === AdsOperationStates.reconciling || row.state === AdsOperationStates.unknown || row.kind === updateKind && row.state === AdsOperationStates.succeeded)) {
|
|
53584
53738
|
return false;
|
|
@@ -54015,7 +54169,7 @@ function quarantineExhaustedReconciliation(app, row, now, policy, context) {
|
|
|
54015
54169
|
eq57(adsOperations.id, row.id),
|
|
54016
54170
|
eq57(adsOperations.projectId, row.projectId),
|
|
54017
54171
|
gte14(adsOperations.reconcileAttempts, policy.maxAttempts),
|
|
54018
|
-
|
|
54172
|
+
inArray26(adsOperations.state, [
|
|
54019
54173
|
AdsOperationStates.pending,
|
|
54020
54174
|
AdsOperationStates.unknown,
|
|
54021
54175
|
AdsOperationStates.reconciling
|
|
@@ -54239,7 +54393,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
54239
54393
|
eq57(adsOperations.reconcileStrategy, AdsReconcileStrategies.create_fingerprint),
|
|
54240
54394
|
or15(
|
|
54241
54395
|
isNotNull7(adsOperations.entityId),
|
|
54242
|
-
|
|
54396
|
+
inArray26(adsOperations.state, [
|
|
54243
54397
|
AdsOperationStates.pending,
|
|
54244
54398
|
AdsOperationStates.reconciling
|
|
54245
54399
|
])
|
|
@@ -54287,7 +54441,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
54287
54441
|
const eligibleProjectIds = [...credentialsByProjectId.keys()];
|
|
54288
54442
|
if (eligibleProjectIds.length === 0) return;
|
|
54289
54443
|
const rows = app.db.select().from(adsOperations).where(and48(
|
|
54290
|
-
|
|
54444
|
+
inArray26(adsOperations.projectId, eligibleProjectIds),
|
|
54291
54445
|
staleReconcileWhere
|
|
54292
54446
|
)).orderBy(asc11(adsOperations.updatedAt)).limit(config.batchSize).all();
|
|
54293
54447
|
for (const row of rows) {
|
|
@@ -54609,12 +54763,12 @@ async function adsRoutes(app, opts) {
|
|
|
54609
54763
|
const cursor = parsed.data.cursor ? decodeAdsOperationCursor(parsed.data.cursor, project.id, parsed.data.state) : void 0;
|
|
54610
54764
|
const rows = app.db.select().from(adsOperations).where(and48(
|
|
54611
54765
|
eq57(adsOperations.projectId, project.id),
|
|
54612
|
-
|
|
54766
|
+
inArray26(adsOperations.state, parsed.data.state),
|
|
54613
54767
|
cursor ? or15(
|
|
54614
|
-
|
|
54768
|
+
gt6(adsOperations.createdAt, cursor.createdAt),
|
|
54615
54769
|
and48(
|
|
54616
54770
|
eq57(adsOperations.createdAt, cursor.createdAt),
|
|
54617
|
-
|
|
54771
|
+
gt6(adsOperations.id, cursor.id)
|
|
54618
54772
|
)
|
|
54619
54773
|
) : void 0
|
|
54620
54774
|
)).orderBy(asc11(adsOperations.createdAt), asc11(adsOperations.id)).limit(parsed.data.limit + 1).all();
|
|
@@ -55043,7 +55197,7 @@ async function adsRoutes(app, opts) {
|
|
|
55043
55197
|
const inFlight = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and48(
|
|
55044
55198
|
eq57(runs.projectId, project.id),
|
|
55045
55199
|
eq57(runs.kind, RunKinds["ads-sync"]),
|
|
55046
|
-
|
|
55200
|
+
inArray26(runs.status, [RunStatuses.queued, RunStatuses.running])
|
|
55047
55201
|
)).get();
|
|
55048
55202
|
if (inFlight) {
|
|
55049
55203
|
const existing = { runId: inFlight.id, status: inFlight.status };
|
|
@@ -55174,7 +55328,7 @@ async function adsRoutes(app, opts) {
|
|
|
55174
55328
|
const latestAdsSync = app.db.select({ id: runs.id, kind: runs.kind, status: runs.status }).from(runs).where(and48(
|
|
55175
55329
|
eq57(runs.projectId, project.id),
|
|
55176
55330
|
eq57(runs.kind, RunKinds["ads-sync"])
|
|
55177
|
-
)).orderBy(
|
|
55331
|
+
)).orderBy(desc29(runs.createdAt)).get();
|
|
55178
55332
|
const snapshot = storedSnapshotProvenance({
|
|
55179
55333
|
connected: Boolean(connection),
|
|
55180
55334
|
connectionLastSyncedAt: connection?.lastSyncedAt ?? null,
|
|
@@ -55578,7 +55732,7 @@ async function adsRoutes(app, opts) {
|
|
|
55578
55732
|
|
|
55579
55733
|
// ../api-routes/src/bing.ts
|
|
55580
55734
|
import crypto39 from "crypto";
|
|
55581
|
-
import { eq as eq58, and as and49, desc as
|
|
55735
|
+
import { eq as eq58, and as and49, desc as desc30 } from "drizzle-orm";
|
|
55582
55736
|
|
|
55583
55737
|
// ../integration-bing/src/bing-client.ts
|
|
55584
55738
|
import crypto38 from "crypto";
|
|
@@ -55997,7 +56151,7 @@ async function bingRoutes(app, opts) {
|
|
|
55997
56151
|
const store = requireConnectionStore();
|
|
55998
56152
|
const project = resolveProject(app.db, request.params.name);
|
|
55999
56153
|
requireConnection(store, project.canonicalDomain);
|
|
56000
|
-
const allInspections = app.db.select().from(bingUrlInspections).where(eq58(bingUrlInspections.projectId, project.id)).orderBy(
|
|
56154
|
+
const allInspections = app.db.select().from(bingUrlInspections).where(eq58(bingUrlInspections.projectId, project.id)).orderBy(desc30(bingUrlInspections.inspectedAt)).all();
|
|
56001
56155
|
const latestByUrl = /* @__PURE__ */ new Map();
|
|
56002
56156
|
const definitiveByUrl = /* @__PURE__ */ new Map();
|
|
56003
56157
|
for (const row of allInspections) {
|
|
@@ -56086,7 +56240,7 @@ async function bingRoutes(app, opts) {
|
|
|
56086
56240
|
const project = resolveProject(app.db, request.params.name);
|
|
56087
56241
|
const parsed = parseInt(request.query.limit ?? "90", 10);
|
|
56088
56242
|
const limit = Number.isNaN(parsed) || parsed <= 0 ? 90 : parsed;
|
|
56089
|
-
const rows = app.db.select().from(bingCoverageSnapshots).where(eq58(bingCoverageSnapshots.projectId, project.id)).orderBy(
|
|
56243
|
+
const rows = app.db.select().from(bingCoverageSnapshots).where(eq58(bingCoverageSnapshots.projectId, project.id)).orderBy(desc30(bingCoverageSnapshots.date)).limit(limit).all();
|
|
56090
56244
|
return rows.map((r) => ({
|
|
56091
56245
|
date: r.date,
|
|
56092
56246
|
indexed: r.indexed,
|
|
@@ -56099,7 +56253,7 @@ async function bingRoutes(app, opts) {
|
|
|
56099
56253
|
const project = resolveProject(app.db, request.params.name);
|
|
56100
56254
|
const { url, limit } = request.query;
|
|
56101
56255
|
const whereClause = url ? and49(eq58(bingUrlInspections.projectId, project.id), eq58(bingUrlInspections.url, url)) : eq58(bingUrlInspections.projectId, project.id);
|
|
56102
|
-
const filtered = app.db.select().from(bingUrlInspections).where(whereClause).orderBy(
|
|
56256
|
+
const filtered = app.db.select().from(bingUrlInspections).where(whereClause).orderBy(desc30(bingUrlInspections.inspectedAt)).limit(Math.max(1, Math.min(parseInt(limit ?? "100", 10) || 100, 1e3))).all();
|
|
56103
56257
|
return filtered.map((r) => ({
|
|
56104
56258
|
id: r.id,
|
|
56105
56259
|
url: r.url,
|
|
@@ -56243,7 +56397,7 @@ async function bingRoutes(app, opts) {
|
|
|
56243
56397
|
}
|
|
56244
56398
|
let urlsToSubmit = request.body?.urls ?? [];
|
|
56245
56399
|
if (request.body?.allUnindexed) {
|
|
56246
|
-
const allInspections = app.db.select().from(bingUrlInspections).where(eq58(bingUrlInspections.projectId, project.id)).orderBy(
|
|
56400
|
+
const allInspections = app.db.select().from(bingUrlInspections).where(eq58(bingUrlInspections.projectId, project.id)).orderBy(desc30(bingUrlInspections.inspectedAt)).all();
|
|
56247
56401
|
const latestByUrl = /* @__PURE__ */ new Map();
|
|
56248
56402
|
for (const row of allInspections) {
|
|
56249
56403
|
if (!latestByUrl.has(row.url)) {
|
|
@@ -56502,7 +56656,7 @@ async function cdpRoutes(app, opts) {
|
|
|
56502
56656
|
|
|
56503
56657
|
// ../api-routes/src/ga.ts
|
|
56504
56658
|
import crypto40 from "crypto";
|
|
56505
|
-
import { eq as eq60, desc as
|
|
56659
|
+
import { eq as eq60, desc as desc31, and as and51, sql as sql23 } from "drizzle-orm";
|
|
56506
56660
|
|
|
56507
56661
|
// ../api-routes/src/ga-session-history.ts
|
|
56508
56662
|
function buildSessionHistory(landingPageDays, dailyTotals) {
|
|
@@ -56978,7 +57132,7 @@ async function ga4Routes(app, opts) {
|
|
|
56978
57132
|
if (!connected) {
|
|
56979
57133
|
return { connected: false, propertyId: null, clientEmail: null, authMethod: null, lastSyncedAt: null };
|
|
56980
57134
|
}
|
|
56981
|
-
const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq60(gaTrafficSummaries.projectId, project.id)).orderBy(
|
|
57135
|
+
const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq60(gaTrafficSummaries.projectId, project.id)).orderBy(desc31(gaTrafficSummaries.syncedAt)).limit(1).get();
|
|
56982
57136
|
return {
|
|
56983
57137
|
connected: true,
|
|
56984
57138
|
propertyId: saConn?.propertyId ?? oauthConn?.propertyId ?? null,
|
|
@@ -57408,7 +57562,7 @@ async function ga4Routes(app, opts) {
|
|
|
57408
57562
|
const socialTotals = app.db.select({
|
|
57409
57563
|
sessions: sql23`SUM(${gaSocialReferrals.sessions})`
|
|
57410
57564
|
}).from(gaSocialReferrals).where(and51(...socialConditions)).get();
|
|
57411
|
-
const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq60(gaTrafficSummaries.projectId, project.id)).orderBy(
|
|
57565
|
+
const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq60(gaTrafficSummaries.projectId, project.id)).orderBy(desc31(gaTrafficSummaries.syncedAt)).limit(1).get();
|
|
57412
57566
|
const total = summaryRow?.totalSessions ?? 0;
|
|
57413
57567
|
const totalDirectSessions = directTotalRow?.totalDirectSessions ?? 0;
|
|
57414
57568
|
const totalOrganicSessions = summaryRow?.totalOrganicSessions ?? 0;
|
|
@@ -59360,7 +59514,7 @@ async function wordpressRoutes(app, opts) {
|
|
|
59360
59514
|
|
|
59361
59515
|
// ../api-routes/src/backlinks.ts
|
|
59362
59516
|
import crypto42 from "crypto";
|
|
59363
|
-
import { and as and53, asc as asc12, desc as
|
|
59517
|
+
import { and as and53, asc as asc12, desc as desc32, eq as eq61, sql as sql24 } from "drizzle-orm";
|
|
59364
59518
|
|
|
59365
59519
|
// ../integration-commoncrawl/src/constants.ts
|
|
59366
59520
|
import os2 from "os";
|
|
@@ -59861,7 +60015,7 @@ function latestSummaryForProject(db, projectId, source, release) {
|
|
|
59861
60015
|
eq61(backlinkSummaries.source, source)
|
|
59862
60016
|
];
|
|
59863
60017
|
if (release) conditions.push(eq61(backlinkSummaries.release, release));
|
|
59864
|
-
return db.select().from(backlinkSummaries).where(and53(...conditions)).orderBy(
|
|
60018
|
+
return db.select().from(backlinkSummaries).where(and53(...conditions)).orderBy(desc32(backlinkSummaries.queriedAt)).limit(1).get();
|
|
59865
60019
|
}
|
|
59866
60020
|
function parseExcludeCrawlers(value) {
|
|
59867
60021
|
if (!value) return false;
|
|
@@ -59883,7 +60037,7 @@ function computeFilteredSummary(db, base) {
|
|
|
59883
60037
|
count: sql24`count(*)`,
|
|
59884
60038
|
total: sql24`coalesce(sum(${backlinkDomains.numHosts}), 0)`
|
|
59885
60039
|
}).from(backlinkDomains).where(filteredCondition).get();
|
|
59886
|
-
const top10Rows = db.select({ numHosts: backlinkDomains.numHosts }).from(backlinkDomains).where(filteredCondition).orderBy(
|
|
60040
|
+
const top10Rows = db.select({ numHosts: backlinkDomains.numHosts }).from(backlinkDomains).where(filteredCondition).orderBy(desc32(backlinkDomains.numHosts)).limit(10).all();
|
|
59887
60041
|
const totalLinkingDomains = Number(filteredAgg?.count ?? 0);
|
|
59888
60042
|
const totalHosts = Number(filteredAgg?.total ?? 0);
|
|
59889
60043
|
const unfilteredLinkingDomains = Number(unfilteredAgg?.count ?? 0);
|
|
@@ -59904,7 +60058,7 @@ function computeFilteredSummary(db, base) {
|
|
|
59904
60058
|
};
|
|
59905
60059
|
}
|
|
59906
60060
|
function buildSourceAvailability(db, projectId, source, connected, excludeCrawlers) {
|
|
59907
|
-
const summary3 = db.select().from(backlinkSummaries).where(and53(eq61(backlinkSummaries.projectId, projectId), eq61(backlinkSummaries.source, source))).orderBy(
|
|
60061
|
+
const summary3 = db.select().from(backlinkSummaries).where(and53(eq61(backlinkSummaries.projectId, projectId), eq61(backlinkSummaries.source, source))).orderBy(desc32(backlinkSummaries.queriedAt)).limit(1).get();
|
|
59908
60062
|
let totalLinkingDomains = summary3?.totalLinkingDomains ?? 0;
|
|
59909
60063
|
if (summary3 && excludeCrawlers) {
|
|
59910
60064
|
const filtered = db.select({ count: sql24`count(*)` }).from(backlinkDomains).where(and53(
|
|
@@ -60009,11 +60163,11 @@ async function backlinksRoutes(app, opts) {
|
|
|
60009
60163
|
return reply.status(201).send(mapSyncRow(inserted));
|
|
60010
60164
|
});
|
|
60011
60165
|
app.get("/backlinks/syncs/latest", async (_request, reply) => {
|
|
60012
|
-
const row = app.db.select().from(ccReleaseSyncs).orderBy(
|
|
60166
|
+
const row = app.db.select().from(ccReleaseSyncs).orderBy(desc32(ccReleaseSyncs.updatedAt)).limit(1).get();
|
|
60013
60167
|
return reply.send(row ? mapSyncRow(row) : null);
|
|
60014
60168
|
});
|
|
60015
60169
|
app.get("/backlinks/syncs", async (_request, reply) => {
|
|
60016
|
-
const rows = app.db.select().from(ccReleaseSyncs).orderBy(
|
|
60170
|
+
const rows = app.db.select().from(ccReleaseSyncs).orderBy(desc32(ccReleaseSyncs.updatedAt)).all();
|
|
60017
60171
|
return reply.send(rows.map(mapSyncRow));
|
|
60018
60172
|
});
|
|
60019
60173
|
app.get("/backlinks/releases", async (_request, reply) => {
|
|
@@ -60100,7 +60254,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
60100
60254
|
linkingDomain: backlinkDomains.linkingDomain,
|
|
60101
60255
|
numHosts: backlinkDomains.numHosts,
|
|
60102
60256
|
source: backlinkDomains.source
|
|
60103
|
-
}).from(backlinkDomains).where(domainCondition).orderBy(
|
|
60257
|
+
}).from(backlinkDomains).where(domainCondition).orderBy(desc32(backlinkDomains.numHosts)).limit(limit).offset(offset).all();
|
|
60104
60258
|
let summary3 = null;
|
|
60105
60259
|
if (summaryRow) {
|
|
60106
60260
|
summary3 = excludeCrawlers ? computeFilteredSummary(app.db, summaryRow) : mapSummaryRow(summaryRow);
|
|
@@ -60146,7 +60300,7 @@ import crypto45 from "crypto";
|
|
|
60146
60300
|
import { isIP } from "net";
|
|
60147
60301
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
60148
60302
|
import { Agent as UndiciAgent } from "undici";
|
|
60149
|
-
import { and as and57, desc as
|
|
60303
|
+
import { and as and57, desc as desc33, eq as eq65, gte as gte16, inArray as inArray27, lte as lte17, sql as sql27 } from "drizzle-orm";
|
|
60150
60304
|
|
|
60151
60305
|
// ../api-routes/src/cloudflare-worker-version.ts
|
|
60152
60306
|
var CURRENT_CLOUDFLARE_WORKER_VERSION = "1.0.1";
|
|
@@ -79330,7 +79484,8 @@ async function trafficRoutes(app, opts) {
|
|
|
79330
79484
|
allEvents = drained.events;
|
|
79331
79485
|
} catch (e) {
|
|
79332
79486
|
const msg = describeError(e);
|
|
79333
|
-
|
|
79487
|
+
const credentialRefused = e instanceof VercelLogsApiError && (e.status === 401 || e.status === 403);
|
|
79488
|
+
markFailed(msg, credentialRefused ? "PROVIDER_AUTH" : "PROVIDER_PULL");
|
|
79334
79489
|
throw providerError(`Vercel pull failed: ${msg}`);
|
|
79335
79490
|
}
|
|
79336
79491
|
}
|
|
@@ -79887,7 +80042,7 @@ async function trafficRoutes(app, opts) {
|
|
|
79887
80042
|
eq65(runs.kind, RunKinds["traffic-sync"]),
|
|
79888
80043
|
eq65(runs.sourceId, row.id)
|
|
79889
80044
|
)
|
|
79890
|
-
).orderBy(
|
|
80045
|
+
).orderBy(desc33(runs.startedAt)).limit(1).get();
|
|
79891
80046
|
return {
|
|
79892
80047
|
...rowToDto(row),
|
|
79893
80048
|
totals24h: {
|
|
@@ -79966,14 +80121,14 @@ async function trafficRoutes(app, opts) {
|
|
|
79966
80121
|
});
|
|
79967
80122
|
app.get("/projects/:name/traffic/sources", async (request) => {
|
|
79968
80123
|
const project = resolveProject(app.db, request.params.name);
|
|
79969
|
-
const rows = app.db.select().from(trafficSources).where(eq65(trafficSources.projectId, project.id)).orderBy(
|
|
80124
|
+
const rows = app.db.select().from(trafficSources).where(eq65(trafficSources.projectId, project.id)).orderBy(desc33(trafficSources.createdAt)).all();
|
|
79970
80125
|
const sources = rows.filter((row) => row.status !== TrafficSourceStatuses.archived).map(rowToDto);
|
|
79971
80126
|
const response = { sources };
|
|
79972
80127
|
return response;
|
|
79973
80128
|
});
|
|
79974
80129
|
app.get("/projects/:name/traffic/status", async (request) => {
|
|
79975
80130
|
const project = resolveProject(app.db, request.params.name);
|
|
79976
|
-
const rows = app.db.select().from(trafficSources).where(eq65(trafficSources.projectId, project.id)).orderBy(
|
|
80131
|
+
const rows = app.db.select().from(trafficSources).where(eq65(trafficSources.projectId, project.id)).orderBy(desc33(trafficSources.createdAt)).all();
|
|
79977
80132
|
const since = new Date(Date.now() - 24 * 60 * 6e4).toISOString();
|
|
79978
80133
|
const sources = rows.filter((row) => row.status !== TrafficSourceStatuses.archived).map((row) => buildSourceDetail(project.id, row, since));
|
|
79979
80134
|
const response = { sources };
|
|
@@ -80084,7 +80239,7 @@ async function trafficRoutes(app, opts) {
|
|
|
80084
80239
|
const listed = useContentList ? contentPaths : infraPaths;
|
|
80085
80240
|
const IN_LIST_CAP = 2e4;
|
|
80086
80241
|
const listFitsInSql = listed.length <= IN_LIST_CAP;
|
|
80087
|
-
const contentExpr = listed.length === 0 ? useContentList ? sql27`0` : sql27`${crawlerEventsHourly.hits}` : useContentList ? sql27`CASE WHEN ${
|
|
80242
|
+
const contentExpr = listed.length === 0 ? useContentList ? sql27`0` : sql27`${crawlerEventsHourly.hits}` : useContentList ? sql27`CASE WHEN ${inArray27(crawlerEventsHourly.pathNormalized, listed)} THEN ${crawlerEventsHourly.hits} ELSE 0 END` : sql27`CASE WHEN ${inArray27(crawlerEventsHourly.pathNormalized, listed)} THEN 0 ELSE ${crawlerEventsHourly.hits} END`;
|
|
80088
80243
|
if (listFitsInSql) {
|
|
80089
80244
|
const crawlerSeries = app.db.select({
|
|
80090
80245
|
bucket: crawlerSeriesBucket,
|
|
@@ -80111,7 +80266,7 @@ async function trafficRoutes(app, opts) {
|
|
|
80111
80266
|
if (useContentList ? inList : !inList) point.crawlerContentHits += hits;
|
|
80112
80267
|
}
|
|
80113
80268
|
}
|
|
80114
|
-
const rows = app.db.select().from(crawlerEventsHourly).where(crawlerWhere).orderBy(
|
|
80269
|
+
const rows = app.db.select().from(crawlerEventsHourly).where(crawlerWhere).orderBy(desc33(crawlerEventsHourly.tsHour)).limit(limit).all();
|
|
80115
80270
|
for (const r of rows) {
|
|
80116
80271
|
events.push({
|
|
80117
80272
|
kind: TrafficEventKinds.crawler,
|
|
@@ -80151,7 +80306,7 @@ async function trafficRoutes(app, opts) {
|
|
|
80151
80306
|
for (const row of userFetchSeries) {
|
|
80152
80307
|
trafficSeriesPoint(seriesByBucket, row.bucket).aiUserFetchHits = Number(row.hits);
|
|
80153
80308
|
}
|
|
80154
|
-
const rows = app.db.select().from(aiUserFetchEventsHourly).where(userFetchWhere).orderBy(
|
|
80309
|
+
const rows = app.db.select().from(aiUserFetchEventsHourly).where(userFetchWhere).orderBy(desc33(aiUserFetchEventsHourly.tsHour)).limit(limit).all();
|
|
80155
80310
|
for (const r of rows) {
|
|
80156
80311
|
events.push({
|
|
80157
80312
|
kind: TrafficEventKinds["ai-user-fetch"],
|
|
@@ -80204,7 +80359,7 @@ async function trafficRoutes(app, opts) {
|
|
|
80204
80359
|
point.aiReferralHits = Number(row.hits);
|
|
80205
80360
|
point.aiReferralLandedHits = Number(row.landed);
|
|
80206
80361
|
}
|
|
80207
|
-
const rows = app.db.select().from(aiReferralEventsHourly).where(aiWhere).orderBy(
|
|
80362
|
+
const rows = app.db.select().from(aiReferralEventsHourly).where(aiWhere).orderBy(desc33(aiReferralEventsHourly.tsHour)).limit(limit).all();
|
|
80208
80363
|
for (const r of rows) {
|
|
80209
80364
|
const counts2 = aiReferralClassCounts(r.sessionsOrHits, r.paidSessionsOrHits, r.organicSessionsOrHits);
|
|
80210
80365
|
events.push({
|
|
@@ -80473,7 +80628,7 @@ var reportSweepsCheck = {
|
|
|
80473
80628
|
};
|
|
80474
80629
|
|
|
80475
80630
|
// ../api-routes/src/doctor/checks/report-models.ts
|
|
80476
|
-
import { and as and59, eq as eq67, gte as gte18, inArray as
|
|
80631
|
+
import { and as and59, eq as eq67, gte as gte18, inArray as inArray28, lte as lte19 } from "drizzle-orm";
|
|
80477
80632
|
var reportModelsCheck = {
|
|
80478
80633
|
id: "report.models",
|
|
80479
80634
|
category: CheckCategories.providers,
|
|
@@ -80488,7 +80643,7 @@ var reportModelsCheck = {
|
|
|
80488
80643
|
const months = reportMonths.flatMap((month) => {
|
|
80489
80644
|
const bounds = calendarMonthBounds(month);
|
|
80490
80645
|
const previous = new Date(Date.parse(bounds.since) - 1).toISOString().slice(0, 7);
|
|
80491
|
-
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"]),
|
|
80646
|
+
const observations = ctx.db.select({ provider: querySnapshots.provider, model: querySnapshots.model, at: runs.createdAt }).from(querySnapshots).innerJoin(runs, eq67(runs.id, querySnapshots.runId)).where(and59(eq67(runs.projectId, ctx.project.id), eq67(runs.kind, RunKinds["answer-visibility"]), inArray28(runs.status, [RunStatuses.completed, RunStatuses.partial]), notProbeRun(), gte18(runs.createdAt, bounds.since), lte19(runs.createdAt, bounds.until))).all();
|
|
80492
80647
|
return readVisibilityContinuity(ctx.db, ctx.project.name, { from: previous, to: month }).map(({ frame, continuity: continuity2 }) => ({
|
|
80493
80648
|
month,
|
|
80494
80649
|
previousMonth: previous,
|
|
@@ -81565,7 +81720,7 @@ var ga4ConnectionCheck = {
|
|
|
81565
81720
|
var GA_AUTH_CHECKS = [ga4ConnectionCheck];
|
|
81566
81721
|
|
|
81567
81722
|
// ../api-routes/src/doctor/checks/data-freshness.ts
|
|
81568
|
-
import { and as and62, desc as
|
|
81723
|
+
import { and as and62, desc as desc34, eq as eq73, inArray as inArray29 } from "drizzle-orm";
|
|
81569
81724
|
var GA_DATA_AGING_DAYS = 3;
|
|
81570
81725
|
var GA_DATA_STALE_DAYS = 5;
|
|
81571
81726
|
var GSC_DATA_AGING_DAYS = 5;
|
|
@@ -81593,7 +81748,7 @@ function skipped(code, summary3) {
|
|
|
81593
81748
|
return { status: CheckStatuses.skipped, code, summary: summary3, remediation: null };
|
|
81594
81749
|
}
|
|
81595
81750
|
function lastSyncAgeDays(ctx, kinds) {
|
|
81596
|
-
const row = ctx.db.select({ createdAt: runs.createdAt }).from(runs).where(and62(eq73(runs.projectId, ctx.project.id),
|
|
81751
|
+
const row = ctx.db.select({ createdAt: runs.createdAt }).from(runs).where(and62(eq73(runs.projectId, ctx.project.id), inArray29(runs.kind, kinds), eq73(runs.status, "completed"))).orderBy(desc34(runs.createdAt)).limit(1).get();
|
|
81597
81752
|
if (!row?.createdAt) return null;
|
|
81598
81753
|
const age = Math.floor((Date.now() - Date.parse(row.createdAt)) / DAY_MS2);
|
|
81599
81754
|
return Number.isFinite(age) ? age : null;
|
|
@@ -81689,7 +81844,7 @@ var gaRecentDataCheck = {
|
|
|
81689
81844
|
const connection = gaConnected(ctx);
|
|
81690
81845
|
if (connection === "store-unavailable") return skipped("ga.data.store-unavailable", "No GA4 credential store configured for this deployment.");
|
|
81691
81846
|
if (connection === "not-connected") return skipped("ga.data.not-connected", "GA4 is not connected for this project.");
|
|
81692
|
-
const newest = ctx.db.select({ date: gaDailyTotals.date }).from(gaDailyTotals).where(eq73(gaDailyTotals.projectId, ctx.project.id)).orderBy(
|
|
81847
|
+
const newest = ctx.db.select({ date: gaDailyTotals.date }).from(gaDailyTotals).where(eq73(gaDailyTotals.projectId, ctx.project.id)).orderBy(desc34(gaDailyTotals.date)).limit(1).get();
|
|
81693
81848
|
return grade(ctx, GA_SPEC, newest?.date);
|
|
81694
81849
|
}
|
|
81695
81850
|
};
|
|
@@ -81706,7 +81861,7 @@ var gscRecentDataCheck = {
|
|
|
81706
81861
|
}
|
|
81707
81862
|
const watermark = ctx.db.select({ dataThroughDate: gscDataWatermarks.dataThroughDate }).from(gscDataWatermarks).where(eq73(gscDataWatermarks.projectId, ctx.project.id)).get();
|
|
81708
81863
|
if (watermark?.dataThroughDate) return grade(ctx, GSC_SPEC, watermark.dataThroughDate);
|
|
81709
|
-
const newest = ctx.db.select({ date: gscDailyTotals.date }).from(gscDailyTotals).where(eq73(gscDailyTotals.projectId, ctx.project.id)).orderBy(
|
|
81864
|
+
const newest = ctx.db.select({ date: gscDailyTotals.date }).from(gscDailyTotals).where(eq73(gscDailyTotals.projectId, ctx.project.id)).orderBy(desc34(gscDailyTotals.date)).limit(1).get();
|
|
81710
81865
|
return grade(ctx, GSC_SPEC, newest?.date);
|
|
81711
81866
|
}
|
|
81712
81867
|
};
|
|
@@ -82962,7 +83117,7 @@ var RUNTIME_STATE_CHECKS = [
|
|
|
82962
83117
|
];
|
|
82963
83118
|
|
|
82964
83119
|
// ../api-routes/src/doctor/checks/traffic-source.ts
|
|
82965
|
-
import { and as and65, eq as eq77, gte as gte19, inArray as
|
|
83120
|
+
import { and as and65, eq as eq77, gte as gte19, inArray as inArray30, ne as ne14, sql as sql28 } from "drizzle-orm";
|
|
82966
83121
|
var RECENT_DATA_WARN_DAYS = 7;
|
|
82967
83122
|
var RECENT_DATA_FAIL_DAYS = 30;
|
|
82968
83123
|
function isCloudflareDirectPush(source) {
|
|
@@ -83110,7 +83265,7 @@ var recentDataCheck = {
|
|
|
83110
83265
|
ctx.db.select({ total: sql28`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
83111
83266
|
and65(
|
|
83112
83267
|
eq77(crawlerEventsHourly.projectId, ctx.project.id),
|
|
83113
|
-
|
|
83268
|
+
inArray30(crawlerEventsHourly.sourceId, activeSourceIds),
|
|
83114
83269
|
gte19(crawlerEventsHourly.tsHour, warnCutoff)
|
|
83115
83270
|
)
|
|
83116
83271
|
).get()?.total ?? 0
|
|
@@ -83119,7 +83274,7 @@ var recentDataCheck = {
|
|
|
83119
83274
|
ctx.db.select({ total: sql28`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
83120
83275
|
and65(
|
|
83121
83276
|
eq77(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
83122
|
-
|
|
83277
|
+
inArray30(aiReferralEventsHourly.sourceId, activeSourceIds),
|
|
83123
83278
|
gte19(aiReferralEventsHourly.tsHour, warnCutoff)
|
|
83124
83279
|
)
|
|
83125
83280
|
).get()?.total ?? 0
|
|
@@ -83128,7 +83283,7 @@ var recentDataCheck = {
|
|
|
83128
83283
|
ctx.db.select({ total: sql28`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
83129
83284
|
and65(
|
|
83130
83285
|
eq77(aiUserFetchEventsHourly.projectId, ctx.project.id),
|
|
83131
|
-
|
|
83286
|
+
inArray30(aiUserFetchEventsHourly.sourceId, activeSourceIds),
|
|
83132
83287
|
gte19(aiUserFetchEventsHourly.tsHour, warnCutoff)
|
|
83133
83288
|
)
|
|
83134
83289
|
).get()?.total ?? 0
|
|
@@ -83154,7 +83309,7 @@ var recentDataCheck = {
|
|
|
83154
83309
|
ctx.db.select({ total: sql28`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
83155
83310
|
and65(
|
|
83156
83311
|
eq77(crawlerEventsHourly.projectId, ctx.project.id),
|
|
83157
|
-
|
|
83312
|
+
inArray30(crawlerEventsHourly.sourceId, activeSourceIds),
|
|
83158
83313
|
gte19(crawlerEventsHourly.tsHour, failCutoff)
|
|
83159
83314
|
)
|
|
83160
83315
|
).get()?.total ?? 0
|
|
@@ -83163,7 +83318,7 @@ var recentDataCheck = {
|
|
|
83163
83318
|
ctx.db.select({ total: sql28`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
83164
83319
|
and65(
|
|
83165
83320
|
eq77(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
83166
|
-
|
|
83321
|
+
inArray30(aiReferralEventsHourly.sourceId, activeSourceIds),
|
|
83167
83322
|
gte19(aiReferralEventsHourly.tsHour, failCutoff)
|
|
83168
83323
|
)
|
|
83169
83324
|
).get()?.total ?? 0
|
|
@@ -83172,7 +83327,7 @@ var recentDataCheck = {
|
|
|
83172
83327
|
ctx.db.select({ total: sql28`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
83173
83328
|
and65(
|
|
83174
83329
|
eq77(aiUserFetchEventsHourly.projectId, ctx.project.id),
|
|
83175
|
-
|
|
83330
|
+
inArray30(aiUserFetchEventsHourly.sourceId, activeSourceIds),
|
|
83176
83331
|
gte19(aiUserFetchEventsHourly.tsHour, failCutoff)
|
|
83177
83332
|
)
|
|
83178
83333
|
).get()?.total ?? 0
|
|
@@ -84179,7 +84334,7 @@ async function doctorRoutes(app, opts) {
|
|
|
84179
84334
|
|
|
84180
84335
|
// ../api-routes/src/discovery/routes.ts
|
|
84181
84336
|
import crypto47 from "crypto";
|
|
84182
|
-
import { and as and66, desc as
|
|
84337
|
+
import { and as and66, desc as desc35, eq as eq78, gte as gte20, inArray as inArray31, isNull as isNull14, or as or17 } from "drizzle-orm";
|
|
84183
84338
|
var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
|
|
84184
84339
|
async function discoveryRoutes(app, opts) {
|
|
84185
84340
|
app.post("/projects/:name/discover/run", async (request, reply) => {
|
|
@@ -84234,13 +84389,13 @@ async function discoveryRoutes(app, opts) {
|
|
|
84234
84389
|
// must never reuse another set's session. Null (= Gemini-only
|
|
84235
84390
|
// default, including explicit ['gemini']) matches legacy rows.
|
|
84236
84391
|
seedProviders == null ? isNull14(discoverySessions.seedProviders) : eq78(discoverySessions.seedProviders, seedProviders),
|
|
84237
|
-
|
|
84392
|
+
inArray31(discoverySessions.status, [
|
|
84238
84393
|
DiscoverySessionStatuses.queued,
|
|
84239
84394
|
DiscoverySessionStatuses.seeding,
|
|
84240
84395
|
DiscoverySessionStatuses.probing
|
|
84241
84396
|
]),
|
|
84242
84397
|
gte20(discoverySessions.createdAt, ageFloorIso)
|
|
84243
|
-
)).orderBy(
|
|
84398
|
+
)).orderBy(desc35(discoverySessions.createdAt)).get();
|
|
84244
84399
|
if (existing && existing.runId) {
|
|
84245
84400
|
return { reused: true, sessionId: existing.id, runId: existing.runId };
|
|
84246
84401
|
}
|
|
@@ -84309,7 +84464,7 @@ async function discoveryRoutes(app, opts) {
|
|
|
84309
84464
|
const project = resolveProject(app.db, request.params.name);
|
|
84310
84465
|
const parsedLimit = parseInt(request.query.limit ?? "", 10);
|
|
84311
84466
|
const limit = Number.isNaN(parsedLimit) || parsedLimit <= 0 ? 50 : parsedLimit;
|
|
84312
|
-
const rows = app.db.select().from(discoverySessions).where(eq78(discoverySessions.projectId, project.id)).orderBy(
|
|
84467
|
+
const rows = app.db.select().from(discoverySessions).where(eq78(discoverySessions.projectId, project.id)).orderBy(desc35(discoverySessions.createdAt)).limit(limit).all();
|
|
84313
84468
|
return reply.send(rows.map(serializeSession));
|
|
84314
84469
|
}
|
|
84315
84470
|
);
|
|
@@ -84933,7 +85088,7 @@ function dedupeStrings(input) {
|
|
|
84933
85088
|
|
|
84934
85089
|
// ../api-routes/src/technical-aeo.ts
|
|
84935
85090
|
import crypto49 from "crypto";
|
|
84936
|
-
import { and as and67, asc as asc14, count as count2, desc as
|
|
85091
|
+
import { and as and67, asc as asc14, count as count2, desc as desc36, eq as eq80, inArray as inArray32, isNotNull as isNotNull8, isNull as isNull15, lt as lt13, or as or18, sql as sql29 } from "drizzle-orm";
|
|
84937
85092
|
import { alias } from "drizzle-orm/sqlite-core";
|
|
84938
85093
|
var FETCHED_SITE_CRAWL_STATES = /* @__PURE__ */ new Set([
|
|
84939
85094
|
...SiteCrawlFetchedStates,
|
|
@@ -85258,11 +85413,11 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85258
85413
|
eq80(siteCrawlSnapshots.projectId, projectId),
|
|
85259
85414
|
eq80(runs.projectId, projectId),
|
|
85260
85415
|
eq80(runs.kind, RunKinds["site-audit"]),
|
|
85261
|
-
|
|
85416
|
+
inArray32(runs.status, SURFACEABLE_STATUSES),
|
|
85262
85417
|
notProbeRun()
|
|
85263
85418
|
];
|
|
85264
85419
|
if (runId) filters.push(eq80(siteCrawlSnapshots.runId, runId));
|
|
85265
|
-
return app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq80(siteCrawlSnapshots.runId, runs.id)).where(and67(...filters)).orderBy(
|
|
85420
|
+
return app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq80(siteCrawlSnapshots.runId, runs.id)).where(and67(...filters)).orderBy(desc36(siteCrawlSnapshots.createdAt), desc36(siteCrawlSnapshots.runId)).limit(1).get();
|
|
85266
85421
|
};
|
|
85267
85422
|
const detailScopeFor = (projectId, snapshot) => snapshot.detailsAvailable && snapshot.attemptId ? { projectId, runId: snapshot.runId, attemptId: snapshot.attemptId } : null;
|
|
85268
85423
|
const completenessOf = (snapshot) => ({
|
|
@@ -85289,7 +85444,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85289
85444
|
eq80(runs.id, runId),
|
|
85290
85445
|
eq80(runs.projectId, projectId),
|
|
85291
85446
|
eq80(runs.kind, RunKinds["site-audit"]),
|
|
85292
|
-
|
|
85447
|
+
inArray32(runs.status, SURFACEABLE_STATUSES),
|
|
85293
85448
|
notProbeRun()
|
|
85294
85449
|
)).limit(1).get());
|
|
85295
85450
|
const assertKnownAuditRun = (projectId, runId) => {
|
|
@@ -85299,7 +85454,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85299
85454
|
eq80(siteAuditSnapshots.projectId, projectId),
|
|
85300
85455
|
eq80(runs.projectId, projectId),
|
|
85301
85456
|
eq80(runs.kind, RunKinds["site-audit"]),
|
|
85302
|
-
|
|
85457
|
+
inArray32(runs.status, SURFACEABLE_STATUSES),
|
|
85303
85458
|
notProbeRun()
|
|
85304
85459
|
)).limit(1).get());
|
|
85305
85460
|
const emptyCrawlSummary = (projectName, legacyAuditAvailable) => ({
|
|
@@ -85323,17 +85478,17 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85323
85478
|
eq80(siteAuditSnapshots.projectId, project.id),
|
|
85324
85479
|
eq80(runs.projectId, project.id),
|
|
85325
85480
|
eq80(runs.kind, RunKinds["site-audit"]),
|
|
85326
|
-
|
|
85481
|
+
inArray32(runs.status, SURFACEABLE_STATUSES),
|
|
85327
85482
|
notProbeRun()
|
|
85328
85483
|
];
|
|
85329
85484
|
const targetFilters = request.query.runId ? [...baseFilters, eq80(siteAuditSnapshots.runId, request.query.runId)] : baseFilters;
|
|
85330
|
-
const latest = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq80(siteAuditSnapshots.runId, runs.id)).where(and67(...targetFilters)).orderBy(
|
|
85485
|
+
const latest = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq80(siteAuditSnapshots.runId, runs.id)).where(and67(...targetFilters)).orderBy(desc36(siteAuditSnapshots.createdAt)).limit(1).get();
|
|
85331
85486
|
if (!latest) {
|
|
85332
85487
|
if (request.query.runId) throw notFound("Site audit run", request.query.runId);
|
|
85333
85488
|
return emptyScore(project.name);
|
|
85334
85489
|
}
|
|
85335
85490
|
const snap = latest.snap;
|
|
85336
|
-
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(
|
|
85491
|
+
const previous = app.db.select({ snap: siteAuditSnapshots }).from(siteAuditSnapshots).innerJoin(runs, eq80(siteAuditSnapshots.runId, runs.id)).where(and67(...baseFilters, lt13(siteAuditSnapshots.createdAt, snap.createdAt))).orderBy(desc36(siteAuditSnapshots.createdAt)).limit(1).get()?.snap ?? null;
|
|
85337
85492
|
const deltaScore = previous ? snap.aggregateScore - previous.aggregateScore : null;
|
|
85338
85493
|
const trend = deltaScore == null ? null : deltaScore > 0 ? SiteAuditTrendDirections.up : deltaScore < 0 ? SiteAuditTrendDirections.down : SiteAuditTrendDirections.flat;
|
|
85339
85494
|
return {
|
|
@@ -85363,11 +85518,11 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85363
85518
|
eq80(siteAuditSnapshots.projectId, project.id),
|
|
85364
85519
|
eq80(runs.projectId, project.id),
|
|
85365
85520
|
eq80(runs.kind, RunKinds["site-audit"]),
|
|
85366
|
-
|
|
85521
|
+
inArray32(runs.status, SURFACEABLE_STATUSES),
|
|
85367
85522
|
notProbeRun()
|
|
85368
85523
|
];
|
|
85369
85524
|
if (request.query.runId) targetFilters.push(eq80(siteAuditSnapshots.runId, request.query.runId));
|
|
85370
|
-
const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq80(siteAuditSnapshots.runId, runs.id)).where(and67(...targetFilters)).orderBy(
|
|
85525
|
+
const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq80(siteAuditSnapshots.runId, runs.id)).where(and67(...targetFilters)).orderBy(desc36(siteAuditSnapshots.createdAt)).limit(1).get();
|
|
85371
85526
|
if (!latest && request.query.runId) {
|
|
85372
85527
|
throw notFound("Site audit run", request.query.runId);
|
|
85373
85528
|
}
|
|
@@ -85382,7 +85537,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85382
85537
|
const total = totalRow?.value ?? 0;
|
|
85383
85538
|
const limit = parsePositiveInt(request.query.limit, 100, 500);
|
|
85384
85539
|
const offset = parsePositiveInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER);
|
|
85385
|
-
const orderBy = request.query.sort === "score-desc" ?
|
|
85540
|
+
const orderBy = request.query.sort === "score-desc" ? desc36(siteAuditPages.overallScore) : request.query.sort === "url" ? asc14(siteAuditPages.url) : asc14(siteAuditPages.overallScore);
|
|
85386
85541
|
const rows = app.db.select().from(siteAuditPages).where(where).orderBy(orderBy).limit(limit).offset(offset).all();
|
|
85387
85542
|
const pages = rows.map((row) => ({
|
|
85388
85543
|
url: row.url,
|
|
@@ -85405,9 +85560,9 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85405
85560
|
eq80(siteAuditSnapshots.projectId, project.id),
|
|
85406
85561
|
eq80(runs.projectId, project.id),
|
|
85407
85562
|
eq80(runs.kind, RunKinds["site-audit"]),
|
|
85408
|
-
|
|
85563
|
+
inArray32(runs.status, SURFACEABLE_STATUSES),
|
|
85409
85564
|
notProbeRun()
|
|
85410
|
-
)).orderBy(
|
|
85565
|
+
)).orderBy(desc36(siteAuditSnapshots.createdAt)).limit(limit).all();
|
|
85411
85566
|
return { project: project.name, points: rows.reverse() };
|
|
85412
85567
|
});
|
|
85413
85568
|
app.get("/projects/:name/technical-aeo/crawl", async (request) => {
|
|
@@ -85713,8 +85868,8 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85713
85868
|
eq80(siteCrawlEdges.internal, true),
|
|
85714
85869
|
isNotNull8(siteCrawlEdges.targetNodeKey),
|
|
85715
85870
|
or18(
|
|
85716
|
-
|
|
85717
|
-
|
|
85871
|
+
inArray32(siteCrawlEdges.sourceNodeKey, frontier),
|
|
85872
|
+
inArray32(siteCrawlEdges.targetNodeKey, frontier)
|
|
85718
85873
|
)
|
|
85719
85874
|
)).orderBy(asc14(siteCrawlEdges.edgeKey)).limit(maxEdges + maxNodes + 1).all();
|
|
85720
85875
|
if (candidates.length > maxEdges + maxNodes) queryTruncated = true;
|
|
@@ -85751,7 +85906,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85751
85906
|
eq80(siteCrawlPages.projectId, scope.projectId),
|
|
85752
85907
|
eq80(siteCrawlPages.runId, scope.runId),
|
|
85753
85908
|
eq80(siteCrawlPages.attemptId, scope.attemptId),
|
|
85754
|
-
|
|
85909
|
+
inArray32(siteCrawlPages.nodeKey, nodeKeys)
|
|
85755
85910
|
)).all();
|
|
85756
85911
|
const persistedNodeKeys = new Set(pageRows.map((row) => row.nodeKey));
|
|
85757
85912
|
const outermostNodeKeys = pageRows.filter((row) => distances.get(row.nodeKey) === hops).map((row) => row.nodeKey);
|
|
@@ -85761,8 +85916,8 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85761
85916
|
eq80(siteCrawlEdges.attemptId, scope.attemptId),
|
|
85762
85917
|
eq80(siteCrawlEdges.internal, true),
|
|
85763
85918
|
isNotNull8(siteCrawlEdges.targetNodeKey),
|
|
85764
|
-
|
|
85765
|
-
|
|
85919
|
+
inArray32(siteCrawlEdges.sourceNodeKey, outermostNodeKeys),
|
|
85920
|
+
inArray32(siteCrawlEdges.targetNodeKey, outermostNodeKeys)
|
|
85766
85921
|
)).limit(1).get();
|
|
85767
85922
|
if (omittedOutermostEdge && !seenEdgeKeys.has(omittedOutermostEdge.edgeKey)) {
|
|
85768
85923
|
omittedEdgeKeys.add(omittedOutermostEdge.edgeKey);
|
|
@@ -85865,7 +86020,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85865
86020
|
eq80(siteCrawlEdges.followable, true),
|
|
85866
86021
|
eq80(siteCrawlEdges.relation, "anchor"),
|
|
85867
86022
|
isNotNull8(siteCrawlEdges.targetNodeKey),
|
|
85868
|
-
|
|
86023
|
+
inArray32(siteCrawlEdges.sourceNodeKey, frontier)
|
|
85869
86024
|
)).orderBy(asc14(siteCrawlEdges.edgeKey)).limit(SITE_HEALTH_PATH_MAX_VISITED_NODES + 1).all();
|
|
85870
86025
|
if (candidates.length > SITE_HEALTH_PATH_MAX_VISITED_NODES) truncated = true;
|
|
85871
86026
|
const candidateTargetKeys = [...new Set(candidates.map((edge) => edge.targetNodeKey).filter((nodeKey) => nodeKey != null))];
|
|
@@ -85873,7 +86028,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85873
86028
|
eq80(siteCrawlPages.projectId, scope.projectId),
|
|
85874
86029
|
eq80(siteCrawlPages.runId, scope.runId),
|
|
85875
86030
|
eq80(siteCrawlPages.attemptId, scope.attemptId),
|
|
85876
|
-
|
|
86031
|
+
inArray32(siteCrawlPages.nodeKey, candidateTargetKeys)
|
|
85877
86032
|
)).all().map((row) => row.nodeKey));
|
|
85878
86033
|
const next = /* @__PURE__ */ new Set();
|
|
85879
86034
|
for (const edge of candidates.slice(0, SITE_HEALTH_PATH_MAX_VISITED_NODES)) {
|
|
@@ -85919,7 +86074,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85919
86074
|
eq80(siteCrawlPages.projectId, scope.projectId),
|
|
85920
86075
|
eq80(siteCrawlPages.runId, scope.runId),
|
|
85921
86076
|
eq80(siteCrawlPages.attemptId, scope.attemptId),
|
|
85922
|
-
|
|
86077
|
+
inArray32(siteCrawlPages.nodeKey, pathKeys)
|
|
85923
86078
|
)).all();
|
|
85924
86079
|
const pageByKey = new Map(pathRows.map((row) => [row.nodeKey, row]));
|
|
85925
86080
|
const pathDetection = templateDetectionOf(snapshot.templateDetection);
|
|
@@ -85955,7 +86110,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85955
86110
|
eq80(siteCrawlSnapshots.complete, true),
|
|
85956
86111
|
notProbeRun()
|
|
85957
86112
|
];
|
|
85958
|
-
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(
|
|
86113
|
+
const afterTarget = request.query.toRunId ? resolveCrawl(project.id, request.query.toRunId) : app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq80(siteCrawlSnapshots.runId, runs.id)).where(and67(...completeSnapshotFilters)).orderBy(desc36(siteCrawlSnapshots.createdAt), desc36(siteCrawlSnapshots.runId)).limit(1).get();
|
|
85959
86114
|
if (request.query.toRunId && !afterTarget) throw notFound("Site crawl run", request.query.toRunId);
|
|
85960
86115
|
const beforeTarget = request.query.fromRunId ? resolveCrawl(project.id, request.query.fromRunId) : afterTarget ? app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq80(siteCrawlSnapshots.runId, runs.id)).where(and67(
|
|
85961
86116
|
...completeSnapshotFilters,
|
|
@@ -85966,7 +86121,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
85966
86121
|
lt13(siteCrawlSnapshots.runId, afterTarget.snapshot.runId)
|
|
85967
86122
|
)
|
|
85968
86123
|
)
|
|
85969
|
-
)).orderBy(
|
|
86124
|
+
)).orderBy(desc36(siteCrawlSnapshots.createdAt), desc36(siteCrawlSnapshots.runId)).limit(1).get() : void 0;
|
|
85970
86125
|
if (request.query.fromRunId && !beforeTarget) throw notFound("Site crawl run", request.query.fromRunId);
|
|
85971
86126
|
if (!afterTarget) {
|
|
85972
86127
|
const latestCrawl = resolveCrawl(project.id);
|
|
@@ -86211,14 +86366,14 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
86211
86366
|
eq80(siteCrawlPages.projectId, scope.projectId),
|
|
86212
86367
|
eq80(siteCrawlPages.runId, scope.runId),
|
|
86213
86368
|
eq80(siteCrawlPages.attemptId, scope.attemptId),
|
|
86214
|
-
|
|
86369
|
+
inArray32(siteCrawlPages.nodeKey, pageKeys)
|
|
86215
86370
|
)).all();
|
|
86216
86371
|
const edgeRowsFor = (scope) => linkKeys.length === 0 ? [] : app.db.select().from(siteCrawlEdges).where(and67(
|
|
86217
86372
|
eq80(siteCrawlEdges.projectId, scope.projectId),
|
|
86218
86373
|
eq80(siteCrawlEdges.runId, scope.runId),
|
|
86219
86374
|
eq80(siteCrawlEdges.attemptId, scope.attemptId),
|
|
86220
86375
|
eq80(siteCrawlEdges.internal, true),
|
|
86221
|
-
|
|
86376
|
+
inArray32(siteCrawlEdges.edgeKey, linkKeys)
|
|
86222
86377
|
)).all();
|
|
86223
86378
|
const beforePages = new Map(pageRowsFor(beforeScope).map((row) => [row.nodeKey, mapCrawlPage(row)]));
|
|
86224
86379
|
const afterPages = new Map(pageRowsFor(afterScope).map((row) => [row.nodeKey, mapCrawlPage(row)]));
|
|
@@ -86356,7 +86511,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
86356
86511
|
const healthState = parseSiteHealthState(request.query.healthState);
|
|
86357
86512
|
const limit = parseBoundedLimit(request.query.limit, 100, 200);
|
|
86358
86513
|
const offset = decodeCursor(request.query.cursor);
|
|
86359
|
-
const orderBy = request.query.sort === "score-desc" ? [
|
|
86514
|
+
const orderBy = request.query.sort === "score-desc" ? [desc36(siteCrawlPages.auditScore), asc14(siteCrawlPages.nodeKey)] : request.query.sort === "score-asc" ? [asc14(siteCrawlPages.auditScore), asc14(siteCrawlPages.nodeKey)] : request.query.sort === "path" ? [asc14(siteCrawlPages.path), asc14(siteCrawlPages.nodeKey)] : [asc14(siteCrawlPages.url), asc14(siteCrawlPages.nodeKey)];
|
|
86360
86515
|
let healthStateFilter = null;
|
|
86361
86516
|
if (healthState) {
|
|
86362
86517
|
const legacyRow = app.db.select({ id: siteCrawlPages.id }).from(siteCrawlPages).where(and67(
|
|
@@ -86669,15 +86824,15 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
86669
86824
|
eq80(runs.projectId, project.id),
|
|
86670
86825
|
eq80(runs.kind, RunKinds["site-audit"]),
|
|
86671
86826
|
notProbeRun()
|
|
86672
|
-
)).orderBy(
|
|
86827
|
+
)).orderBy(desc36(runs.createdAt), desc36(runs.id)).limit(limit).all();
|
|
86673
86828
|
const runIds = rows.map((row) => row.runId);
|
|
86674
86829
|
const crawlRunIds = new Set(runIds.length === 0 ? [] : app.db.select({ runId: siteCrawlSnapshots.runId }).from(siteCrawlSnapshots).innerJoin(runs, eq80(siteCrawlSnapshots.runId, runs.id)).where(and67(
|
|
86675
86830
|
eq80(siteCrawlSnapshots.projectId, project.id),
|
|
86676
86831
|
eq80(runs.projectId, project.id),
|
|
86677
86832
|
eq80(runs.kind, RunKinds["site-audit"]),
|
|
86678
|
-
|
|
86833
|
+
inArray32(runs.status, SURFACEABLE_STATUSES),
|
|
86679
86834
|
notProbeRun(),
|
|
86680
|
-
|
|
86835
|
+
inArray32(siteCrawlSnapshots.runId, runIds)
|
|
86681
86836
|
)).all().map((row) => row.runId));
|
|
86682
86837
|
return {
|
|
86683
86838
|
project: project.name,
|
|
@@ -86700,7 +86855,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
86700
86855
|
const attempt = app.db.select().from(siteCrawlAttempts).where(and67(
|
|
86701
86856
|
eq80(siteCrawlAttempts.projectId, project.id),
|
|
86702
86857
|
eq80(siteCrawlAttempts.runId, run.id)
|
|
86703
|
-
)).orderBy(
|
|
86858
|
+
)).orderBy(desc36(siteCrawlAttempts.attemptNumber), desc36(siteCrawlAttempts.updatedAt)).limit(1).get();
|
|
86704
86859
|
const persistedLayout = attempt ? app.db.select().from(siteCrawlGraphLayouts).where(and67(
|
|
86705
86860
|
eq80(siteCrawlGraphLayouts.projectId, project.id),
|
|
86706
86861
|
eq80(siteCrawlGraphLayouts.runId, run.id),
|
|
@@ -86747,7 +86902,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
86747
86902
|
const attempt = tx.select().from(siteCrawlAttempts).where(and67(
|
|
86748
86903
|
eq80(siteCrawlAttempts.projectId, project.id),
|
|
86749
86904
|
eq80(siteCrawlAttempts.runId, run.id)
|
|
86750
|
-
)).orderBy(
|
|
86905
|
+
)).orderBy(desc36(siteCrawlAttempts.attemptNumber), desc36(siteCrawlAttempts.updatedAt)).limit(1).get();
|
|
86751
86906
|
const state = run.status === RunStatuses.queued ? "waiting" : run.status === RunStatuses.running ? "collecting" : "terminal";
|
|
86752
86907
|
const base = {
|
|
86753
86908
|
project: project.name,
|
|
@@ -86817,7 +86972,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
86817
86972
|
)).where(and67(
|
|
86818
86973
|
eq80(runs.projectId, project.id),
|
|
86819
86974
|
eq80(runs.kind, RunKinds["site-audit"]),
|
|
86820
|
-
|
|
86975
|
+
inArray32(runs.status, [RunStatuses.queued, RunStatuses.running])
|
|
86821
86976
|
)).get();
|
|
86822
86977
|
if (existing) {
|
|
86823
86978
|
if (existing.identityKey === identityKey) {
|
|
@@ -86871,7 +87026,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
86871
87026
|
// ../api-routes/src/research.ts
|
|
86872
87027
|
import crypto50 from "crypto";
|
|
86873
87028
|
import { z as z5 } from "zod";
|
|
86874
|
-
import { and as and68, count as count3, desc as
|
|
87029
|
+
import { and as and68, count as count3, desc as desc37, eq as eq81, gte as gte21, lt as lt14, or as or19, sql as sql30 } from "drizzle-orm";
|
|
86875
87030
|
var sameLocation = (a, b) => a.label === b.label && a.city === b.city && a.region === b.region && a.country === b.country && a.timezone === b.timezone;
|
|
86876
87031
|
var BATCH_RECEIPT_PREFIX = "__canonry_research_batch__:";
|
|
86877
87032
|
async function researchRoutes(app, opts) {
|
|
@@ -87042,7 +87197,7 @@ async function researchRoutes(app, opts) {
|
|
|
87042
87197
|
const rows = app.db.select().from(researchRuns).where(and68(
|
|
87043
87198
|
eq81(researchRuns.projectId, project.id),
|
|
87044
87199
|
cursor ? or19(lt14(researchRuns.createdAt, cursor.createdAt), and68(eq81(researchRuns.createdAt, cursor.createdAt), lt14(researchRuns.id, cursor.id))) : void 0
|
|
87045
|
-
)).orderBy(
|
|
87200
|
+
)).orderBy(desc37(researchRuns.createdAt), desc37(researchRuns.id)).limit(limit + 1).all();
|
|
87046
87201
|
const runs2 = rows.slice(0, limit).map(serializeRun);
|
|
87047
87202
|
const last = runs2.at(-1);
|
|
87048
87203
|
const nextCursor = rows.length > limit && last ? Buffer.from(JSON.stringify({ projectId: project.id, createdAt: last.createdAt, id: last.id })).toString("base64url") : null;
|
|
@@ -87223,7 +87378,7 @@ function utcDayBounds(now) {
|
|
|
87223
87378
|
}
|
|
87224
87379
|
|
|
87225
87380
|
// ../api-routes/src/snapshot-competitor-refresh.ts
|
|
87226
|
-
import { and as and69, eq as eq82, inArray as
|
|
87381
|
+
import { and as and69, eq as eq82, inArray as inArray33 } from "drizzle-orm";
|
|
87227
87382
|
var SNAPSHOT_BATCH_SIZE = 500;
|
|
87228
87383
|
function backfillProjectAnswerMentions(db, projectId, opts) {
|
|
87229
87384
|
const isDryRun = opts?.dryRun === true;
|
|
@@ -87267,7 +87422,7 @@ function backfillProjectAnswerMentions(db, projectId, opts) {
|
|
|
87267
87422
|
competitorOverlap: querySnapshots.competitorOverlap,
|
|
87268
87423
|
recommendedCompetitors: querySnapshots.recommendedCompetitors,
|
|
87269
87424
|
rawResponse: querySnapshots.rawResponse
|
|
87270
|
-
}).from(querySnapshots).where(
|
|
87425
|
+
}).from(querySnapshots).where(inArray33(querySnapshots.runId, batchRunIds)).all();
|
|
87271
87426
|
const pendingUpdates = [];
|
|
87272
87427
|
for (const snapshot of snapshotRows) {
|
|
87273
87428
|
if (competitorFieldsOnly && snapshot.answerText == null) continue;
|
|
@@ -88323,7 +88478,7 @@ var IntelligenceService = class {
|
|
|
88323
88478
|
this.db.select({ one: sql31`1` }).from(querySnapshots).where(eq84(querySnapshots.runId, runs.id))
|
|
88324
88479
|
)
|
|
88325
88480
|
)
|
|
88326
|
-
).orderBy(
|
|
88481
|
+
).orderBy(desc38(runs.finishedAt), desc38(runs.createdAt)).limit(HISTORY_WINDOW_RUNS).all();
|
|
88327
88482
|
const trackedCompetitors = this.loadTrackedCompetitors(projectId);
|
|
88328
88483
|
const currentRun = this.buildRunData(
|
|
88329
88484
|
runId,
|
|
@@ -88442,10 +88597,10 @@ var IntelligenceService = class {
|
|
|
88442
88597
|
buildGbpLocationSignals(projectId, locationName, displayName, fallbackDate) {
|
|
88443
88598
|
const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(and71(eq84(gbpDailyMetrics.projectId, projectId), eq84(gbpDailyMetrics.locationName, locationName))).all();
|
|
88444
88599
|
const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(and71(eq84(gbpPlaceActions.projectId, projectId), eq84(gbpPlaceActions.locationName, locationName))).all();
|
|
88445
|
-
const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and71(eq84(gbpLodgingSnapshots.projectId, projectId), eq84(gbpLodgingSnapshots.locationName, locationName))).orderBy(
|
|
88600
|
+
const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and71(eq84(gbpLodgingSnapshots.projectId, projectId), eq84(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc38(gbpLodgingSnapshots.syncedAt)).limit(1).get();
|
|
88446
88601
|
const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(and71(eq84(gbpLocations.projectId, projectId), eq84(gbpLocations.locationName, locationName))).get();
|
|
88447
88602
|
const descriptionMissing = !(ownerRow?.description ?? "").trim();
|
|
88448
|
-
const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and71(eq84(gbpPlaceDetails.projectId, projectId), eq84(gbpPlaceDetails.locationName, locationName))).orderBy(
|
|
88603
|
+
const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and71(eq84(gbpPlaceDetails.projectId, projectId), eq84(gbpPlaceDetails.locationName, locationName))).orderBy(desc38(gbpPlaceDetails.syncedAt)).limit(1).get();
|
|
88449
88604
|
const placesAmenities = placeRow ? extractPlaceAmenities(placeRow.attributes) : [];
|
|
88450
88605
|
const summary3 = buildGbpSummary({
|
|
88451
88606
|
locationName,
|
|
@@ -88652,7 +88807,7 @@ var IntelligenceService = class {
|
|
|
88652
88807
|
let wouldDeleteTotal = 0;
|
|
88653
88808
|
const existingByRunId = /* @__PURE__ */ new Map();
|
|
88654
88809
|
if (isDryRun && targetRuns.length > 0) {
|
|
88655
|
-
const rows = this.db.select({ runId: insights.runId }).from(insights).where(
|
|
88810
|
+
const rows = this.db.select({ runId: insights.runId }).from(insights).where(inArray34(insights.runId, targetRuns.map((r) => r.id))).all();
|
|
88656
88811
|
for (const r of rows) {
|
|
88657
88812
|
if (r.runId == null) continue;
|
|
88658
88813
|
existingByRunId.set(r.runId, (existingByRunId.get(r.runId) ?? 0) + 1);
|
|
@@ -88707,7 +88862,7 @@ var IntelligenceService = class {
|
|
|
88707
88862
|
*/
|
|
88708
88863
|
runIdsWithSnapshots(runIds) {
|
|
88709
88864
|
if (runIds.length === 0) return /* @__PURE__ */ new Set();
|
|
88710
|
-
const rows = this.db.select({ runId: querySnapshots.runId }).from(querySnapshots).where(
|
|
88865
|
+
const rows = this.db.select({ runId: querySnapshots.runId }).from(querySnapshots).where(inArray34(querySnapshots.runId, [...runIds])).groupBy(querySnapshots.runId).all();
|
|
88711
88866
|
return new Set(rows.map((r) => r.runId));
|
|
88712
88867
|
}
|
|
88713
88868
|
/**
|
|
@@ -88852,7 +89007,7 @@ var IntelligenceService = class {
|
|
|
88852
89007
|
// Defensive — see top of file.
|
|
88853
89008
|
ne15(runs.trigger, RunTriggers.probe)
|
|
88854
89009
|
)
|
|
88855
|
-
).orderBy(
|
|
89010
|
+
).orderBy(desc38(runs.createdAt), desc38(runs.id)).limit((RECURRENCE_LOOKBACK_RUNS + 1) * ROWS_PER_GROUP_BUDGET).all();
|
|
88856
89011
|
const recentGroups = groupRunsByCreatedAt(recentRunRows);
|
|
88857
89012
|
const recentRunIds = [];
|
|
88858
89013
|
const recentRunIdToCreatedAt = /* @__PURE__ */ new Map();
|
|
@@ -88868,7 +89023,7 @@ var IntelligenceService = class {
|
|
|
88868
89023
|
const haveHistory = recentRunIds.length > 0;
|
|
88869
89024
|
const priorRegressionsByPair = /* @__PURE__ */ new Map();
|
|
88870
89025
|
if (haveHistory) {
|
|
88871
|
-
const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and71(eq84(insights.type, "regression"),
|
|
89026
|
+
const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and71(eq84(insights.type, "regression"), inArray34(insights.runId, recentRunIds))).all();
|
|
88872
89027
|
const regressionGroups = /* @__PURE__ */ new Map();
|
|
88873
89028
|
for (const row of priorRows) {
|
|
88874
89029
|
if (!row.runId) continue;
|