@ainyc/canonry 4.188.4 → 4.189.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/assets/{AuditHistoryPanel-Cn1xsaFZ.js → AuditHistoryPanel-CZ7ygQfy.js} +1 -1
- package/assets/assets/{BacklinksPage-CfTxBHZn.js → BacklinksPage-CYEYxjE8.js} +1 -1
- package/assets/assets/{HistoryPage-BvgKqrbW.js → HistoryPage-CvAllKzD.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-CGbNTIdz.js → MeasurementPropertyPage-BED9ak5a.js} +1 -1
- package/assets/assets/ProjectPage-Cgl5v16o.js +9 -0
- package/assets/assets/{RunRow-DzneLSnv.js → RunRow-DUlFaUBp.js} +1 -1
- package/assets/assets/{RunsPage-BgByi_t3.js → RunsPage-BcbBe_aQ.js} +1 -1
- package/assets/assets/{SettingsPage-DBv-GyPu.js → SettingsPage-gCyOuoD_.js} +1 -1
- package/assets/assets/{SiteHealthSection-DaNslx5J.js → SiteHealthSection-DJfFmT3n.js} +3 -3
- package/assets/assets/{TrafficPage-B6mfVlPe.js → TrafficPage-2ATExz7V.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-BXwAVIDo.js → TrafficSourceDetailPage-0PBMk9UH.js} +1 -1
- package/assets/assets/{extract-error-message-DMJa2ku8.js → extract-error-message-D8N7K1pb.js} +1 -1
- package/assets/assets/index-Bhwxe6W_.js +86 -0
- package/assets/assets/{react-sigma_core.esm.min-DiTvmmQd.js → react-sigma_core.esm.min-CU1UA6VY.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-3HZELBZZ.js → chunk-CDI3YR57.js} +2587 -2569
- package/dist/{chunk-7NMMQ7QO.js → chunk-HG6NLN7H.js} +330 -30
- package/dist/{chunk-VJRQTKUB.js → chunk-J533DKYE.js} +2 -2
- package/dist/{chunk-AC3ZIRHR.js → chunk-QQLMRABM.js} +645 -502
- package/dist/{chunk-OXYM6VCJ.js → chunk-YDYB3H4O.js} +19 -1
- package/dist/cli.js +48 -22
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-GMG2S55U.js → intelligence-service-M5TYY4TH.js} +2 -2
- package/dist/mcp.js +3 -3
- package/package.json +11 -11
- package/assets/assets/ProjectPage-BQ4lzu49.js +0 -9
- package/assets/assets/index-BRnD7hdh.js +0 -86
|
@@ -206,6 +206,7 @@ import {
|
|
|
206
206
|
buildMeasurementRunManifestV1,
|
|
207
207
|
calendarDateRange,
|
|
208
208
|
calendarMonthBounds,
|
|
209
|
+
calendarRecurrenceSchema,
|
|
209
210
|
canonicalMeasurementExecutionIdentityJson,
|
|
210
211
|
canonicalMeasurementPlanJson,
|
|
211
212
|
canonicalMeasurementPlanV2,
|
|
@@ -671,10 +672,10 @@ import {
|
|
|
671
672
|
wordpressSchemaDeployResultDtoSchema,
|
|
672
673
|
wordpressSchemaStatusResultDtoSchema,
|
|
673
674
|
wordpressStatusDtoSchema
|
|
674
|
-
} from "./chunk-
|
|
675
|
+
} from "./chunk-CDI3YR57.js";
|
|
675
676
|
|
|
676
677
|
// src/intelligence-service.ts
|
|
677
|
-
import { eq as eq67, desc as desc29, asc as asc12, and as
|
|
678
|
+
import { eq as eq67, desc as desc29, asc as asc12, and as and57, ne as ne10, or as or14, inArray as inArray25, gte as gte18, lte as lte15, isNull as isNull12, sql as sql26, exists } from "drizzle-orm";
|
|
678
679
|
|
|
679
680
|
// ../db/src/client.ts
|
|
680
681
|
import { mkdirSync } from "fs";
|
|
@@ -1270,6 +1271,7 @@ var schedules = sqliteTable("schedules", {
|
|
|
1270
1271
|
// created before migration 53.
|
|
1271
1272
|
kind: text("kind").notNull().default("answer-visibility"),
|
|
1272
1273
|
cronExpr: text("cron_expr").notNull(),
|
|
1274
|
+
recurrence: text("recurrence", { mode: "json" }).$type(),
|
|
1273
1275
|
preset: text("preset"),
|
|
1274
1276
|
timezone: text("timezone").notNull().default("UTC"),
|
|
1275
1277
|
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
|
|
@@ -7152,6 +7154,13 @@ var MIGRATION_VERSIONS = [
|
|
|
7152
7154
|
statements: [
|
|
7153
7155
|
`ALTER TABLE research_runs ADD COLUMN initiated_by TEXT`
|
|
7154
7156
|
]
|
|
7157
|
+
},
|
|
7158
|
+
{
|
|
7159
|
+
version: 152,
|
|
7160
|
+
name: "schedule-calendar-recurrence",
|
|
7161
|
+
statements: [
|
|
7162
|
+
`ALTER TABLE schedules ADD COLUMN recurrence TEXT`
|
|
7163
|
+
]
|
|
7155
7164
|
}
|
|
7156
7165
|
];
|
|
7157
7166
|
function addRunsMeasurementPlanVersionForeignKey(tx) {
|
|
@@ -11544,7 +11553,7 @@ function registerOAuthAdminRoutes(app, opts) {
|
|
|
11544
11553
|
|
|
11545
11554
|
// ../api-routes/src/projects.ts
|
|
11546
11555
|
import crypto7 from "crypto";
|
|
11547
|
-
import { eq as eq5, sql as sql4 } from "drizzle-orm";
|
|
11556
|
+
import { and as and2, eq as eq5, sql as sql4 } from "drizzle-orm";
|
|
11548
11557
|
|
|
11549
11558
|
// ../api-routes/src/helpers.ts
|
|
11550
11559
|
import crypto6 from "crypto";
|
|
@@ -11627,18 +11636,22 @@ async function settingsRoutes(app, opts) {
|
|
|
11627
11636
|
requireAdminSession(request);
|
|
11628
11637
|
return {
|
|
11629
11638
|
providers: opts.providerSummary ?? [],
|
|
11630
|
-
providerCatalog: (opts.providerAdapters ?? []).map((adapter) =>
|
|
11631
|
-
name
|
|
11632
|
-
|
|
11633
|
-
|
|
11634
|
-
|
|
11635
|
-
|
|
11636
|
-
|
|
11637
|
-
|
|
11638
|
-
|
|
11639
|
-
|
|
11640
|
-
|
|
11641
|
-
|
|
11639
|
+
providerCatalog: await Promise.all((opts.providerAdapters ?? []).map(async (adapter) => {
|
|
11640
|
+
const configured = opts.providerSummary?.some((provider) => provider.name === adapter.name && provider.configured);
|
|
11641
|
+
const discovered = configured && opts.getProviderModels ? await opts.getProviderModels(adapter.name) : [];
|
|
11642
|
+
return {
|
|
11643
|
+
name: adapter.name,
|
|
11644
|
+
displayName: adapter.displayName,
|
|
11645
|
+
mode: adapter.mode,
|
|
11646
|
+
modelConfigurable: adapter.modelConfigurable,
|
|
11647
|
+
defaultModel: adapter.defaultModel,
|
|
11648
|
+
knownModels: discovered.length ? discovered : adapter.knownModels,
|
|
11649
|
+
modelValidationPattern: {
|
|
11650
|
+
source: adapter.modelValidationPattern.source,
|
|
11651
|
+
flags: adapter.modelValidationPattern.flags
|
|
11652
|
+
},
|
|
11653
|
+
modelValidationHint: adapter.modelValidationHint
|
|
11654
|
+
};
|
|
11642
11655
|
})),
|
|
11643
11656
|
google: opts.google ?? { configured: false },
|
|
11644
11657
|
bing: opts.bing ?? { configured: false }
|
|
@@ -12150,7 +12163,10 @@ async function projectRoutes(app, opts) {
|
|
|
12150
12163
|
const project = resolveProject(app.db, request.params.name);
|
|
12151
12164
|
const qs = app.db.select().from(queries).where(eq5(queries.projectId, project.id)).all();
|
|
12152
12165
|
const comps = app.db.select().from(competitors).where(eq5(competitors.projectId, project.id)).all();
|
|
12153
|
-
const schedule = app.db.select().from(schedules).where(
|
|
12166
|
+
const schedule = app.db.select().from(schedules).where(and2(
|
|
12167
|
+
eq5(schedules.projectId, project.id),
|
|
12168
|
+
eq5(schedules.kind, SchedulableRunKinds["answer-visibility"])
|
|
12169
|
+
)).get();
|
|
12154
12170
|
const notificationRows = app.db.select().from(notifications).where(eq5(notifications.projectId, project.id)).all();
|
|
12155
12171
|
const config = {
|
|
12156
12172
|
apiVersion: "canonry/v1",
|
|
@@ -12184,9 +12200,10 @@ async function projectRoutes(app, opts) {
|
|
|
12184
12200
|
}),
|
|
12185
12201
|
...schedule ? {
|
|
12186
12202
|
schedule: {
|
|
12187
|
-
...schedule.preset ? { preset: schedule.preset } : { cron: schedule.cronExpr },
|
|
12203
|
+
...schedule.recurrence ? { recurrence: schedule.recurrence } : schedule.preset ? { preset: schedule.preset } : { cron: schedule.cronExpr },
|
|
12188
12204
|
timezone: schedule.timezone,
|
|
12189
|
-
providers: schedule.providers
|
|
12205
|
+
providers: schedule.providers,
|
|
12206
|
+
enabled: schedule.enabled
|
|
12190
12207
|
}
|
|
12191
12208
|
} : {}
|
|
12192
12209
|
}
|
|
@@ -12239,15 +12256,15 @@ function aliasArraysEqual(a, b) {
|
|
|
12239
12256
|
|
|
12240
12257
|
// ../api-routes/src/queries.ts
|
|
12241
12258
|
import crypto10 from "crypto";
|
|
12242
|
-
import { and as
|
|
12259
|
+
import { and as and5, eq as eq8, inArray as inArray2, sql as sql5 } from "drizzle-orm";
|
|
12243
12260
|
|
|
12244
12261
|
// ../api-routes/src/query-replace.ts
|
|
12245
12262
|
import crypto9 from "crypto";
|
|
12246
|
-
import { and as
|
|
12263
|
+
import { and as and4, eq as eq7, inArray, isNull as isNull2 } from "drizzle-orm";
|
|
12247
12264
|
|
|
12248
12265
|
// ../api-routes/src/measurement-draft-repo.ts
|
|
12249
12266
|
import crypto8 from "crypto";
|
|
12250
|
-
import { and as
|
|
12267
|
+
import { and as and3, eq as eq6, gt, lte as lte2 } from "drizzle-orm";
|
|
12251
12268
|
var MEASUREMENT_RECEIPT_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
12252
12269
|
function compareText(left, right) {
|
|
12253
12270
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
@@ -12333,7 +12350,7 @@ function draftCounts(authoring) {
|
|
|
12333
12350
|
function activePlanVersionRow(db, projectId) {
|
|
12334
12351
|
const pointer = db.select().from(measurementPlans).where(eq6(measurementPlans.projectId, projectId)).get();
|
|
12335
12352
|
if (!pointer) return null;
|
|
12336
|
-
const version = db.select().from(measurementPlanVersions).where(
|
|
12353
|
+
const version = db.select().from(measurementPlanVersions).where(and3(
|
|
12337
12354
|
eq6(measurementPlanVersions.projectId, projectId),
|
|
12338
12355
|
eq6(measurementPlanVersions.id, pointer.activeVersionId)
|
|
12339
12356
|
)).get();
|
|
@@ -12362,7 +12379,7 @@ function requireIdempotencyKey(request, operation) {
|
|
|
12362
12379
|
return value;
|
|
12363
12380
|
}
|
|
12364
12381
|
function replayReceipt(db, projectId, lookup, reply) {
|
|
12365
|
-
const existing = db.select().from(measurementOperationReceipts).where(
|
|
12382
|
+
const existing = db.select().from(measurementOperationReceipts).where(and3(
|
|
12366
12383
|
eq6(measurementOperationReceipts.projectId, projectId),
|
|
12367
12384
|
eq6(measurementOperationReceipts.operation, lookup.operation),
|
|
12368
12385
|
eq6(measurementOperationReceipts.idempotencyKey, lookup.key),
|
|
@@ -12392,9 +12409,9 @@ function sweepExpiredMeasurementReceipts(db, now) {
|
|
|
12392
12409
|
|
|
12393
12410
|
// ../api-routes/src/query-replace.ts
|
|
12394
12411
|
function preserveSnapshotQueryText(tx, projectId, queryIds) {
|
|
12395
|
-
const candidates = queryIds && queryIds.length > 0 ? tx.select({ id: queries.id, text: queries.query }).from(queries).where(
|
|
12412
|
+
const candidates = queryIds && queryIds.length > 0 ? tx.select({ id: queries.id, text: queries.query }).from(queries).where(and4(eq7(queries.projectId, projectId), inArray(queries.id, queryIds))).all() : tx.select({ id: queries.id, text: queries.query }).from(queries).where(eq7(queries.projectId, projectId)).all();
|
|
12396
12413
|
for (const q of candidates) {
|
|
12397
|
-
tx.update(querySnapshots).set({ queryText: q.text }).where(
|
|
12414
|
+
tx.update(querySnapshots).set({ queryText: q.text }).where(and4(eq7(querySnapshots.queryId, q.id), isNull2(querySnapshots.queryText))).run();
|
|
12398
12415
|
}
|
|
12399
12416
|
}
|
|
12400
12417
|
function changedQueryIdsForReplace(diff) {
|
|
@@ -12411,7 +12428,7 @@ function assertQueryCatalogMutationAllowed(tx, scope, affectedQueryIds, addsQuer
|
|
|
12411
12428
|
const protectedIds = /* @__PURE__ */ new Set();
|
|
12412
12429
|
const activePlan = tx.select({ activeVersionId: measurementPlans.activeVersionId }).from(measurementPlans).where(eq7(measurementPlans.projectId, scope.projectId)).get();
|
|
12413
12430
|
if (activePlan) {
|
|
12414
|
-
const version = tx.select({ canonicalJson: measurementPlanVersions.canonicalJson }).from(measurementPlanVersions).where(
|
|
12431
|
+
const version = tx.select({ canonicalJson: measurementPlanVersions.canonicalJson }).from(measurementPlanVersions).where(and4(
|
|
12415
12432
|
eq7(measurementPlanVersions.projectId, scope.projectId),
|
|
12416
12433
|
eq7(measurementPlanVersions.id, activePlan.activeVersionId)
|
|
12417
12434
|
)).get();
|
|
@@ -12452,7 +12469,7 @@ function assertQueryCatalogMutationAllowed(tx, scope, affectedQueryIds, addsQuer
|
|
|
12452
12469
|
assertNoActivePlanlessSweep(tx, scope);
|
|
12453
12470
|
}
|
|
12454
12471
|
function assertNoActivePlanlessSweep(tx, scope) {
|
|
12455
|
-
const activeRun = tx.select({ id: runs.id }).from(runs).where(
|
|
12472
|
+
const activeRun = tx.select({ id: runs.id }).from(runs).where(and4(
|
|
12456
12473
|
eq7(runs.projectId, scope.projectId),
|
|
12457
12474
|
eq7(runs.kind, RunKinds["answer-visibility"]),
|
|
12458
12475
|
inArray(runs.status, [RunStatuses.queued, RunStatuses.running]),
|
|
@@ -12650,7 +12667,7 @@ async function queryRoutes(app, opts) {
|
|
|
12650
12667
|
app.delete("/projects/:name/queries/:id", async (request, reply) => {
|
|
12651
12668
|
const project = resolveProject(app.db, request.params.name);
|
|
12652
12669
|
app.db.transaction((tx) => {
|
|
12653
|
-
const query = tx.select().from(queries).where(
|
|
12670
|
+
const query = tx.select().from(queries).where(and5(eq8(queries.projectId, project.id), eq8(queries.id, request.params.id))).get();
|
|
12654
12671
|
if (!query) throw notFound("Query", request.params.id);
|
|
12655
12672
|
assertQueryCatalogMutationAllowed(
|
|
12656
12673
|
tx,
|
|
@@ -12882,7 +12899,7 @@ async function queryRoutes(app, opts) {
|
|
|
12882
12899
|
|
|
12883
12900
|
// ../api-routes/src/competitors.ts
|
|
12884
12901
|
import crypto11 from "crypto";
|
|
12885
|
-
import { and as
|
|
12902
|
+
import { and as and6, eq as eq9 } from "drizzle-orm";
|
|
12886
12903
|
function normalizeCompetitor(domain) {
|
|
12887
12904
|
const reg = registrableDomain(domain);
|
|
12888
12905
|
if (reg) return reg;
|
|
@@ -12996,7 +13013,7 @@ async function competitorRoutes(app) {
|
|
|
12996
13013
|
});
|
|
12997
13014
|
app.delete("/projects/:name/competitors/:id", async (request, reply) => {
|
|
12998
13015
|
const project = resolveProject(app.db, request.params.name);
|
|
12999
|
-
const competitor = app.db.select().from(competitors).where(
|
|
13016
|
+
const competitor = app.db.select().from(competitors).where(and6(eq9(competitors.projectId, project.id), eq9(competitors.id, request.params.id))).get();
|
|
13000
13017
|
if (!competitor) {
|
|
13001
13018
|
throw notFound("Competitor", request.params.id);
|
|
13002
13019
|
}
|
|
@@ -13026,7 +13043,7 @@ function parseCompetitorBatch(value) {
|
|
|
13026
13043
|
}
|
|
13027
13044
|
|
|
13028
13045
|
// ../api-routes/src/competitor-landscape.ts
|
|
13029
|
-
import { and as
|
|
13046
|
+
import { and as and9, eq as eq14, gte as gte2, inArray as inArray4 } from "drizzle-orm";
|
|
13030
13047
|
|
|
13031
13048
|
// ../api-routes/src/mention-share-inputs.ts
|
|
13032
13049
|
import { eq as eq10 } from "drizzle-orm";
|
|
@@ -13127,7 +13144,7 @@ function shareOfVoiceFromLandscape(landscape, queryClass) {
|
|
|
13127
13144
|
|
|
13128
13145
|
// ../api-routes/src/measurement-overview.ts
|
|
13129
13146
|
import { createHash } from "crypto";
|
|
13130
|
-
import { and as
|
|
13147
|
+
import { and as and8, eq as eq13 } from "drizzle-orm";
|
|
13131
13148
|
|
|
13132
13149
|
// ../api-routes/src/measurement-report.ts
|
|
13133
13150
|
var compareText2 = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
@@ -13836,7 +13853,7 @@ function buildMeasurementReport(input, options = {}) {
|
|
|
13836
13853
|
}
|
|
13837
13854
|
|
|
13838
13855
|
// ../api-routes/src/measurement-report-adapter.ts
|
|
13839
|
-
import { and as
|
|
13856
|
+
import { and as and7, desc, eq as eq11, gte, inArray as inArray3, isNull as isNull3, lt as lt2, lte as lte3, ne as ne2 } from "drizzle-orm";
|
|
13840
13857
|
function compareText3(left, right) {
|
|
13841
13858
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
13842
13859
|
}
|
|
@@ -14133,7 +14150,7 @@ function comparableMeasurementVersionIds(db, projectId, versionId) {
|
|
|
14133
14150
|
const seen2 = new Set(ids);
|
|
14134
14151
|
let cursor = versionId;
|
|
14135
14152
|
for (let step = 0; step < MEASUREMENT_COMPARABLE_VERSION_WALK_LIMIT; step++) {
|
|
14136
|
-
const row = db.select({ comparableToVersionId: measurementPlanVersions.comparableToVersionId }).from(measurementPlanVersions).where(
|
|
14153
|
+
const row = db.select({ comparableToVersionId: measurementPlanVersions.comparableToVersionId }).from(measurementPlanVersions).where(and7(
|
|
14137
14154
|
eq11(measurementPlanVersions.projectId, projectId),
|
|
14138
14155
|
eq11(measurementPlanVersions.id, cursor)
|
|
14139
14156
|
)).get();
|
|
@@ -14165,10 +14182,10 @@ function latestMeasurementRun(db, projectId, versionId, statuses, window = {}, o
|
|
|
14165
14182
|
];
|
|
14166
14183
|
if (window.from !== void 0) conditions.push(gte(runs.createdAt, window.from));
|
|
14167
14184
|
if (window.to !== void 0) conditions.push(lte3(runs.createdAt, window.to));
|
|
14168
|
-
return db.select().from(runs).where(
|
|
14185
|
+
return db.select().from(runs).where(and7(...conditions)).orderBy(desc(runs.createdAt), desc(runs.id)).get();
|
|
14169
14186
|
}
|
|
14170
14187
|
function pinnedMeasurementRun(db, projectId, versionId, runId, opts = {}) {
|
|
14171
|
-
return db.select().from(runs).where(
|
|
14188
|
+
return db.select().from(runs).where(and7(
|
|
14172
14189
|
eq11(runs.id, runId),
|
|
14173
14190
|
eq11(runs.projectId, projectId),
|
|
14174
14191
|
opts.exactVersion ? eq11(runs.measurementPlanVersionId, versionId) : inArray3(runs.measurementPlanVersionId, comparableMeasurementVersionIds(db, projectId, versionId)),
|
|
@@ -14207,7 +14224,7 @@ function storedMeasurementPlanV2Report(db, projectId, version, plan, runId) {
|
|
|
14207
14224
|
};
|
|
14208
14225
|
}
|
|
14209
14226
|
function buildStoredMeasurementReport(db, projectId, revision, runId) {
|
|
14210
|
-
const version = db.select().from(measurementPlanVersions).where(
|
|
14227
|
+
const version = db.select().from(measurementPlanVersions).where(and7(
|
|
14211
14228
|
eq11(measurementPlanVersions.projectId, projectId),
|
|
14212
14229
|
eq11(measurementPlanVersions.revision, revision)
|
|
14213
14230
|
)).get();
|
|
@@ -14217,7 +14234,7 @@ function buildStoredMeasurementReport(db, projectId, revision, runId) {
|
|
|
14217
14234
|
return storedMeasurementPlanV2Report(db, projectId, version, stored, runId);
|
|
14218
14235
|
}
|
|
14219
14236
|
const plan = stored;
|
|
14220
|
-
const run = runId ? pinnedMeasurementRun(db, projectId, version.id, runId, { exactVersion: true }) : db.select().from(runs).where(
|
|
14237
|
+
const run = runId ? pinnedMeasurementRun(db, projectId, version.id, runId, { exactVersion: true }) : db.select().from(runs).where(and7(
|
|
14221
14238
|
eq11(runs.projectId, projectId),
|
|
14222
14239
|
eq11(runs.measurementPlanVersionId, version.id),
|
|
14223
14240
|
eq11(runs.kind, RunKinds["answer-visibility"]),
|
|
@@ -14231,7 +14248,7 @@ function buildStoredMeasurementReport(db, projectId, revision, runId) {
|
|
|
14231
14248
|
if (selectedRun.measurementManifest === null) manifestFailure(`missing for run ${selectedRun.id}`);
|
|
14232
14249
|
manifest = parseManifest(selectedRun.measurementManifest, frozenExecutionNodes(plan));
|
|
14233
14250
|
} else if (runId === void 0) {
|
|
14234
|
-
selectedRun = db.select().from(runs).where(
|
|
14251
|
+
selectedRun = db.select().from(runs).where(and7(
|
|
14235
14252
|
eq11(runs.projectId, projectId),
|
|
14236
14253
|
isNull3(runs.measurementPlanVersionId),
|
|
14237
14254
|
eq11(runs.kind, RunKinds["answer-visibility"]),
|
|
@@ -14357,7 +14374,7 @@ function parseOverviewQuery(raw) {
|
|
|
14357
14374
|
function activeMeasurementPlan(db, projectId) {
|
|
14358
14375
|
const pointer = db.select().from(measurementPlans).where(eq13(measurementPlans.projectId, projectId)).get();
|
|
14359
14376
|
if (!pointer) return null;
|
|
14360
|
-
const version = db.select().from(measurementPlanVersions).where(
|
|
14377
|
+
const version = db.select().from(measurementPlanVersions).where(and8(
|
|
14361
14378
|
eq13(measurementPlanVersions.projectId, projectId),
|
|
14362
14379
|
eq13(measurementPlanVersions.id, pointer.activeVersionId)
|
|
14363
14380
|
)).get();
|
|
@@ -14626,7 +14643,7 @@ function selectDisplayedRun(db, projectId, active, query) {
|
|
|
14626
14643
|
to: windowBound(query.to, true)
|
|
14627
14644
|
});
|
|
14628
14645
|
}
|
|
14629
|
-
const run = db.select().from(runs).where(
|
|
14646
|
+
const run = db.select().from(runs).where(and8(eq13(runs.projectId, projectId), eq13(runs.id, selectedRunId))).get();
|
|
14630
14647
|
if (!run) throw notFound("Run", selectedRunId);
|
|
14631
14648
|
if (runVersionServesActiveVersion(db, projectId, active.version.id, run.measurementPlanVersionId)) return run;
|
|
14632
14649
|
const pinned = run.measurementPlanVersionId === null ? null : db.select({ revision: measurementPlanVersions.revision }).from(measurementPlanVersions).where(eq13(measurementPlanVersions.id, run.measurementPlanVersionId)).get()?.revision ?? null;
|
|
@@ -14951,7 +14968,7 @@ function readCompetitorLandscape(app, projectName, query, selection) {
|
|
|
14951
14968
|
if (selection?.autoAdvanced && activeMeasurementPlan(app.db, project.id)?.plan.schemaVersion === 2) filters.scope = "all-markets";
|
|
14952
14969
|
const window = parseWindow(filters.window);
|
|
14953
14970
|
const cutoff = windowCutoff(window);
|
|
14954
|
-
const candidateRuns = app.db.select().from(runs).where(
|
|
14971
|
+
const candidateRuns = app.db.select().from(runs).where(and9(
|
|
14955
14972
|
eq14(runs.projectId, project.id),
|
|
14956
14973
|
eq14(runs.kind, RunKinds["answer-visibility"]),
|
|
14957
14974
|
selection ? inArray4(runs.id, [...selection.runIds]) : void 0,
|
|
@@ -15139,7 +15156,7 @@ function resolveAdvancedScope(app, projectId, kind, groupKey, candidateRuns) {
|
|
|
15139
15156
|
throw validationError(`Unknown Advanced Measurement group "${groupKey ?? ""}".`);
|
|
15140
15157
|
}
|
|
15141
15158
|
const planVersionIds = [...new Set(candidateRuns.map((run) => run.measurementPlanVersionId).filter((id) => typeof id === "string" && id.length > 0))];
|
|
15142
|
-
const historicalVersions = planVersionIds.length === 0 ? [] : app.db.select().from(measurementPlanVersions).where(
|
|
15159
|
+
const historicalVersions = planVersionIds.length === 0 ? [] : app.db.select().from(measurementPlanVersions).where(and9(
|
|
15143
15160
|
eq14(measurementPlanVersions.projectId, projectId),
|
|
15144
15161
|
inArray4(measurementPlanVersions.id, planVersionIds)
|
|
15145
15162
|
)).all();
|
|
@@ -15279,16 +15296,16 @@ function mergePins(...collections) {
|
|
|
15279
15296
|
|
|
15280
15297
|
// ../api-routes/src/runs.ts
|
|
15281
15298
|
import crypto14 from "crypto";
|
|
15282
|
-
import { and as
|
|
15299
|
+
import { and as and12, eq as eq17, asc, desc as desc3, inArray as inArray5, or as or2, sql as sql6 } from "drizzle-orm";
|
|
15283
15300
|
import { gte as gte3 } from "drizzle-orm";
|
|
15284
15301
|
|
|
15285
15302
|
// ../api-routes/src/run-queue.ts
|
|
15286
15303
|
import crypto13 from "crypto";
|
|
15287
|
-
import { and as
|
|
15304
|
+
import { and as and11, eq as eq16, or } from "drizzle-orm";
|
|
15288
15305
|
|
|
15289
15306
|
// ../api-routes/src/query-basket.ts
|
|
15290
15307
|
import crypto12 from "crypto";
|
|
15291
|
-
import { and as
|
|
15308
|
+
import { and as and10, desc as desc2, eq as eq15 } from "drizzle-orm";
|
|
15292
15309
|
function queryBasketMembers(db, projectId) {
|
|
15293
15310
|
const rows = db.select({ query: queries.query }).from(queries).where(eq15(queries.projectId, projectId)).all();
|
|
15294
15311
|
return [...new Set(rows.map((row) => normalizeQueryText(row.query)))].sort();
|
|
@@ -15539,7 +15556,7 @@ function measurementStamp(tx, params) {
|
|
|
15539
15556
|
}
|
|
15540
15557
|
return null;
|
|
15541
15558
|
}
|
|
15542
|
-
const version = tx.select().from(measurementPlanVersions).where(
|
|
15559
|
+
const version = tx.select().from(measurementPlanVersions).where(and11(
|
|
15543
15560
|
eq16(measurementPlanVersions.projectId, params.projectId),
|
|
15544
15561
|
eq16(measurementPlanVersions.id, active.activeVersionId)
|
|
15545
15562
|
)).get();
|
|
@@ -15617,18 +15634,40 @@ function queueRunIfProjectIdle(db, params) {
|
|
|
15617
15634
|
const kind = params.kind ?? "answer-visibility";
|
|
15618
15635
|
const trigger = params.trigger ?? "manual";
|
|
15619
15636
|
const runId = crypto13.randomUUID();
|
|
15637
|
+
if (params.scheduleClaim && trigger !== RunTriggers.scheduled) {
|
|
15638
|
+
throw new Error("Schedule claims require a scheduled run trigger");
|
|
15639
|
+
}
|
|
15620
15640
|
return db.transaction((tx) => {
|
|
15621
|
-
const activeRun = tx.select().from(runs).where(
|
|
15622
|
-
|
|
15641
|
+
const activeRun = () => tx.select().from(runs).where(
|
|
15642
|
+
and11(
|
|
15623
15643
|
eq16(runs.projectId, params.projectId),
|
|
15624
15644
|
eq16(runs.kind, kind),
|
|
15625
15645
|
or(eq16(runs.status, "queued"), eq16(runs.status, "running"))
|
|
15626
15646
|
)
|
|
15627
15647
|
).get();
|
|
15628
|
-
if (
|
|
15629
|
-
|
|
15648
|
+
if (!params.scheduleClaim) {
|
|
15649
|
+
const current2 = activeRun();
|
|
15650
|
+
if (current2) return { conflict: true, activeRunId: current2.id };
|
|
15630
15651
|
}
|
|
15631
15652
|
const stamp = measurementStamp(tx, params);
|
|
15653
|
+
if (params.scheduleClaim) {
|
|
15654
|
+
const claim = tx.update(schedules).set({
|
|
15655
|
+
nextRunAt: params.scheduleClaim.nextRunAt,
|
|
15656
|
+
updatedAt: nextScheduleUpdatedAt(params.scheduleClaim.expectedUpdatedAt)
|
|
15657
|
+
}).where(and11(
|
|
15658
|
+
eq16(schedules.id, params.scheduleClaim.scheduleId),
|
|
15659
|
+
eq16(schedules.projectId, params.projectId),
|
|
15660
|
+
eq16(schedules.kind, kind),
|
|
15661
|
+
eq16(schedules.enabled, true),
|
|
15662
|
+
eq16(schedules.nextRunAt, params.scheduleClaim.dueAt),
|
|
15663
|
+
eq16(schedules.updatedAt, params.scheduleClaim.expectedUpdatedAt)
|
|
15664
|
+
)).run();
|
|
15665
|
+
if (claim.changes !== 1) {
|
|
15666
|
+
return { conflict: true, activeRunId: params.scheduleClaim.scheduleId, scheduleClaimed: false };
|
|
15667
|
+
}
|
|
15668
|
+
}
|
|
15669
|
+
const current = activeRun();
|
|
15670
|
+
if (current) return { conflict: true, activeRunId: current.id };
|
|
15632
15671
|
const scoped = params.queries != null || stamp?.scope != null;
|
|
15633
15672
|
const basket = scoped ? null : ensureCurrentQueryBasketRevision(tx, params.projectId, createdAt);
|
|
15634
15673
|
tx.insert(runs).values({
|
|
@@ -15746,7 +15785,7 @@ async function runRoutes(app, opts) {
|
|
|
15746
15785
|
throw validationError("No locations configured for this project");
|
|
15747
15786
|
}
|
|
15748
15787
|
const result = app.db.transaction((tx) => {
|
|
15749
|
-
const activeRun = tx.select({ id: runs.id }).from(runs).where(
|
|
15788
|
+
const activeRun = tx.select({ id: runs.id }).from(runs).where(and12(
|
|
15750
15789
|
eq17(runs.projectId, project.id),
|
|
15751
15790
|
eq17(runs.kind, kind),
|
|
15752
15791
|
or2(eq17(runs.status, "queued"), eq17(runs.status, "running"))
|
|
@@ -15824,15 +15863,15 @@ async function runRoutes(app, opts) {
|
|
|
15824
15863
|
const parsedLimit = parseInt(request.query.limit ?? "", 10);
|
|
15825
15864
|
const limit = Number.isNaN(parsedLimit) || parsedLimit <= 0 ? void 0 : parsedLimit;
|
|
15826
15865
|
const kind = parseListKind(request.query.kind);
|
|
15827
|
-
const where = kind ?
|
|
15866
|
+
const where = kind ? and12(eq17(runs.projectId, project.id), eq17(runs.kind, kind)) : eq17(runs.projectId, project.id);
|
|
15828
15867
|
const rows = limit == null ? app.db.select().from(runs).where(where).orderBy(asc(runs.createdAt)).all() : app.db.select().from(runs).where(where).orderBy(desc3(runs.createdAt)).limit(limit).all().reverse();
|
|
15829
15868
|
return reply.send(rows.map(formatRun));
|
|
15830
15869
|
});
|
|
15831
15870
|
app.get("/projects/:name/runs/latest", async (request, reply) => {
|
|
15832
15871
|
const project = resolveProject(app.db, request.params.name);
|
|
15833
|
-
const countRow = app.db.select({ count: sql6`count(*)` }).from(runs).where(
|
|
15872
|
+
const countRow = app.db.select({ count: sql6`count(*)` }).from(runs).where(and12(eq17(runs.projectId, project.id), notProbeRun())).get();
|
|
15834
15873
|
const totalRuns = countRow?.count ?? 0;
|
|
15835
|
-
const latestRun = app.db.select().from(runs).where(
|
|
15874
|
+
const latestRun = app.db.select().from(runs).where(and12(eq17(runs.projectId, project.id), notProbeRun())).orderBy(desc3(runs.createdAt), desc3(runs.id)).limit(1).get();
|
|
15836
15875
|
if (!latestRun) {
|
|
15837
15876
|
return reply.send({ totalRuns: 0, run: null });
|
|
15838
15877
|
}
|
|
@@ -15851,7 +15890,7 @@ async function runRoutes(app, opts) {
|
|
|
15851
15890
|
if (kind) filters.push(eq17(runs.kind, kind));
|
|
15852
15891
|
const scopedProjectId = request.apiKey?.projectId;
|
|
15853
15892
|
if (scopedProjectId) filters.push(eq17(runs.projectId, scopedProjectId));
|
|
15854
|
-
const rows = app.db.select().from(runs).where(
|
|
15893
|
+
const rows = app.db.select().from(runs).where(and12(...filters)).orderBy(desc3(runs.createdAt), desc3(runs.id)).limit(limit).all();
|
|
15855
15894
|
return reply.send(rows.map(formatRun));
|
|
15856
15895
|
});
|
|
15857
15896
|
app.post("/runs", async (request, reply) => {
|
|
@@ -15982,7 +16021,7 @@ async function runRoutes(app, opts) {
|
|
|
15982
16021
|
const terminalStatuses = /* @__PURE__ */ new Set(["completed", "partial", "failed", "cancelled"]);
|
|
15983
16022
|
if (terminalStatuses.has(run.status)) throw runNotCancellable(run.id, run.status);
|
|
15984
16023
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15985
|
-
const cancelled = app.db.update(runs).set({ status: "cancelled", finishedAt: now, error: serializeRunError({ message: "Cancelled by user" }) }).where(
|
|
16024
|
+
const cancelled = app.db.update(runs).set({ status: "cancelled", finishedAt: now, error: serializeRunError({ message: "Cancelled by user" }) }).where(and12(eq17(runs.id, run.id), inArray5(runs.status, ["queued", "running"]))).run();
|
|
15986
16025
|
if (cancelled.changes === 0) {
|
|
15987
16026
|
const current = app.db.select().from(runs).where(eq17(runs.id, run.id)).get();
|
|
15988
16027
|
if (!current) throw notFound("Run", run.id);
|
|
@@ -16183,7 +16222,7 @@ function loadRunDetail(app, run) {
|
|
|
16183
16222
|
|
|
16184
16223
|
// ../api-routes/src/measurement-plan.ts
|
|
16185
16224
|
import crypto15 from "crypto";
|
|
16186
|
-
import { and as
|
|
16225
|
+
import { and as and13, desc as desc4, eq as eq18 } from "drizzle-orm";
|
|
16187
16226
|
var MEASUREMENT_PLAN_WRITE_SCOPE = "measurement-plan.write";
|
|
16188
16227
|
function parseStoredPlanAnyVersion(canonicalJson3) {
|
|
16189
16228
|
return parseStoredMeasurementPlanAnyVersion(canonicalJson3);
|
|
@@ -16220,7 +16259,7 @@ function versionMetadata(row, activeVersionId) {
|
|
|
16220
16259
|
function activePlanVersion(app, projectId) {
|
|
16221
16260
|
const plan = app.db.select().from(measurementPlans).where(eq18(measurementPlans.projectId, projectId)).get();
|
|
16222
16261
|
if (!plan) return null;
|
|
16223
|
-
const version = app.db.select().from(measurementPlanVersions).where(
|
|
16262
|
+
const version = app.db.select().from(measurementPlanVersions).where(and13(
|
|
16224
16263
|
eq18(measurementPlanVersions.projectId, projectId),
|
|
16225
16264
|
eq18(measurementPlanVersions.id, plan.activeVersionId)
|
|
16226
16265
|
)).get();
|
|
@@ -16439,7 +16478,7 @@ async function measurementPlanRoutes(app, opts) {
|
|
|
16439
16478
|
const desired = desiredSegmentKinds(compiled);
|
|
16440
16479
|
const published = app.db.transaction((tx) => {
|
|
16441
16480
|
const activePlan = tx.select().from(measurementPlans).where(eq18(measurementPlans.projectId, project.id)).get();
|
|
16442
|
-
const activeVersion = activePlan ? tx.select().from(measurementPlanVersions).where(
|
|
16481
|
+
const activeVersion = activePlan ? tx.select().from(measurementPlanVersions).where(and13(
|
|
16443
16482
|
eq18(measurementPlanVersions.projectId, project.id),
|
|
16444
16483
|
eq18(measurementPlanVersions.id, activePlan.activeVersionId)
|
|
16445
16484
|
)).get() : null;
|
|
@@ -16508,7 +16547,7 @@ async function measurementPlanRoutes(app, opts) {
|
|
|
16508
16547
|
app.post("/projects/:name/measurement-plan/segments/:stableKey/retire", async (request, reply) => {
|
|
16509
16548
|
requireScope(request, MEASUREMENT_PLAN_WRITE_SCOPE);
|
|
16510
16549
|
const project = resolveProject(app.db, request.params.name);
|
|
16511
|
-
const segment = app.db.select().from(measurementSegments).where(
|
|
16550
|
+
const segment = app.db.select().from(measurementSegments).where(and13(
|
|
16512
16551
|
eq18(measurementSegments.projectId, project.id),
|
|
16513
16552
|
eq18(measurementSegments.stableKey, request.params.stableKey)
|
|
16514
16553
|
)).get();
|
|
@@ -16545,7 +16584,7 @@ async function measurementPlanRoutes(app, opts) {
|
|
|
16545
16584
|
throw notFound("Measurement plan revision", request.params.revision);
|
|
16546
16585
|
}
|
|
16547
16586
|
const revision = Number(request.params.revision);
|
|
16548
|
-
const row = app.db.select().from(measurementPlanVersions).where(
|
|
16587
|
+
const row = app.db.select().from(measurementPlanVersions).where(and13(
|
|
16549
16588
|
eq18(measurementPlanVersions.projectId, project.id),
|
|
16550
16589
|
eq18(measurementPlanVersions.revision, revision)
|
|
16551
16590
|
)).get();
|
|
@@ -17275,7 +17314,7 @@ async function measurementServiceRoutes(app, opts) {
|
|
|
17275
17314
|
|
|
17276
17315
|
// ../api-routes/src/measurement-draft.ts
|
|
17277
17316
|
import crypto18 from "crypto";
|
|
17278
|
-
import { and as
|
|
17317
|
+
import { and as and14, asc as asc2, desc as desc5, eq as eq19, inArray as inArray6 } from "drizzle-orm";
|
|
17279
17318
|
|
|
17280
17319
|
// ../api-routes/src/measurement-draft-compile.ts
|
|
17281
17320
|
var MEASUREMENT_DRAFT_MAX_TARGETS = 1e3;
|
|
@@ -19372,7 +19411,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
19372
19411
|
const active = activePlanVersionRow(app.db, project.id);
|
|
19373
19412
|
const draft = draftRow(app.db, project.id);
|
|
19374
19413
|
const activeSchemaVersion = active ? active.schemaVersion === 2 ? 2 : 1 : null;
|
|
19375
|
-
const completedRun = active ? app.db.select({ id: runs.id }).from(runs).where(
|
|
19414
|
+
const completedRun = active ? app.db.select({ id: runs.id }).from(runs).where(and14(
|
|
19376
19415
|
eq19(runs.projectId, project.id),
|
|
19377
19416
|
// The comparable chain, not the bare active id: a label-only
|
|
19378
19417
|
// republish must not flip setup back to awaiting_first_run while
|
|
@@ -19556,7 +19595,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
19556
19595
|
etagVersion,
|
|
19557
19596
|
updatedBy: serializeActor(gate.actor),
|
|
19558
19597
|
updatedAt: now.toISOString()
|
|
19559
|
-
}).where(
|
|
19598
|
+
}).where(and14(
|
|
19560
19599
|
eq19(measurementPlanDrafts.id, row.id),
|
|
19561
19600
|
eq19(measurementPlanDrafts.etagVersion, row.etagVersion)
|
|
19562
19601
|
)).run();
|
|
@@ -19603,7 +19642,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
19603
19642
|
etagVersion,
|
|
19604
19643
|
updatedBy: serializeActor(gate.actor),
|
|
19605
19644
|
updatedAt: now.toISOString()
|
|
19606
|
-
}).where(
|
|
19645
|
+
}).where(and14(
|
|
19607
19646
|
eq19(measurementPlanDrafts.id, row.id),
|
|
19608
19647
|
eq19(measurementPlanDrafts.etagVersion, row.etagVersion)
|
|
19609
19648
|
)).run();
|
|
@@ -19726,7 +19765,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
19726
19765
|
etagVersion,
|
|
19727
19766
|
updatedBy: serializeActor(gate.actor),
|
|
19728
19767
|
updatedAt: now.toISOString()
|
|
19729
|
-
}).where(
|
|
19768
|
+
}).where(and14(
|
|
19730
19769
|
eq19(measurementPlanDrafts.id, row.id),
|
|
19731
19770
|
eq19(measurementPlanDrafts.etagVersion, row.etagVersion)
|
|
19732
19771
|
)).run();
|
|
@@ -19965,7 +20004,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
19965
20004
|
});
|
|
19966
20005
|
});
|
|
19967
20006
|
function querySetDetail(projectId, setId) {
|
|
19968
|
-
const set = app.db.select().from(measurementQuerySets).where(
|
|
20007
|
+
const set = app.db.select().from(measurementQuerySets).where(and14(
|
|
19969
20008
|
eq19(measurementQuerySets.projectId, projectId),
|
|
19970
20009
|
eq19(measurementQuerySets.id, setId)
|
|
19971
20010
|
)).get();
|
|
@@ -20021,7 +20060,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
20021
20060
|
for (const queryId of parsed.data.queryIds) {
|
|
20022
20061
|
if (!known.has(queryId)) throw notFound("Query", queryId);
|
|
20023
20062
|
}
|
|
20024
|
-
const existing = app.db.select().from(measurementQuerySets).where(
|
|
20063
|
+
const existing = app.db.select().from(measurementQuerySets).where(and14(
|
|
20025
20064
|
eq19(measurementQuerySets.projectId, project.id),
|
|
20026
20065
|
eq19(measurementQuerySets.id, setId)
|
|
20027
20066
|
)).get();
|
|
@@ -20063,7 +20102,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
20063
20102
|
app.delete("/projects/:name/measurement-query-sets/:setId", async (request, reply) => {
|
|
20064
20103
|
requireScope(request, MEASUREMENT_PLAN_WRITE_SCOPE);
|
|
20065
20104
|
const project = resolveProject(app.db, request.params.name);
|
|
20066
|
-
const existing = app.db.select().from(measurementQuerySets).where(
|
|
20105
|
+
const existing = app.db.select().from(measurementQuerySets).where(and14(
|
|
20067
20106
|
eq19(measurementQuerySets.projectId, project.id),
|
|
20068
20107
|
eq19(measurementQuerySets.id, request.params.setId)
|
|
20069
20108
|
)).get();
|
|
@@ -20108,7 +20147,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
20108
20147
|
}
|
|
20109
20148
|
}
|
|
20110
20149
|
const templateId = request.params.templateId;
|
|
20111
|
-
const existing = app.db.select().from(measurementQueryTemplates).where(
|
|
20150
|
+
const existing = app.db.select().from(measurementQueryTemplates).where(and14(
|
|
20112
20151
|
eq19(measurementQueryTemplates.projectId, project.id),
|
|
20113
20152
|
eq19(measurementQueryTemplates.id, templateId)
|
|
20114
20153
|
)).get();
|
|
@@ -20148,7 +20187,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
20148
20187
|
app.delete("/projects/:name/measurement-query-templates/:templateId", async (request, reply) => {
|
|
20149
20188
|
requireScope(request, MEASUREMENT_PLAN_WRITE_SCOPE);
|
|
20150
20189
|
const project = resolveProject(app.db, request.params.name);
|
|
20151
|
-
const existing = app.db.select().from(measurementQueryTemplates).where(
|
|
20190
|
+
const existing = app.db.select().from(measurementQueryTemplates).where(and14(
|
|
20152
20191
|
eq19(measurementQueryTemplates.projectId, project.id),
|
|
20153
20192
|
eq19(measurementQueryTemplates.id, request.params.templateId)
|
|
20154
20193
|
)).get();
|
|
@@ -20170,7 +20209,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
20170
20209
|
if (gate.replay !== null) return gate.replay;
|
|
20171
20210
|
const parsed = measurementQueryTemplateApplyRequestSchema.safeParse(request.body);
|
|
20172
20211
|
if (!parsed.success) throw validationError("Invalid template apply payload", { issues: parsed.error.issues });
|
|
20173
|
-
const template = app.db.select().from(measurementQueryTemplates).where(
|
|
20212
|
+
const template = app.db.select().from(measurementQueryTemplates).where(and14(
|
|
20174
20213
|
eq19(measurementQueryTemplates.projectId, gate.project.id),
|
|
20175
20214
|
eq19(measurementQueryTemplates.id, request.params.templateId)
|
|
20176
20215
|
)).get();
|
|
@@ -20196,7 +20235,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
20196
20235
|
(found ? existing : created).push(entry);
|
|
20197
20236
|
return entry;
|
|
20198
20237
|
});
|
|
20199
|
-
const querySet = parsed.data.querySetId ? app.db.select().from(measurementQuerySets).where(
|
|
20238
|
+
const querySet = parsed.data.querySetId ? app.db.select().from(measurementQuerySets).where(and14(
|
|
20200
20239
|
eq19(measurementQuerySets.projectId, gate.project.id),
|
|
20201
20240
|
eq19(measurementQuerySets.id, parsed.data.querySetId)
|
|
20202
20241
|
)).get() : void 0;
|
|
@@ -20241,7 +20280,7 @@ async function measurementDraftRoutes(app, opts = {}) {
|
|
|
20241
20280
|
|
|
20242
20281
|
// ../api-routes/src/measurement-discovery-v2.ts
|
|
20243
20282
|
import crypto19 from "crypto";
|
|
20244
|
-
import { and as
|
|
20283
|
+
import { and as and15, eq as eq20 } from "drizzle-orm";
|
|
20245
20284
|
var MEASUREMENT_DISCOVERY_COMPILER_VERSION = "measurement-discovery/2.0";
|
|
20246
20285
|
var MEASUREMENT_REBIND_THRESHOLD = 0.7;
|
|
20247
20286
|
var DISCOVERY_URL_LIMIT = 1e4;
|
|
@@ -20384,7 +20423,7 @@ function requireIdempotencyKey2(request, operation) {
|
|
|
20384
20423
|
return supplied;
|
|
20385
20424
|
}
|
|
20386
20425
|
function replayedResponse(app, projectId, operation, idempotencyKey, requestChecksum2) {
|
|
20387
|
-
const receipt = app.db.select().from(measurementOperationReceipts).where(
|
|
20426
|
+
const receipt = app.db.select().from(measurementOperationReceipts).where(and15(
|
|
20388
20427
|
eq20(measurementOperationReceipts.projectId, projectId),
|
|
20389
20428
|
eq20(measurementOperationReceipts.operation, operation),
|
|
20390
20429
|
eq20(measurementOperationReceipts.idempotencyKey, idempotencyKey)
|
|
@@ -20426,7 +20465,7 @@ function commitDraft(app, input) {
|
|
|
20426
20465
|
}).where(eq20(measurementPlanDrafts.id, input.draft.row.id)).run();
|
|
20427
20466
|
}
|
|
20428
20467
|
if (input.discovery) {
|
|
20429
|
-
const existing = tx.select().from(measurementDiscoveryConfigs).where(
|
|
20468
|
+
const existing = tx.select().from(measurementDiscoveryConfigs).where(and15(
|
|
20430
20469
|
eq20(measurementDiscoveryConfigs.projectId, input.project.id),
|
|
20431
20470
|
eq20(measurementDiscoveryConfigs.inputChecksum, input.discovery.inputChecksum)
|
|
20432
20471
|
)).get();
|
|
@@ -20710,7 +20749,7 @@ async function measurementDiscoveryV2Routes(app) {
|
|
|
20710
20749
|
|
|
20711
20750
|
// ../api-routes/src/measurement-property-evidence.ts
|
|
20712
20751
|
import { createHash as createHash2 } from "crypto";
|
|
20713
|
-
import { and as
|
|
20752
|
+
import { and as and16, eq as eq21 } from "drizzle-orm";
|
|
20714
20753
|
function parseEvidenceQuery(raw) {
|
|
20715
20754
|
const candidate = { ...raw, ...raw.limit === void 0 ? {} : { limit: Number(raw.limit) } };
|
|
20716
20755
|
const parsed = measurementPropertyEvidenceQuerySchema.safeParse(candidate);
|
|
@@ -20782,7 +20821,7 @@ function selectDisplayedRun2(db, projectId, active, runId) {
|
|
|
20782
20821
|
if (runId === void 0) {
|
|
20783
20822
|
return latestMeasurementRun(db, projectId, active.version.id, [RunStatuses.completed]);
|
|
20784
20823
|
}
|
|
20785
|
-
const run = db.select().from(runs).where(
|
|
20824
|
+
const run = db.select().from(runs).where(and16(eq21(runs.projectId, projectId), eq21(runs.id, runId))).get();
|
|
20786
20825
|
if (!run) throw notFound("Run", runId);
|
|
20787
20826
|
if (runVersionServesActiveVersion(db, projectId, active.version.id, run.measurementPlanVersionId)) return run;
|
|
20788
20827
|
const pinned = run.measurementPlanVersionId === null ? null : db.select({ revision: measurementPlanVersions.revision }).from(measurementPlanVersions).where(eq21(measurementPlanVersions.id, run.measurementPlanVersionId)).get()?.revision ?? null;
|
|
@@ -20897,10 +20936,10 @@ async function measurementPropertyEvidenceRoutes(app) {
|
|
|
20897
20936
|
}
|
|
20898
20937
|
|
|
20899
20938
|
// ../api-routes/src/measurement-portfolio-reads.ts
|
|
20900
|
-
import { and as
|
|
20939
|
+
import { and as and18, desc as desc6, eq as eq23, inArray as inArray8, lt as lt3, or as or3 } from "drizzle-orm";
|
|
20901
20940
|
|
|
20902
20941
|
// ../api-routes/src/measurement-question-reads.ts
|
|
20903
|
-
import { and as
|
|
20942
|
+
import { and as and17, eq as eq22, getTableColumns, inArray as inArray7, sql as sql7 } from "drizzle-orm";
|
|
20904
20943
|
var DEFAULT_LIMIT2 = 50;
|
|
20905
20944
|
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
20906
20945
|
RunStatuses.completed,
|
|
@@ -20978,7 +21017,7 @@ function selectMeasurementQuestionRun(db, projectId, active, runId) {
|
|
|
20978
21017
|
if (runId === void 0) {
|
|
20979
21018
|
return latestMeasurementRun(db, projectId, active.version.id, [RunStatuses.completed]);
|
|
20980
21019
|
}
|
|
20981
|
-
const run = db.select().from(runs).where(
|
|
21020
|
+
const run = db.select().from(runs).where(and17(
|
|
20982
21021
|
eq22(runs.id, runId),
|
|
20983
21022
|
eq22(runs.projectId, projectId)
|
|
20984
21023
|
)).get();
|
|
@@ -21021,7 +21060,7 @@ function selectedQuestionSnapshots(db, runId, manifest, scope) {
|
|
|
21021
21060
|
if (scope?.provider !== void 0) {
|
|
21022
21061
|
conditions.push(sql7`lower(trim(${querySnapshots.provider})) = ${normalizeText(scope.provider)}`);
|
|
21023
21062
|
}
|
|
21024
|
-
return db.select(measurementQuestionSnapshotColumns).from(querySnapshots).where(
|
|
21063
|
+
return db.select(measurementQuestionSnapshotColumns).from(querySnapshots).where(and17(...conditions)).all();
|
|
21025
21064
|
}
|
|
21026
21065
|
function rawResponsesForLegacyQuestionSnapshots(db, runId, snapshots) {
|
|
21027
21066
|
const legacyIds = snapshots.filter((snapshot) => snapshot.citedUrls === null).map((snapshot) => snapshot.id);
|
|
@@ -21029,7 +21068,7 @@ function rawResponsesForLegacyQuestionSnapshots(db, runId, snapshots) {
|
|
|
21029
21068
|
return new Map(db.select({
|
|
21030
21069
|
id: querySnapshots.id,
|
|
21031
21070
|
rawResponse: querySnapshots.rawResponse
|
|
21032
|
-
}).from(querySnapshots).where(
|
|
21071
|
+
}).from(querySnapshots).where(and17(
|
|
21033
21072
|
eq22(querySnapshots.runId, runId),
|
|
21034
21073
|
inArray7(querySnapshots.id, legacyIds)
|
|
21035
21074
|
)).all().map((snapshot) => [snapshot.id, snapshot.rawResponse]));
|
|
@@ -21222,7 +21261,7 @@ async function measurementQuestionReadRoutes(app) {
|
|
|
21222
21261
|
const target = requireTarget2(plan, query.targetKey);
|
|
21223
21262
|
const snapshot = app.db.select(measurementQuestionSnapshotColumns).from(querySnapshots).where(eq22(querySnapshots.id, query.resultId)).get();
|
|
21224
21263
|
if (!snapshot) throw notFound("Measurement question result", query.resultId);
|
|
21225
|
-
const run = app.db.select().from(runs).where(
|
|
21264
|
+
const run = app.db.select().from(runs).where(and17(
|
|
21226
21265
|
eq22(runs.id, snapshot.runId),
|
|
21227
21266
|
eq22(runs.projectId, project.id)
|
|
21228
21267
|
)).get();
|
|
@@ -21673,7 +21712,7 @@ function previousComparableRun(db, active, current) {
|
|
|
21673
21712
|
trigger: runs.trigger,
|
|
21674
21713
|
measurementScope: runs.measurementScope,
|
|
21675
21714
|
measurementExecutionIdentity: runs.measurementExecutionIdentity
|
|
21676
|
-
}).from(runs).where(
|
|
21715
|
+
}).from(runs).where(and18(
|
|
21677
21716
|
eq23(runs.projectId, current.projectId),
|
|
21678
21717
|
// The comparable chain keeps period-over-period alive across a label-only
|
|
21679
21718
|
// republish: a run pinned to a comparable prior revision measured exactly
|
|
@@ -21684,7 +21723,7 @@ function previousComparableRun(db, active, current) {
|
|
|
21684
21723
|
inArray8(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
21685
21724
|
or3(
|
|
21686
21725
|
lt3(runs.createdAt, current.createdAt),
|
|
21687
|
-
|
|
21726
|
+
and18(eq23(runs.createdAt, current.createdAt), lt3(runs.id, current.id))
|
|
21688
21727
|
)
|
|
21689
21728
|
)).orderBy(desc6(runs.createdAt), desc6(runs.id)).all().filter((candidate) => (
|
|
21690
21729
|
// Full reporting never admits probes. A plan slice is itself stored as a
|
|
@@ -21707,7 +21746,7 @@ function previousComparableRun(db, active, current) {
|
|
|
21707
21746
|
if (!previousCandidate) {
|
|
21708
21747
|
return { state: "unavailable", reason: "incomplete" };
|
|
21709
21748
|
}
|
|
21710
|
-
const previous = db.select().from(runs).where(
|
|
21749
|
+
const previous = db.select().from(runs).where(and18(
|
|
21711
21750
|
eq23(runs.id, previousCandidate.id),
|
|
21712
21751
|
eq23(runs.projectId, current.projectId)
|
|
21713
21752
|
)).get();
|
|
@@ -21948,7 +21987,7 @@ async function measurementPortfolioReadRoutes(app) {
|
|
|
21948
21987
|
|
|
21949
21988
|
// ../api-routes/src/visibility-report.ts
|
|
21950
21989
|
import { createHash as createHash4 } from "crypto";
|
|
21951
|
-
import { and as
|
|
21990
|
+
import { and as and19, desc as desc7, eq as eq24, gte as gte4, inArray as inArray9, isNotNull, isNull as isNull4, lte as lte4, ne as ne3 } from "drizzle-orm";
|
|
21952
21991
|
|
|
21953
21992
|
// ../api-routes/src/visibility-report-reader.ts
|
|
21954
21993
|
import { createHash as createHash3 } from "crypto";
|
|
@@ -22972,7 +23011,7 @@ function unsupportedAdvancedResponse(query, active) {
|
|
|
22972
23011
|
});
|
|
22973
23012
|
}
|
|
22974
23013
|
function completedVisibilityRuns(db, projectId, planless, query) {
|
|
22975
|
-
return db.select().from(runs).where(
|
|
23014
|
+
return db.select().from(runs).where(and19(
|
|
22976
23015
|
eq24(runs.projectId, projectId),
|
|
22977
23016
|
eq24(runs.kind, RunKinds["answer-visibility"]),
|
|
22978
23017
|
inArray9(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
@@ -23087,7 +23126,7 @@ function advancedReaderInput(db, projectId, active, query) {
|
|
|
23087
23126
|
}
|
|
23088
23127
|
function simpleReaderInput(db, project, query) {
|
|
23089
23128
|
const sourceRuns = completedVisibilityRuns(db, project.id, true, query);
|
|
23090
|
-
const frozen = new Map(sourceRuns.length === 0 ? [] : db.select().from(simpleMeasurementDefinitions).where(
|
|
23129
|
+
const frozen = new Map(sourceRuns.length === 0 ? [] : db.select().from(simpleMeasurementDefinitions).where(and19(
|
|
23091
23130
|
eq24(simpleMeasurementDefinitions.projectId, project.id),
|
|
23092
23131
|
inArray9(simpleMeasurementDefinitions.runId, sourceRuns.map((run) => run.id))
|
|
23093
23132
|
)).all().map((row) => [row.runId, row.definition]));
|
|
@@ -23145,7 +23184,7 @@ async function visibilityReportRoutes(app) {
|
|
|
23145
23184
|
|
|
23146
23185
|
// ../api-routes/src/query-tracking.ts
|
|
23147
23186
|
import crypto20 from "crypto";
|
|
23148
|
-
import { and as
|
|
23187
|
+
import { and as and20, desc as desc8, eq as eq25, inArray as inArray10, isNotNull as isNotNull2, isNull as isNull5, ne as ne4 } from "drizzle-orm";
|
|
23149
23188
|
var SOURCE_LIMIT = 100;
|
|
23150
23189
|
var MAX_REVIEW_AGE_MS = 15 * 60 * 1e3;
|
|
23151
23190
|
var MAX_REVIEW_FUTURE_SKEW_MS = 60 * 1e3;
|
|
@@ -23324,7 +23363,7 @@ function simpleMeasuredAtByQuery(db, project, queryRows2, opts) {
|
|
|
23324
23363
|
id: runs.id,
|
|
23325
23364
|
finishedAt: runs.finishedAt,
|
|
23326
23365
|
createdAt: runs.createdAt
|
|
23327
|
-
}).from(runs).where(
|
|
23366
|
+
}).from(runs).where(and20(
|
|
23328
23367
|
eq25(runs.projectId, project.id),
|
|
23329
23368
|
eq25(runs.kind, RunKinds["answer-visibility"]),
|
|
23330
23369
|
inArray10(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
@@ -23337,7 +23376,7 @@ function simpleMeasuredAtByQuery(db, project, queryRows2, opts) {
|
|
|
23337
23376
|
for (const row of db.select({
|
|
23338
23377
|
runId: simpleMeasurementDefinitions.runId,
|
|
23339
23378
|
definition: simpleMeasurementDefinitions.definition
|
|
23340
|
-
}).from(simpleMeasurementDefinitions).where(
|
|
23379
|
+
}).from(simpleMeasurementDefinitions).where(and20(
|
|
23341
23380
|
eq25(simpleMeasurementDefinitions.projectId, project.id),
|
|
23342
23381
|
inArray10(simpleMeasurementDefinitions.runId, eligibleRuns.map((run) => run.id))
|
|
23343
23382
|
)).all()) {
|
|
@@ -23445,7 +23484,7 @@ function measuredAtByQuery(db, state, opts) {
|
|
|
23445
23484
|
if (active === null) return simpleMeasuredAtByQuery(db, project, state.queryRows, opts);
|
|
23446
23485
|
const activeSignatures = assignmentSignaturesByQuery(active.plan);
|
|
23447
23486
|
if (activeSignatures.size === 0) return /* @__PURE__ */ new Map();
|
|
23448
|
-
const eligibleRuns = db.select().from(runs).where(
|
|
23487
|
+
const eligibleRuns = db.select().from(runs).where(and20(
|
|
23449
23488
|
eq25(runs.projectId, project.id),
|
|
23450
23489
|
eq25(runs.kind, RunKinds["answer-visibility"]),
|
|
23451
23490
|
inArray10(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
@@ -23459,7 +23498,7 @@ function measuredAtByQuery(db, state, opts) {
|
|
|
23459
23498
|
id: measurementPlanVersions.id,
|
|
23460
23499
|
revision: measurementPlanVersions.revision,
|
|
23461
23500
|
canonicalJson: measurementPlanVersions.canonicalJson
|
|
23462
|
-
}).from(measurementPlanVersions).where(
|
|
23501
|
+
}).from(measurementPlanVersions).where(and20(
|
|
23463
23502
|
eq25(measurementPlanVersions.projectId, project.id),
|
|
23464
23503
|
inArray10(measurementPlanVersions.id, versionIds)
|
|
23465
23504
|
)).all().flatMap((row) => {
|
|
@@ -23767,7 +23806,7 @@ function sourceRecord(db, projectId, addition, manualCapturedAt) {
|
|
|
23767
23806
|
id: researchRunQueries.id,
|
|
23768
23807
|
queryText: researchRunQueries.queryText,
|
|
23769
23808
|
createdAt: researchRunQueries.createdAt
|
|
23770
|
-
}).from(researchRunQueries).innerJoin(researchRuns, eq25(researchRunQueries.researchRunId, researchRuns.id)).where(
|
|
23809
|
+
}).from(researchRunQueries).innerJoin(researchRuns, eq25(researchRunQueries.researchRunId, researchRuns.id)).where(and20(eq25(researchRuns.projectId, projectId), eq25(researchRunQueries.id, addition.input.researchRunQueryId))).get();
|
|
23771
23810
|
if (!row) throw notFound("Saved research query", addition.input.researchRunQueryId);
|
|
23772
23811
|
if (!row.queryText.trim()) throw validationError("Saved research query has no usable text.");
|
|
23773
23812
|
return [{ queryText: row.queryText, provenance: { source: "research", sourceId: row.id, capturedAt: row.createdAt } }];
|
|
@@ -23777,7 +23816,7 @@ function sourceRecord(db, projectId, addition, manualCapturedAt) {
|
|
|
23777
23816
|
id: discoveryProbes.id,
|
|
23778
23817
|
queryText: discoveryProbes.query,
|
|
23779
23818
|
createdAt: discoveryProbes.createdAt
|
|
23780
|
-
}).from(discoveryProbes).innerJoin(discoverySessions, eq25(discoveryProbes.sessionId, discoverySessions.id)).where(
|
|
23819
|
+
}).from(discoveryProbes).innerJoin(discoverySessions, eq25(discoveryProbes.sessionId, discoverySessions.id)).where(and20(eq25(discoverySessions.projectId, projectId), eq25(discoveryProbes.id, addition.input.discoveryProbeId))).get();
|
|
23781
23820
|
if (!row) throw notFound("Saved discovery probe", addition.input.discoveryProbeId);
|
|
23782
23821
|
if (!row.queryText.trim()) throw validationError("Saved discovery probe has no usable text.");
|
|
23783
23822
|
return [{ queryText: row.queryText, provenance: { source: "discovery", sourceId: row.id, capturedAt: row.createdAt } }];
|
|
@@ -23788,7 +23827,7 @@ function sourceRecord(db, projectId, addition, manualCapturedAt) {
|
|
|
23788
23827
|
}
|
|
23789
23828
|
function templateRecords(db, state, addition, audience) {
|
|
23790
23829
|
if (addition.input.source !== "template") return [];
|
|
23791
|
-
const template = db.select().from(measurementQueryTemplates).where(
|
|
23830
|
+
const template = db.select().from(measurementQueryTemplates).where(and20(
|
|
23792
23831
|
eq25(measurementQueryTemplates.projectId, state.project.id),
|
|
23793
23832
|
eq25(measurementQueryTemplates.id, addition.input.templateId)
|
|
23794
23833
|
)).get();
|
|
@@ -24639,7 +24678,7 @@ async function queryTrackingRoutes(app, opts = {}) {
|
|
|
24639
24678
|
|
|
24640
24679
|
// ../api-routes/src/apply.ts
|
|
24641
24680
|
import crypto22 from "crypto";
|
|
24642
|
-
import { and as
|
|
24681
|
+
import { and as and21, eq as eq26 } from "drizzle-orm";
|
|
24643
24682
|
|
|
24644
24683
|
// ../api-routes/src/schedule-utils.ts
|
|
24645
24684
|
import { CronExpressionParser } from "cron-parser";
|
|
@@ -24740,6 +24779,80 @@ function nextRunFromCron(cronExpr, timezone, from = /* @__PURE__ */ new Date())
|
|
|
24740
24779
|
return null;
|
|
24741
24780
|
}
|
|
24742
24781
|
}
|
|
24782
|
+
var MS_PER_CALENDAR_DAY = 24 * 60 * 60 * 1e3;
|
|
24783
|
+
function calendarOrdinal(date) {
|
|
24784
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) return null;
|
|
24785
|
+
const parsed = /* @__PURE__ */ new Date(`${date}T00:00:00.000Z`);
|
|
24786
|
+
if (Number.isNaN(parsed.getTime()) || parsed.toISOString().slice(0, 10) !== date) return null;
|
|
24787
|
+
return Math.floor(parsed.getTime() / MS_PER_CALENDAR_DAY);
|
|
24788
|
+
}
|
|
24789
|
+
function dateFromOrdinal(ordinal) {
|
|
24790
|
+
const date = new Date(ordinal * MS_PER_CALENDAR_DAY);
|
|
24791
|
+
return Number.isNaN(date.getTime()) ? null : date.toISOString().slice(0, 10);
|
|
24792
|
+
}
|
|
24793
|
+
function utcMillis(year, month, day, hour = 0, minute = 0) {
|
|
24794
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
24795
|
+
date.setUTCFullYear(year, month - 1, day);
|
|
24796
|
+
date.setUTCHours(hour, minute, 0, 0);
|
|
24797
|
+
return date.getTime();
|
|
24798
|
+
}
|
|
24799
|
+
function zonedParts(instant, timezone) {
|
|
24800
|
+
try {
|
|
24801
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
24802
|
+
timeZone: timezone,
|
|
24803
|
+
year: "numeric",
|
|
24804
|
+
month: "2-digit",
|
|
24805
|
+
day: "2-digit",
|
|
24806
|
+
hour: "2-digit",
|
|
24807
|
+
minute: "2-digit",
|
|
24808
|
+
hourCycle: "h23"
|
|
24809
|
+
}).formatToParts(instant);
|
|
24810
|
+
const values = Object.fromEntries(parts.filter((part) => part.type !== "literal").map((part) => [part.type, Number(part.value)]));
|
|
24811
|
+
const { year, month, day, hour, minute } = values;
|
|
24812
|
+
return Number.isInteger(year) && Number.isInteger(month) && Number.isInteger(day) && Number.isInteger(hour) && Number.isInteger(minute) ? { year, month, day, hour, minute } : null;
|
|
24813
|
+
} catch {
|
|
24814
|
+
return null;
|
|
24815
|
+
}
|
|
24816
|
+
}
|
|
24817
|
+
function recurrenceDate(recurrence, timezone, ordinal) {
|
|
24818
|
+
const date = dateFromOrdinal(ordinal);
|
|
24819
|
+
if (!date || !/^\d{2}:\d{2}$/.test(recurrence.time)) return null;
|
|
24820
|
+
const [year, month, day] = date.split("-").map(Number);
|
|
24821
|
+
const [hour, minute] = recurrence.time.split(":").map(Number);
|
|
24822
|
+
if ([year, month, day, hour, minute].some((value) => value === void 0 || Number.isNaN(value))) return null;
|
|
24823
|
+
const localAsUtc = utcMillis(year, month, day, hour, minute);
|
|
24824
|
+
const offsets = /* @__PURE__ */ new Set();
|
|
24825
|
+
for (const hours of [-36, -24, -12, 0, 12, 24, 36]) {
|
|
24826
|
+
const probe = new Date(localAsUtc + hours * 60 * 60 * 1e3);
|
|
24827
|
+
const local = zonedParts(probe, timezone);
|
|
24828
|
+
if (!local) continue;
|
|
24829
|
+
offsets.add(utcMillis(local.year, local.month, local.day, local.hour, local.minute) - probe.getTime());
|
|
24830
|
+
}
|
|
24831
|
+
const matches = [...offsets].map((offset) => new Date(localAsUtc - offset)).filter((candidate) => {
|
|
24832
|
+
const local = zonedParts(candidate, timezone);
|
|
24833
|
+
return local?.year === year && local.month === month && local.day === day && local.hour === hour && local.minute === minute;
|
|
24834
|
+
});
|
|
24835
|
+
return matches.length ? new Date(Math.min(...matches.map((candidate) => candidate.getTime()))) : null;
|
|
24836
|
+
}
|
|
24837
|
+
function nextRunFromRecurrence(recurrence, timezone, from = /* @__PURE__ */ new Date()) {
|
|
24838
|
+
if (!Number.isInteger(recurrence.everyDays) || recurrence.everyDays < 1 || recurrence.everyDays > 3650 || !isValidTimezone(timezone)) return null;
|
|
24839
|
+
const anchor = calendarOrdinal(recurrence.startDate);
|
|
24840
|
+
if (anchor === null || !/^\d{2}:\d{2}$/.test(recurrence.time)) return null;
|
|
24841
|
+
const [hour, minute] = recurrence.time.split(":").map(Number);
|
|
24842
|
+
if (hour === void 0 || minute === void 0 || hour > 23 || minute > 59) return null;
|
|
24843
|
+
const local = zonedParts(from, timezone);
|
|
24844
|
+
const localOrdinal = local ? calendarOrdinal(`${String(local.year).padStart(4, "0")}-${String(local.month).padStart(2, "0")}-${String(local.day).padStart(2, "0")}`) : null;
|
|
24845
|
+
if (localOrdinal === null) return null;
|
|
24846
|
+
let occurrenceIndex = Math.max(0, Math.floor((localOrdinal - anchor) / recurrence.everyDays));
|
|
24847
|
+
for (let attempts = 0; attempts < 8; attempts += 1, occurrenceIndex += 1) {
|
|
24848
|
+
const occurrence = recurrenceDate(recurrence, timezone, anchor + occurrenceIndex * recurrence.everyDays);
|
|
24849
|
+
if (occurrence && occurrence > from) return occurrence.toISOString();
|
|
24850
|
+
}
|
|
24851
|
+
return null;
|
|
24852
|
+
}
|
|
24853
|
+
function nextRunFromSchedule(schedule, from = /* @__PURE__ */ new Date()) {
|
|
24854
|
+
return schedule.recurrence ? nextRunFromRecurrence(schedule.recurrence, schedule.timezone, from) : nextRunFromCron(schedule.cronExpr, schedule.timezone, from);
|
|
24855
|
+
}
|
|
24743
24856
|
|
|
24744
24857
|
// ../api-routes/src/webhooks.ts
|
|
24745
24858
|
import crypto21 from "crypto";
|
|
@@ -24952,8 +25065,9 @@ async function applyRoutes(app, opts) {
|
|
|
24952
25065
|
let deleteSchedule = false;
|
|
24953
25066
|
if (config.spec.schedule) {
|
|
24954
25067
|
const schedSpec = config.spec.schedule;
|
|
24955
|
-
let cronExpr;
|
|
25068
|
+
let cronExpr = "";
|
|
24956
25069
|
let preset = null;
|
|
25070
|
+
const recurrence = schedSpec.recurrence ?? null;
|
|
24957
25071
|
if (schedSpec.preset) {
|
|
24958
25072
|
preset = schedSpec.preset;
|
|
24959
25073
|
try {
|
|
@@ -24965,12 +25079,10 @@ async function applyRoutes(app, opts) {
|
|
|
24965
25079
|
} else if (schedSpec.cron) {
|
|
24966
25080
|
cronExpr = schedSpec.cron;
|
|
24967
25081
|
if (!validateCron(cronExpr)) throw validationError(`Invalid cron expression in schedule: ${cronExpr}`);
|
|
24968
|
-
} else {
|
|
24969
|
-
throw validationError('Schedule requires either "preset" or "cron"');
|
|
24970
25082
|
}
|
|
24971
25083
|
const timezone = schedSpec.timezone ?? "UTC";
|
|
24972
25084
|
if (!isValidTimezone(timezone)) throw validationError(`Invalid timezone: ${timezone}`);
|
|
24973
|
-
resolvedSchedule = { cronExpr, preset, timezone };
|
|
25085
|
+
resolvedSchedule = { cronExpr, preset, recurrence, timezone };
|
|
24974
25086
|
} else {
|
|
24975
25087
|
deleteSchedule = true;
|
|
24976
25088
|
}
|
|
@@ -25096,13 +25208,20 @@ async function applyRoutes(app, opts) {
|
|
|
25096
25208
|
});
|
|
25097
25209
|
const AV_KIND = SchedulableRunKinds["answer-visibility"];
|
|
25098
25210
|
if (resolvedSchedule) {
|
|
25099
|
-
const existingSched = tx.select().from(schedules).where(
|
|
25211
|
+
const existingSched = tx.select().from(schedules).where(and21(eq26(schedules.projectId, projectId), eq26(schedules.kind, AV_KIND))).get();
|
|
25100
25212
|
const specEnabled = config.spec.schedule?.enabled;
|
|
25213
|
+
const effectiveEnabled = specEnabled ?? existingSched?.enabled ?? true;
|
|
25214
|
+
const nextRunAt = effectiveEnabled ? nextRunFromSchedule(resolvedSchedule) : null;
|
|
25215
|
+
if (effectiveEnabled && resolvedSchedule.recurrence && !nextRunAt) {
|
|
25216
|
+
throw validationError("Calendar recurrence has no valid future occurrence");
|
|
25217
|
+
}
|
|
25101
25218
|
if (existingSched) {
|
|
25102
25219
|
tx.update(schedules).set({
|
|
25103
25220
|
cronExpr: resolvedSchedule.cronExpr,
|
|
25104
25221
|
preset: resolvedSchedule.preset,
|
|
25222
|
+
recurrence: resolvedSchedule.recurrence,
|
|
25105
25223
|
timezone: resolvedSchedule.timezone,
|
|
25224
|
+
nextRunAt,
|
|
25106
25225
|
providers: config.spec.schedule?.providers ?? [],
|
|
25107
25226
|
...specEnabled === void 0 ? {} : { enabled: specEnabled },
|
|
25108
25227
|
updatedAt: nextScheduleUpdatedAt(existingSched.updatedAt, Date.parse(now))
|
|
@@ -25114,7 +25233,9 @@ async function applyRoutes(app, opts) {
|
|
|
25114
25233
|
kind: AV_KIND,
|
|
25115
25234
|
cronExpr: resolvedSchedule.cronExpr,
|
|
25116
25235
|
preset: resolvedSchedule.preset,
|
|
25236
|
+
recurrence: resolvedSchedule.recurrence,
|
|
25117
25237
|
timezone: resolvedSchedule.timezone,
|
|
25238
|
+
nextRunAt,
|
|
25118
25239
|
enabled: specEnabled ?? true,
|
|
25119
25240
|
providers: config.spec.schedule?.providers ?? [],
|
|
25120
25241
|
createdAt: now,
|
|
@@ -25123,9 +25244,9 @@ async function applyRoutes(app, opts) {
|
|
|
25123
25244
|
}
|
|
25124
25245
|
scheduleAction = "upsert";
|
|
25125
25246
|
} else if (deleteSchedule) {
|
|
25126
|
-
const existingSched = tx.select().from(schedules).where(
|
|
25247
|
+
const existingSched = tx.select().from(schedules).where(and21(eq26(schedules.projectId, projectId), eq26(schedules.kind, AV_KIND))).get();
|
|
25127
25248
|
if (existingSched) {
|
|
25128
|
-
tx.delete(schedules).where(
|
|
25249
|
+
tx.delete(schedules).where(and21(eq26(schedules.projectId, projectId), eq26(schedules.kind, AV_KIND))).run();
|
|
25129
25250
|
scheduleAction = "delete";
|
|
25130
25251
|
}
|
|
25131
25252
|
}
|
|
@@ -25214,7 +25335,7 @@ function normalizeCompetitorList2(domains) {
|
|
|
25214
25335
|
}
|
|
25215
25336
|
|
|
25216
25337
|
// ../api-routes/src/history.ts
|
|
25217
|
-
import { and as
|
|
25338
|
+
import { and as and22, asc as asc3, count, desc as desc9, eq as eq27, gte as gte5, inArray as inArray11 } from "drizzle-orm";
|
|
25218
25339
|
|
|
25219
25340
|
// ../api-routes/src/notification-redaction.ts
|
|
25220
25341
|
var REDACTED_URL = {
|
|
@@ -25266,11 +25387,11 @@ async function historyRoutes(app) {
|
|
|
25266
25387
|
if (!parsed.success) throw validationError("Invalid history cleanup request", { issues: parsed.error.issues });
|
|
25267
25388
|
const input = parsed.data;
|
|
25268
25389
|
return app.db.transaction((tx) => {
|
|
25269
|
-
const active = tx.select({ id: runs.id }).from(runs).where(
|
|
25270
|
-
const activeResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(
|
|
25390
|
+
const active = tx.select({ id: runs.id }).from(runs).where(and22(eq27(runs.projectId, project.id), eq27(runs.kind, RunKinds["answer-visibility"]), inArray11(runs.status, ["queued", "running"]))).get();
|
|
25391
|
+
const activeResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and22(eq27(researchRuns.projectId, project.id), inArray11(researchRuns.status, ["queued", "running"]))).get();
|
|
25271
25392
|
if (active || activeResearch) throw runInProgress(project.name, active ? "answer-visibility" : "research", (active ?? activeResearch).id);
|
|
25272
|
-
const selectedRuns = tx.select({ id: runs.id, kind: runs.kind }).from(runs).where(
|
|
25273
|
-
const selectedResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(
|
|
25393
|
+
const selectedRuns = tx.select({ id: runs.id, kind: runs.kind }).from(runs).where(and22(eq27(runs.projectId, project.id), inArray11(runs.id, input.runIds))).all();
|
|
25394
|
+
const selectedResearch = tx.select({ id: researchRuns.id }).from(researchRuns).where(and22(eq27(researchRuns.projectId, project.id), inArray11(researchRuns.id, input.researchRunIds))).all();
|
|
25274
25395
|
if (selectedRuns.length !== input.runIds.length || selectedResearch.length !== input.researchRunIds.length) throw notFound("Selected saved run in project", project.name);
|
|
25275
25396
|
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.");
|
|
25276
25397
|
const result = {
|
|
@@ -25283,8 +25404,8 @@ async function historyRoutes(app) {
|
|
|
25283
25404
|
healthSnapshots: tx.select({ value: count() }).from(healthSnapshots).where(inArray11(healthSnapshots.runId, input.runIds)).get().value
|
|
25284
25405
|
};
|
|
25285
25406
|
if (input.confirm) {
|
|
25286
|
-
tx.delete(researchRuns).where(
|
|
25287
|
-
tx.delete(runs).where(
|
|
25407
|
+
tx.delete(researchRuns).where(and22(eq27(researchRuns.projectId, project.id), inArray11(researchRuns.id, input.researchRunIds))).run();
|
|
25408
|
+
tx.delete(runs).where(and22(eq27(runs.projectId, project.id), inArray11(runs.id, input.runIds))).run();
|
|
25288
25409
|
writeAuditLog(tx, { projectId: project.id, actor: request.principal ? `${request.principal.kind}:${request.principal.id}` : "api", action: "results.cleared", entityType: "project", entityId: project.id, diff: result, userAgent: request.headers["user-agent"] });
|
|
25289
25410
|
}
|
|
25290
25411
|
return result;
|
|
@@ -25294,21 +25415,21 @@ async function historyRoutes(app) {
|
|
|
25294
25415
|
const project = resolveProject(app.db, request.params.name);
|
|
25295
25416
|
const filters = [eq27(auditLog.projectId, project.id)];
|
|
25296
25417
|
addAuditHistoryFilters(filters, request.query);
|
|
25297
|
-
const rows = app.db.select().from(auditLog).where(
|
|
25418
|
+
const rows = app.db.select().from(auditLog).where(and22(...filters)).orderBy(desc9(auditLog.createdAt)).limit(parseBoundedInt(request.query.limit, 100, 500)).offset(parseBoundedInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER)).all();
|
|
25298
25419
|
return reply.send(rows.map(formatAuditEntry));
|
|
25299
25420
|
});
|
|
25300
25421
|
app.get("/history", async (request, reply) => {
|
|
25301
25422
|
const scopedProjectId = request.apiKey?.projectId;
|
|
25302
25423
|
const filters = scopedProjectId ? [eq27(auditLog.projectId, scopedProjectId)] : [];
|
|
25303
25424
|
addAuditHistoryFilters(filters, request.query);
|
|
25304
|
-
const rows = app.db.select().from(auditLog).where(filters.length > 0 ?
|
|
25425
|
+
const rows = app.db.select().from(auditLog).where(filters.length > 0 ? and22(...filters) : void 0).orderBy(desc9(auditLog.createdAt)).limit(parseBoundedInt(request.query.limit, 100, 500)).offset(parseBoundedInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER)).all();
|
|
25305
25426
|
return reply.send(rows.map(formatAuditEntry));
|
|
25306
25427
|
});
|
|
25307
25428
|
app.get("/projects/:name/snapshots", async (request, reply) => {
|
|
25308
25429
|
const project = resolveProject(app.db, request.params.name);
|
|
25309
25430
|
const limit = parseInt(request.query.limit ?? "50", 10);
|
|
25310
25431
|
const offset = parseInt(request.query.offset ?? "0", 10);
|
|
25311
|
-
const projectRuns = app.db.select({ id: runs.id }).from(runs).where(
|
|
25432
|
+
const projectRuns = app.db.select({ id: runs.id }).from(runs).where(and22(eq27(runs.projectId, project.id), notProbeRun())).all();
|
|
25312
25433
|
if (projectRuns.length === 0) {
|
|
25313
25434
|
return reply.send({ snapshots: [], total: 0 });
|
|
25314
25435
|
}
|
|
@@ -25384,7 +25505,7 @@ async function historyRoutes(app) {
|
|
|
25384
25505
|
app.get("/projects/:name/timeline", async (request, reply) => {
|
|
25385
25506
|
const project = resolveProject(app.db, request.params.name);
|
|
25386
25507
|
const projectQueries = app.db.select().from(queries).where(eq27(queries.projectId, project.id)).all();
|
|
25387
|
-
const runKindFilter =
|
|
25508
|
+
const runKindFilter = and22(
|
|
25388
25509
|
eq27(runs.projectId, project.id),
|
|
25389
25510
|
notProbeRun(),
|
|
25390
25511
|
eq27(runs.kind, RunKinds["answer-visibility"])
|
|
@@ -25614,7 +25735,7 @@ function parseOptionalPositiveInt(value, max2) {
|
|
|
25614
25735
|
}
|
|
25615
25736
|
|
|
25616
25737
|
// ../api-routes/src/analytics.ts
|
|
25617
|
-
import { and as
|
|
25738
|
+
import { and as and23, desc as desc10, eq as eq28, gte as gte6, inArray as inArray12, lt as lt4 } from "drizzle-orm";
|
|
25618
25739
|
|
|
25619
25740
|
// ../api-routes/src/analytics-model-attribution.ts
|
|
25620
25741
|
function logicalSweeps(observations) {
|
|
@@ -25707,7 +25828,7 @@ async function analyticsRoutes(app) {
|
|
|
25707
25828
|
const mentionShareScope = classifyQuery ? "non-brand" : "pooled";
|
|
25708
25829
|
const window = parseWindow(request.query.window);
|
|
25709
25830
|
const cutoff = windowCutoff(window);
|
|
25710
|
-
const projectRuns = app.db.select().from(runs).where(
|
|
25831
|
+
const projectRuns = app.db.select().from(runs).where(and23(
|
|
25711
25832
|
eq28(runs.projectId, project.id),
|
|
25712
25833
|
eq28(runs.kind, RunKinds["answer-visibility"]),
|
|
25713
25834
|
inArray12(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
@@ -25801,7 +25922,7 @@ async function analyticsRoutes(app) {
|
|
|
25801
25922
|
const servedAnchorUnavailable = /* @__PURE__ */ new Set();
|
|
25802
25923
|
const windowProviders = new Set(allSnapshots.map((snapshot) => snapshot.provider));
|
|
25803
25924
|
if (cutoff && windowProviders.size > 0) {
|
|
25804
|
-
const anchorRunPredicate =
|
|
25925
|
+
const anchorRunPredicate = and23(
|
|
25805
25926
|
eq28(runs.projectId, project.id),
|
|
25806
25927
|
eq28(runs.kind, RunKinds["answer-visibility"]),
|
|
25807
25928
|
inArray12(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
@@ -25812,7 +25933,7 @@ async function analyticsRoutes(app) {
|
|
|
25812
25933
|
const anchorScanTruncated = anchorSweepTimes.length > ANCHOR_SWEEP_SCAN_LIMIT;
|
|
25813
25934
|
if (anchorScanTruncated) anchorSweepTimes.length = ANCHOR_SWEEP_SCAN_LIMIT;
|
|
25814
25935
|
if (anchorSweepTimes.length > 0) {
|
|
25815
|
-
const anchorRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
|
|
25936
|
+
const anchorRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and23(anchorRunPredicate, gte6(runs.createdAt, anchorSweepTimes[anchorSweepTimes.length - 1]))).all();
|
|
25816
25937
|
const runIdsBySweep = /* @__PURE__ */ new Map();
|
|
25817
25938
|
for (const run of anchorRuns) {
|
|
25818
25939
|
const ids = runIdsBySweep.get(run.createdAt) ?? [];
|
|
@@ -25962,14 +26083,14 @@ async function analyticsRoutes(app) {
|
|
|
25962
26083
|
const project = resolveProject(app.db, request.params.name);
|
|
25963
26084
|
const window = parseWindow(request.query.window);
|
|
25964
26085
|
const cutoff = windowCutoff(window);
|
|
25965
|
-
const completedRuns = app.db.select().from(runs).where(
|
|
26086
|
+
const completedRuns = app.db.select().from(runs).where(and23(eq28(runs.projectId, project.id), eq28(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc10(runs.createdAt), desc10(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => measuredWhole(app.db, r));
|
|
25966
26087
|
const latestGroup = groupRunsByCreatedAt(completedRuns)[0] ?? [];
|
|
25967
26088
|
const latestGroupRunIds = latestGroup.map((r) => r.id);
|
|
25968
26089
|
const latestRun = pickGroupRepresentative(latestGroup);
|
|
25969
26090
|
if (!latestRun) {
|
|
25970
26091
|
return reply.send({ cited: [], gap: [], uncited: [], mentionedQueries: [], mentionGap: [], notMentioned: [], runId: "", window });
|
|
25971
26092
|
}
|
|
25972
|
-
const windowRuns = app.db.select().from(runs).where(
|
|
26093
|
+
const windowRuns = app.db.select().from(runs).where(and23(eq28(runs.projectId, project.id), eq28(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(runs.createdAt).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => measuredWhole(app.db, r)).filter((r) => !cutoff || r.createdAt >= cutoff);
|
|
25973
26094
|
const windowRunIds = windowRuns.map((r) => r.id);
|
|
25974
26095
|
const competitorDomains = app.db.select({ domain: competitors.domain }).from(competitors).where(eq28(competitors.projectId, project.id)).all().map((c) => c.domain);
|
|
25975
26096
|
const competitorMatchers = new Map(
|
|
@@ -26114,7 +26235,7 @@ async function analyticsRoutes(app) {
|
|
|
26114
26235
|
const mapped = surfaceClassFromCompetitorType(row.competitorType);
|
|
26115
26236
|
if (mapped) storedSurfaceClasses.set(normalizeProjectDomain(row.domain), mapped);
|
|
26116
26237
|
}
|
|
26117
|
-
const windowRuns = app.db.select().from(runs).where(
|
|
26238
|
+
const windowRuns = app.db.select().from(runs).where(and23(eq28(runs.projectId, project.id), eq28(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc10(runs.createdAt), desc10(runs.id)).all().filter((r) => r.status === "completed" || r.status === "partial").filter((r) => measuredWhole(app.db, r)).filter((r) => !cutoff || r.createdAt >= cutoff);
|
|
26118
26239
|
if (windowRuns.length === 0) {
|
|
26119
26240
|
return reply.send({
|
|
26120
26241
|
overall: [],
|
|
@@ -26407,7 +26528,7 @@ function buildCategoryCounts(counts2) {
|
|
|
26407
26528
|
}
|
|
26408
26529
|
|
|
26409
26530
|
// ../api-routes/src/intelligence.ts
|
|
26410
|
-
import { eq as eq29, desc as desc11, and as
|
|
26531
|
+
import { eq as eq29, desc as desc11, and as and24, inArray as inArray13, like } from "drizzle-orm";
|
|
26411
26532
|
var SEVERITY_RANK = { low: 0, medium: 1, high: 2, critical: 3 };
|
|
26412
26533
|
function severitiesAtOrAbove(min2) {
|
|
26413
26534
|
const floor = SEVERITY_RANK[min2];
|
|
@@ -26547,7 +26668,7 @@ async function intelligenceRoutes(app) {
|
|
|
26547
26668
|
}
|
|
26548
26669
|
limit = parsed;
|
|
26549
26670
|
}
|
|
26550
|
-
const rows = app.db.select().from(insights).where(conditions.length === 1 ? conditions[0] :
|
|
26671
|
+
const rows = app.db.select().from(insights).where(conditions.length === 1 ? conditions[0] : and24(...conditions)).orderBy(desc11(insights.createdAt)).all();
|
|
26551
26672
|
const showDismissed = request.query.dismissed === "true";
|
|
26552
26673
|
let result = rows.filter((r) => showDismissed || !r.dismissed).map(mapInsightRow);
|
|
26553
26674
|
if (limit !== void 0) result = result.slice(0, limit);
|
|
@@ -26572,7 +26693,7 @@ async function intelligenceRoutes(app) {
|
|
|
26572
26693
|
});
|
|
26573
26694
|
app.get("/projects/:name/health/latest", async (request, reply) => {
|
|
26574
26695
|
const project = resolveProject(app.db, request.params.name);
|
|
26575
|
-
const projectVisRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
|
|
26696
|
+
const projectVisRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and24(
|
|
26576
26697
|
eq29(runs.projectId, project.id),
|
|
26577
26698
|
eq29(runs.kind, RunKinds["answer-visibility"]),
|
|
26578
26699
|
inArray13(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
@@ -26583,7 +26704,7 @@ async function intelligenceRoutes(app) {
|
|
|
26583
26704
|
const latestGroup = groupRunsByCreatedAt(projectVisRuns)[0] ?? [];
|
|
26584
26705
|
const latestGroupRunIds = latestGroup.map((r) => r.id);
|
|
26585
26706
|
if (latestGroupRunIds.length > 0) {
|
|
26586
|
-
const groupRows = app.db.select().from(healthSnapshots).where(
|
|
26707
|
+
const groupRows = app.db.select().from(healthSnapshots).where(and24(
|
|
26587
26708
|
eq29(healthSnapshots.projectId, project.id),
|
|
26588
26709
|
inArray13(healthSnapshots.runId, latestGroupRunIds)
|
|
26589
26710
|
)).all();
|
|
@@ -26607,13 +26728,13 @@ async function intelligenceRoutes(app) {
|
|
|
26607
26728
|
}
|
|
26608
26729
|
|
|
26609
26730
|
// ../api-routes/src/ai-referral-status.ts
|
|
26610
|
-
import { and as
|
|
26731
|
+
import { and as and25, sql as sql8 } from "drizzle-orm";
|
|
26611
26732
|
var REDIRECT_LIST = sql8.join([...LOCATION_REDIRECT_STATUSES].map((s) => sql8`${s}`), sql8`, `);
|
|
26612
26733
|
function referralLandedCondition() {
|
|
26613
26734
|
return sql8`${aiReferralEventsHourly.status} NOT IN (${REDIRECT_LIST})`;
|
|
26614
26735
|
}
|
|
26615
26736
|
function countableReferralCondition() {
|
|
26616
|
-
return
|
|
26737
|
+
return and25(nonSubresourceReferralPathCondition(), referralLandedCondition());
|
|
26617
26738
|
}
|
|
26618
26739
|
function nonSubresourceReferralPathCondition() {
|
|
26619
26740
|
return sql8`
|
|
@@ -26640,17 +26761,17 @@ function nonSubresourceReferralPathCondition() {
|
|
|
26640
26761
|
}
|
|
26641
26762
|
|
|
26642
26763
|
// ../api-routes/src/report.ts
|
|
26643
|
-
import { and as
|
|
26764
|
+
import { and as and29, desc as desc14, eq as eq33, gte as gte8, inArray as inArray15, lt as lt5, lte as lte6, ne as ne5, or as or4, sql as sql10 } from "drizzle-orm";
|
|
26644
26765
|
|
|
26645
26766
|
// ../api-routes/src/content.ts
|
|
26646
26767
|
import crypto23 from "crypto";
|
|
26647
|
-
import { and as
|
|
26768
|
+
import { and as and28, desc as desc13, eq as eq32 } from "drizzle-orm";
|
|
26648
26769
|
|
|
26649
26770
|
// ../api-routes/src/content-data.ts
|
|
26650
|
-
import { and as
|
|
26771
|
+
import { and as and27, eq as eq31, desc as desc12, gte as gte7, inArray as inArray14, lte as lte5 } from "drizzle-orm";
|
|
26651
26772
|
|
|
26652
26773
|
// ../api-routes/src/gsc-totals.ts
|
|
26653
|
-
import { and as
|
|
26774
|
+
import { and as and26, asc as asc4, eq as eq30, sql as sql9, max, min } from "drizzle-orm";
|
|
26654
26775
|
var WINDOW_DAYS = { "7d": 7, "30d": 30, "90d": 90 };
|
|
26655
26776
|
function resolveGscWindowRange(window, latestDataDate, today) {
|
|
26656
26777
|
if (window === "all") {
|
|
@@ -26703,7 +26824,7 @@ function readGscDailyTotals(db, projectId, startDate, endDate) {
|
|
|
26703
26824
|
impressions: gscDailyTotals.impressions,
|
|
26704
26825
|
position: gscDailyTotals.position
|
|
26705
26826
|
}).from(gscDailyTotals).where(
|
|
26706
|
-
|
|
26827
|
+
and26(
|
|
26707
26828
|
eq30(gscDailyTotals.projectId, projectId),
|
|
26708
26829
|
sql9`${gscDailyTotals.date} >= ${startDate}`,
|
|
26709
26830
|
sql9`${gscDailyTotals.date} <= ${endDate}`
|
|
@@ -26733,7 +26854,7 @@ function readGscQueryDailyRows(db, projectId, startDate, endDate) {
|
|
|
26733
26854
|
impressions: gscQueryDailyTotals.impressions,
|
|
26734
26855
|
position: gscQueryDailyTotals.position
|
|
26735
26856
|
}).from(gscQueryDailyTotals).where(
|
|
26736
|
-
|
|
26857
|
+
and26(
|
|
26737
26858
|
eq30(gscQueryDailyTotals.projectId, projectId),
|
|
26738
26859
|
sql9`${gscQueryDailyTotals.date} >= ${startDate}`,
|
|
26739
26860
|
sql9`${gscQueryDailyTotals.date} <= ${endDate}`
|
|
@@ -26916,7 +27037,7 @@ function listCompetitorDomains(db, projectId) {
|
|
|
26916
27037
|
}
|
|
26917
27038
|
function listRecentAnswerVisibilityRunIds(db, projectId, limit, locationFilter) {
|
|
26918
27039
|
const rows = db.select({ id: runs.id, location: runs.location }).from(runs).where(
|
|
26919
|
-
|
|
27040
|
+
and27(
|
|
26920
27041
|
eq31(runs.projectId, projectId),
|
|
26921
27042
|
eq31(runs.kind, RunKinds["answer-visibility"]),
|
|
26922
27043
|
// Queued/running/failed/cancelled runs may have partial or no
|
|
@@ -26948,7 +27069,7 @@ function buildGaTrafficByPage(db, projectId, window) {
|
|
|
26948
27069
|
const rows = db.select({
|
|
26949
27070
|
landingPage: gaTrafficSnapshots.landingPage,
|
|
26950
27071
|
organicSessions: gaTrafficSnapshots.organicSessions
|
|
26951
|
-
}).from(gaTrafficSnapshots).where(
|
|
27072
|
+
}).from(gaTrafficSnapshots).where(and27(
|
|
26952
27073
|
eq31(gaTrafficSnapshots.projectId, projectId),
|
|
26953
27074
|
gte7(gaTrafficSnapshots.date, window.startDate),
|
|
26954
27075
|
lte5(gaTrafficSnapshots.date, window.endDate)
|
|
@@ -26971,7 +27092,7 @@ function resolveContentGaWindow(db, projectId, windowDays2) {
|
|
|
26971
27092
|
function sumAiReferralSessions(db, projectId, window) {
|
|
26972
27093
|
if (!window) return 0;
|
|
26973
27094
|
const rows = db.select({ sessions: gaAiReferrals.sessions }).from(gaAiReferrals).where(
|
|
26974
|
-
|
|
27095
|
+
and27(
|
|
26975
27096
|
eq31(gaAiReferrals.projectId, projectId),
|
|
26976
27097
|
eq31(gaAiReferrals.sourceDimension, "session"),
|
|
26977
27098
|
// Bounded for the same reason the per-page read is: this scales every
|
|
@@ -26998,7 +27119,7 @@ function buildCandidateQueries(opts) {
|
|
|
26998
27119
|
snapshotsByQuery.set(row.queryId, list);
|
|
26999
27120
|
}
|
|
27000
27121
|
const gscWindow = resolveContentGscWindow(opts.db, opts.projectId, opts.gscWindowDays);
|
|
27001
|
-
const pageRows = gscWindow ? opts.db.select().from(gscSearchData).where(
|
|
27122
|
+
const pageRows = gscWindow ? opts.db.select().from(gscSearchData).where(and27(
|
|
27002
27123
|
eq31(gscSearchData.projectId, opts.projectId),
|
|
27003
27124
|
gte7(gscSearchData.date, gscWindow.startDate),
|
|
27004
27125
|
lte5(gscSearchData.date, gscWindow.endDate)
|
|
@@ -27365,7 +27486,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
27365
27486
|
dismissedAt: now
|
|
27366
27487
|
}
|
|
27367
27488
|
}).run();
|
|
27368
|
-
const row = app.db.select().from(contentTargetDismissals).where(
|
|
27489
|
+
const row = app.db.select().from(contentTargetDismissals).where(and28(
|
|
27369
27490
|
eq32(contentTargetDismissals.projectId, project.id),
|
|
27370
27491
|
eq32(contentTargetDismissals.targetRef, targetRef)
|
|
27371
27492
|
)).get();
|
|
@@ -27375,7 +27496,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
27375
27496
|
app.delete("/projects/:name/content/dismissals/:targetRef", async (request, reply) => {
|
|
27376
27497
|
const project = resolveProject(app.db, request.params.name);
|
|
27377
27498
|
const { targetRef } = request.params;
|
|
27378
|
-
const result = app.db.delete(contentTargetDismissals).where(
|
|
27499
|
+
const result = app.db.delete(contentTargetDismissals).where(and28(
|
|
27379
27500
|
eq32(contentTargetDismissals.projectId, project.id),
|
|
27380
27501
|
eq32(contentTargetDismissals.targetRef, targetRef)
|
|
27381
27502
|
)).run();
|
|
@@ -27386,7 +27507,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
27386
27507
|
});
|
|
27387
27508
|
app.get("/projects/:name/content/recommendations/:targetRef/analysis", async (request, reply) => {
|
|
27388
27509
|
const project = resolveProject(app.db, request.params.name);
|
|
27389
|
-
const row = app.db.select().from(recommendationExplanations).where(
|
|
27510
|
+
const row = app.db.select().from(recommendationExplanations).where(and28(
|
|
27390
27511
|
eq32(recommendationExplanations.projectId, project.id),
|
|
27391
27512
|
eq32(recommendationExplanations.targetRef, request.params.targetRef)
|
|
27392
27513
|
)).orderBy(desc13(recommendationExplanations.generatedAt)).limit(1).get();
|
|
@@ -27414,7 +27535,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
27414
27535
|
throw notFound("contentRecommendation", targetRef);
|
|
27415
27536
|
}
|
|
27416
27537
|
if (!body.forceRefresh) {
|
|
27417
|
-
const cached = app.db.select().from(recommendationExplanations).where(
|
|
27538
|
+
const cached = app.db.select().from(recommendationExplanations).where(and28(
|
|
27418
27539
|
eq32(recommendationExplanations.projectId, project.id),
|
|
27419
27540
|
eq32(recommendationExplanations.targetRef, targetRef)
|
|
27420
27541
|
)).orderBy(desc13(recommendationExplanations.generatedAt)).limit(1).get();
|
|
@@ -27453,7 +27574,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
27453
27574
|
generatedAt: now
|
|
27454
27575
|
}
|
|
27455
27576
|
}).run();
|
|
27456
|
-
const row = app.db.select().from(recommendationExplanations).where(
|
|
27577
|
+
const row = app.db.select().from(recommendationExplanations).where(and28(
|
|
27457
27578
|
eq32(recommendationExplanations.projectId, project.id),
|
|
27458
27579
|
eq32(recommendationExplanations.targetRef, targetRef),
|
|
27459
27580
|
eq32(recommendationExplanations.promptVersion, result.promptVersion)
|
|
@@ -27537,7 +27658,7 @@ async function contentRoutes(app, opts = {}) {
|
|
|
27537
27658
|
generatedAt: now
|
|
27538
27659
|
}
|
|
27539
27660
|
}).run();
|
|
27540
|
-
const row = app.db.select().from(recommendationBriefs).where(
|
|
27661
|
+
const row = app.db.select().from(recommendationBriefs).where(and28(
|
|
27541
27662
|
eq32(recommendationBriefs.projectId, project.id),
|
|
27542
27663
|
eq32(recommendationBriefs.targetRef, targetRef),
|
|
27543
27664
|
eq32(recommendationBriefs.promptVersion, result.promptVersion)
|
|
@@ -27567,7 +27688,7 @@ function lookupCachedBrief(db, projectId, targetRef, promptVersion) {
|
|
|
27567
27688
|
if (promptVersion !== void 0) {
|
|
27568
27689
|
conditions.push(eq32(recommendationBriefs.promptVersion, promptVersion));
|
|
27569
27690
|
}
|
|
27570
|
-
return db.select().from(recommendationBriefs).where(
|
|
27691
|
+
return db.select().from(recommendationBriefs).where(and28(...conditions)).orderBy(desc13(recommendationBriefs.generatedAt)).limit(1).get();
|
|
27571
27692
|
}
|
|
27572
27693
|
function parseLimitParam(raw) {
|
|
27573
27694
|
if (raw === void 0) return void 0;
|
|
@@ -30094,7 +30215,7 @@ function buildGscSection(db, projectId, projectBrandNames, canonicalDomain, trac
|
|
|
30094
30215
|
if (!maxDate) return null;
|
|
30095
30216
|
const startDate = windowStartDate(maxDate, windowDays2);
|
|
30096
30217
|
const rows = db.select().from(gscSearchData).where(
|
|
30097
|
-
|
|
30218
|
+
and29(
|
|
30098
30219
|
eq33(gscSearchData.projectId, projectId),
|
|
30099
30220
|
gte8(gscSearchData.date, startDate),
|
|
30100
30221
|
lte6(gscSearchData.date, maxDate)
|
|
@@ -30193,7 +30314,7 @@ function buildGscSection(db, projectId, projectBrandNames, canonicalDomain, trac
|
|
|
30193
30314
|
function buildGaSection(db, projectId, windowDays2) {
|
|
30194
30315
|
const gaWindowKey = GA_WINDOW_SUMMARY_KEYS[windowDays2];
|
|
30195
30316
|
const windowSummary = gaWindowKey ? db.select().from(gaTrafficWindowSummaries).where(
|
|
30196
|
-
|
|
30317
|
+
and29(
|
|
30197
30318
|
eq33(gaTrafficWindowSummaries.projectId, projectId),
|
|
30198
30319
|
eq33(gaTrafficWindowSummaries.windowKey, gaWindowKey)
|
|
30199
30320
|
)
|
|
@@ -30206,7 +30327,7 @@ function buildGaSection(db, projectId, windowDays2) {
|
|
|
30206
30327
|
const snapshotMaxInWindow = summaryPeriod?.periodEnd || snapshotMaxDate;
|
|
30207
30328
|
const snapshotStartDate = summaryPeriod?.periodStart || (snapshotMaxDate ? windowStartDate(snapshotMaxDate, windowDays2) : "");
|
|
30208
30329
|
const snapshotRows = snapshotStartDate ? db.select().from(gaTrafficSnapshots).where(
|
|
30209
|
-
|
|
30330
|
+
and29(
|
|
30210
30331
|
eq33(gaTrafficSnapshots.projectId, projectId),
|
|
30211
30332
|
gte8(gaTrafficSnapshots.date, snapshotStartDate),
|
|
30212
30333
|
lte6(gaTrafficSnapshots.date, snapshotMaxInWindow)
|
|
@@ -30243,7 +30364,7 @@ function buildGaSection(db, projectId, windowDays2) {
|
|
|
30243
30364
|
trafficClass: gaAiReferrals.trafficClass,
|
|
30244
30365
|
channelGroup: gaAiReferrals.channelGroup,
|
|
30245
30366
|
sessions: sql10`COALESCE(SUM(${gaAiReferrals.sessions}), 0)`
|
|
30246
|
-
}).from(gaAiReferrals).where(
|
|
30367
|
+
}).from(gaAiReferrals).where(and29(...aiConditions)).groupBy(gaAiReferrals.trafficClass, gaAiReferrals.channelGroup).all();
|
|
30247
30368
|
let paidAiSessions = 0;
|
|
30248
30369
|
let organicAiSessions = 0;
|
|
30249
30370
|
let aiOrganicOverlap = 0;
|
|
@@ -30291,7 +30412,7 @@ function buildGaSection(db, projectId, windowDays2) {
|
|
|
30291
30412
|
}
|
|
30292
30413
|
function buildSocialReferrals(db, projectId, windowDays2) {
|
|
30293
30414
|
const window = resolveAiReferralWindow(db, projectId, windowDays2);
|
|
30294
|
-
const rows = db.select().from(gaSocialReferrals).where(
|
|
30415
|
+
const rows = db.select().from(gaSocialReferrals).where(and29(
|
|
30295
30416
|
eq33(gaSocialReferrals.projectId, projectId),
|
|
30296
30417
|
gte8(gaSocialReferrals.date, window.start),
|
|
30297
30418
|
lte6(gaSocialReferrals.date, window.end)
|
|
@@ -30328,7 +30449,7 @@ function buildSocialReferrals(db, projectId, windowDays2) {
|
|
|
30328
30449
|
}
|
|
30329
30450
|
function resolveAiReferralWindow(db, projectId, windowDays2) {
|
|
30330
30451
|
const windowKey = GA_WINDOW_SUMMARY_KEYS[windowDays2];
|
|
30331
|
-
const windowSummary = windowKey ? db.select({ periodStart: gaTrafficWindowSummaries.periodStart, periodEnd: gaTrafficWindowSummaries.periodEnd }).from(gaTrafficWindowSummaries).where(
|
|
30452
|
+
const windowSummary = windowKey ? db.select({ periodStart: gaTrafficWindowSummaries.periodStart, periodEnd: gaTrafficWindowSummaries.periodEnd }).from(gaTrafficWindowSummaries).where(and29(
|
|
30332
30453
|
eq33(gaTrafficWindowSummaries.projectId, projectId),
|
|
30333
30454
|
eq33(gaTrafficWindowSummaries.windowKey, windowKey)
|
|
30334
30455
|
)).get() : void 0;
|
|
@@ -30339,7 +30460,7 @@ function resolveAiReferralWindow(db, projectId, windowDays2) {
|
|
|
30339
30460
|
}
|
|
30340
30461
|
function buildAiReferrals(db, projectId, windowDays2) {
|
|
30341
30462
|
const window = resolveAiReferralWindow(db, projectId, windowDays2);
|
|
30342
|
-
const rows = db.select().from(gaAiReferrals).where(
|
|
30463
|
+
const rows = db.select().from(gaAiReferrals).where(and29(
|
|
30343
30464
|
eq33(gaAiReferrals.projectId, projectId),
|
|
30344
30465
|
sql10`${gaAiReferrals.date} >= ${window.start}`,
|
|
30345
30466
|
sql10`${gaAiReferrals.date} <= ${window.end}`
|
|
@@ -30412,7 +30533,7 @@ function buildAiReferrals(db, projectId, windowDays2) {
|
|
|
30412
30533
|
}
|
|
30413
30534
|
function buildServerActivity(db, projectId, windowDays2) {
|
|
30414
30535
|
const sourceRows = db.select({ id: trafficSources.id }).from(trafficSources).where(
|
|
30415
|
-
|
|
30536
|
+
and29(
|
|
30416
30537
|
eq33(trafficSources.projectId, projectId),
|
|
30417
30538
|
ne5(trafficSources.status, TrafficSourceStatuses.archived)
|
|
30418
30539
|
)
|
|
@@ -30428,7 +30549,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30428
30549
|
const trendStart = new Date(trendStartMs).toISOString();
|
|
30429
30550
|
const sumVerifiedCrawlers = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
|
|
30430
30551
|
db.select({ total: sql10`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
30431
|
-
|
|
30552
|
+
and29(
|
|
30432
30553
|
eq33(crawlerEventsHourly.projectId, projectId),
|
|
30433
30554
|
eq33(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
30434
30555
|
gte8(crawlerEventsHourly.tsHour, windowStartIso),
|
|
@@ -30438,7 +30559,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30438
30559
|
);
|
|
30439
30560
|
const sumUnverifiedCrawlers = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
|
|
30440
30561
|
db.select({ total: sql10`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
30441
|
-
|
|
30562
|
+
and29(
|
|
30442
30563
|
eq33(crawlerEventsHourly.projectId, projectId),
|
|
30443
30564
|
ne5(crawlerEventsHourly.verificationStatus, VerificationStatuses.verified),
|
|
30444
30565
|
gte8(crawlerEventsHourly.tsHour, windowStartIso),
|
|
@@ -30452,7 +30573,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30452
30573
|
paid: sql10`COALESCE(SUM(${aiReferralEventsHourly.paidSessionsOrHits}), 0)`,
|
|
30453
30574
|
organic: sql10`COALESCE(SUM(${aiReferralEventsHourly.organicSessionsOrHits}), 0)`
|
|
30454
30575
|
}).from(aiReferralEventsHourly).where(
|
|
30455
|
-
|
|
30576
|
+
and29(
|
|
30456
30577
|
eq33(aiReferralEventsHourly.projectId, projectId),
|
|
30457
30578
|
countableReferralCondition(),
|
|
30458
30579
|
gte8(aiReferralEventsHourly.tsHour, windowStartIso),
|
|
@@ -30463,7 +30584,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30463
30584
|
};
|
|
30464
30585
|
const sumUserFetches = (windowStartIso, windowEndIso, exclusiveEnd = false) => Number(
|
|
30465
30586
|
db.select({ total: sql10`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
30466
|
-
|
|
30587
|
+
and29(
|
|
30467
30588
|
eq33(aiUserFetchEventsHourly.projectId, projectId),
|
|
30468
30589
|
gte8(aiUserFetchEventsHourly.tsHour, windowStartIso),
|
|
30469
30590
|
exclusiveEnd ? lt5(aiUserFetchEventsHourly.tsHour, windowEndIso) : lte6(aiUserFetchEventsHourly.tsHour, windowEndIso)
|
|
@@ -30479,7 +30600,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30479
30600
|
const referralCurrent = sumReferrals(headlineStart, headlineEnd);
|
|
30480
30601
|
const referralAllCurrent = Number(
|
|
30481
30602
|
db.select({ total: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
30482
|
-
|
|
30603
|
+
and29(
|
|
30483
30604
|
eq33(aiReferralEventsHourly.projectId, projectId),
|
|
30484
30605
|
nonSubresourceReferralPathCondition(),
|
|
30485
30606
|
gte8(aiReferralEventsHourly.tsHour, headlineStart),
|
|
@@ -30494,7 +30615,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30494
30615
|
verificationStatus: crawlerEventsHourly.verificationStatus,
|
|
30495
30616
|
hits: sql10`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
30496
30617
|
}).from(crawlerEventsHourly).where(
|
|
30497
|
-
|
|
30618
|
+
and29(
|
|
30498
30619
|
eq33(crawlerEventsHourly.projectId, projectId),
|
|
30499
30620
|
gte8(crawlerEventsHourly.tsHour, headlineStart),
|
|
30500
30621
|
lte6(crawlerEventsHourly.tsHour, headlineEnd)
|
|
@@ -30504,7 +30625,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30504
30625
|
operator: crawlerEventsHourly.operator,
|
|
30505
30626
|
hits: sql10`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
30506
30627
|
}).from(crawlerEventsHourly).where(
|
|
30507
|
-
|
|
30628
|
+
and29(
|
|
30508
30629
|
eq33(crawlerEventsHourly.projectId, projectId),
|
|
30509
30630
|
gte8(crawlerEventsHourly.tsHour, priorStart),
|
|
30510
30631
|
lt5(crawlerEventsHourly.tsHour, headlineStart)
|
|
@@ -30514,7 +30635,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30514
30635
|
operator: aiReferralEventsHourly.operator,
|
|
30515
30636
|
hits: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
|
|
30516
30637
|
}).from(aiReferralEventsHourly).where(
|
|
30517
|
-
|
|
30638
|
+
and29(
|
|
30518
30639
|
eq33(aiReferralEventsHourly.projectId, projectId),
|
|
30519
30640
|
countableReferralCondition(),
|
|
30520
30641
|
gte8(aiReferralEventsHourly.tsHour, headlineStart),
|
|
@@ -30525,7 +30646,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30525
30646
|
operator: aiUserFetchEventsHourly.operator,
|
|
30526
30647
|
hits: sql10`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
|
|
30527
30648
|
}).from(aiUserFetchEventsHourly).where(
|
|
30528
|
-
|
|
30649
|
+
and29(
|
|
30529
30650
|
eq33(aiUserFetchEventsHourly.projectId, projectId),
|
|
30530
30651
|
gte8(aiUserFetchEventsHourly.tsHour, headlineStart),
|
|
30531
30652
|
lte6(aiUserFetchEventsHourly.tsHour, headlineEnd)
|
|
@@ -30570,7 +30691,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30570
30691
|
unverifiedHits: sql10`COALESCE(SUM(CASE WHEN ${crawlerEventsHourly.verificationStatus} <> ${VerificationStatuses.verified} THEN ${crawlerEventsHourly.hits} ELSE 0 END), 0)`,
|
|
30571
30692
|
operators: sql10`COUNT(DISTINCT ${crawlerEventsHourly.operator})`
|
|
30572
30693
|
}).from(crawlerEventsHourly).where(
|
|
30573
|
-
|
|
30694
|
+
and29(
|
|
30574
30695
|
eq33(crawlerEventsHourly.projectId, projectId),
|
|
30575
30696
|
gte8(crawlerEventsHourly.tsHour, headlineStart),
|
|
30576
30697
|
lte6(crawlerEventsHourly.tsHour, headlineEnd)
|
|
@@ -30587,7 +30708,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30587
30708
|
arrivals: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
|
|
30588
30709
|
landingPaths: sql10`COUNT(DISTINCT ${aiReferralEventsHourly.landingPathNormalized})`
|
|
30589
30710
|
}).from(aiReferralEventsHourly).where(
|
|
30590
|
-
|
|
30711
|
+
and29(
|
|
30591
30712
|
eq33(aiReferralEventsHourly.projectId, projectId),
|
|
30592
30713
|
countableReferralCondition(),
|
|
30593
30714
|
gte8(aiReferralEventsHourly.tsHour, headlineStart),
|
|
@@ -30604,7 +30725,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30604
30725
|
arrivals: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
|
|
30605
30726
|
products: sql10`COUNT(DISTINCT ${aiReferralEventsHourly.product})`
|
|
30606
30727
|
}).from(aiReferralEventsHourly).where(
|
|
30607
|
-
|
|
30728
|
+
and29(
|
|
30608
30729
|
eq33(aiReferralEventsHourly.projectId, projectId),
|
|
30609
30730
|
countableReferralCondition(),
|
|
30610
30731
|
gte8(aiReferralEventsHourly.tsHour, headlineStart),
|
|
@@ -30621,7 +30742,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30621
30742
|
verifiedHits: sql10`COALESCE(SUM(CASE WHEN ${crawlerEventsHourly.verificationStatus} = ${VerificationStatuses.verified} THEN ${crawlerEventsHourly.hits} ELSE 0 END), 0)`,
|
|
30622
30743
|
unverifiedHits: sql10`COALESCE(SUM(CASE WHEN ${crawlerEventsHourly.verificationStatus} <> ${VerificationStatuses.verified} THEN ${crawlerEventsHourly.hits} ELSE 0 END), 0)`
|
|
30623
30744
|
}).from(crawlerEventsHourly).where(
|
|
30624
|
-
|
|
30745
|
+
and29(
|
|
30625
30746
|
eq33(crawlerEventsHourly.projectId, projectId),
|
|
30626
30747
|
gte8(crawlerEventsHourly.tsHour, trendStart),
|
|
30627
30748
|
lte6(crawlerEventsHourly.tsHour, headlineEnd)
|
|
@@ -30631,7 +30752,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30631
30752
|
date: sql10`SUBSTR(${aiReferralEventsHourly.tsHour}, 1, 10)`,
|
|
30632
30753
|
hits: sql10`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
|
|
30633
30754
|
}).from(aiReferralEventsHourly).where(
|
|
30634
|
-
|
|
30755
|
+
and29(
|
|
30635
30756
|
eq33(aiReferralEventsHourly.projectId, projectId),
|
|
30636
30757
|
countableReferralCondition(),
|
|
30637
30758
|
gte8(aiReferralEventsHourly.tsHour, trendStart),
|
|
@@ -30642,7 +30763,7 @@ function buildServerActivity(db, projectId, windowDays2) {
|
|
|
30642
30763
|
date: sql10`SUBSTR(${aiUserFetchEventsHourly.tsHour}, 1, 10)`,
|
|
30643
30764
|
hits: sql10`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
|
|
30644
30765
|
}).from(aiUserFetchEventsHourly).where(
|
|
30645
|
-
|
|
30766
|
+
and29(
|
|
30646
30767
|
eq33(aiUserFetchEventsHourly.projectId, projectId),
|
|
30647
30768
|
gte8(aiUserFetchEventsHourly.tsHour, trendStart),
|
|
30648
30769
|
lte6(aiUserFetchEventsHourly.tsHour, headlineEnd)
|
|
@@ -30747,7 +30868,7 @@ function buildIndexingHealth(db, projectId) {
|
|
|
30747
30868
|
return null;
|
|
30748
30869
|
}
|
|
30749
30870
|
function buildCitationsTrend(db, projectId, queryLookup, locationFilter) {
|
|
30750
|
-
const visibilityRuns = db.select().from(runs).where(
|
|
30871
|
+
const visibilityRuns = db.select().from(runs).where(and29(eq33(runs.projectId, projectId), eq33(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter);
|
|
30751
30872
|
const totalQueries = queryLookup.byId.size;
|
|
30752
30873
|
const points = [];
|
|
30753
30874
|
for (const run of visibilityRuns) {
|
|
@@ -30795,7 +30916,7 @@ function buildCitationsTrend(db, projectId, queryLookup, locationFilter) {
|
|
|
30795
30916
|
}
|
|
30796
30917
|
function buildInsightList(db, projectId, locationFilter) {
|
|
30797
30918
|
const recentRunIds = db.select({ id: runs.id, location: runs.location }).from(runs).where(
|
|
30798
|
-
|
|
30919
|
+
and29(
|
|
30799
30920
|
eq33(runs.projectId, projectId),
|
|
30800
30921
|
eq33(runs.kind, RunKinds["answer-visibility"]),
|
|
30801
30922
|
or4(eq33(runs.status, RunStatuses.completed), eq33(runs.status, RunStatuses.partial)),
|
|
@@ -30803,7 +30924,7 @@ function buildInsightList(db, projectId, locationFilter) {
|
|
|
30803
30924
|
)
|
|
30804
30925
|
).orderBy(desc14(runs.createdAt)).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter).slice(0, INSIGHT_LOOKBACK_RUNS).map((r) => r.id);
|
|
30805
30926
|
if (recentRunIds.length === 0) return [];
|
|
30806
|
-
const rows = db.select().from(insights).where(
|
|
30927
|
+
const rows = db.select().from(insights).where(and29(eq33(insights.projectId, projectId), inArray15(insights.runId, recentRunIds))).orderBy(desc14(insights.createdAt)).all();
|
|
30807
30928
|
const severityRank = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
30808
30929
|
const flat = rows.filter((r) => !r.dismissed).map((r) => {
|
|
30809
30930
|
const recommendation = r.recommendation;
|
|
@@ -31370,7 +31491,7 @@ function buildProjectReport(db, projectName, periodDays) {
|
|
|
31370
31491
|
const project = resolveProject(db, projectName);
|
|
31371
31492
|
const queryLookup = loadQueryLookup(db, project.id);
|
|
31372
31493
|
const comparisonWindowDays = reportComparisonWindowDays(periodDays);
|
|
31373
|
-
const allRuns = db.select().from(runs).where(
|
|
31494
|
+
const allRuns = db.select().from(runs).where(and29(eq33(runs.projectId, project.id), notProbeRun())).orderBy(desc14(runs.createdAt), desc14(runs.id)).all();
|
|
31374
31495
|
const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
|
|
31375
31496
|
const completedVisRunGroups = groupRunsByCreatedAt(
|
|
31376
31497
|
visibilityRuns.filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial)
|
|
@@ -31633,10 +31754,10 @@ async function reportRoutes(app) {
|
|
|
31633
31754
|
}
|
|
31634
31755
|
|
|
31635
31756
|
// ../api-routes/src/organic-evidence.ts
|
|
31636
|
-
import { and as
|
|
31757
|
+
import { and as and31, desc as desc15, eq as eq35, gte as gte10, lte as lte8, or as or6, sql as sql12 } from "drizzle-orm";
|
|
31637
31758
|
|
|
31638
31759
|
// ../api-routes/src/ga-measurement-analysis.ts
|
|
31639
|
-
import { and as
|
|
31760
|
+
import { and as and30, eq as eq34, gte as gte9, lte as lte7, or as or5, sql as sql11 } from "drizzle-orm";
|
|
31640
31761
|
var UNKNOWN_LANDING_PAGE = "(not set)";
|
|
31641
31762
|
function addDays(date, offset) {
|
|
31642
31763
|
const value = /* @__PURE__ */ new Date(`${date}T00:00:00.000Z`);
|
|
@@ -31824,27 +31945,27 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
31824
31945
|
};
|
|
31825
31946
|
const acquisitionScope = scopedConditions(gaAcquisitionDaily.hostName, gaAcquisitionDaily.landingPageNormalized, gaAcquisitionDaily.landingPage);
|
|
31826
31947
|
const leadLandingScope = scopedConditions(gaLeadEventsDaily.hostName, gaLeadEventsDaily.landingPageNormalized, gaLeadEventsDaily.landingPage);
|
|
31827
|
-
const acquisitionAnchor = db.select({ date: sql11`max(${gaAcquisitionDaily.date})` }).from(gaAcquisitionDaily).where(
|
|
31828
|
-
const leadAnchor = db.select({ date: sql11`max(${gaLeadEventsDaily.date})` }).from(gaLeadEventsDaily).where(
|
|
31948
|
+
const acquisitionAnchor = db.select({ date: sql11`max(${gaAcquisitionDaily.date})` }).from(gaAcquisitionDaily).where(and30(eq34(gaAcquisitionDaily.projectId, project.id), ...acquisitionScope)).get()?.date ?? null;
|
|
31949
|
+
const leadAnchor = db.select({ date: sql11`max(${gaLeadEventsDaily.date})` }).from(gaLeadEventsDaily).where(and30(eq34(gaLeadEventsDaily.projectId, project.id), or5(
|
|
31829
31950
|
eq34(gaLeadEventsDaily.attributionScope, "channel"),
|
|
31830
|
-
|
|
31951
|
+
and30(eq34(gaLeadEventsDaily.attributionScope, "landing-page"), ...leadLandingScope)
|
|
31831
31952
|
))).get()?.date ?? null;
|
|
31832
31953
|
const gaAnchor = [acquisitionAnchor, leadAnchor].filter((date) => date !== null).sort().at(-1) ?? null;
|
|
31833
31954
|
const gaPeriods = gaAnchor ? buildPeriods(gaAnchor, days) : [];
|
|
31834
31955
|
const gaStartDate = gaPeriods[0]?.startDate;
|
|
31835
|
-
const acquisitionRows = gaStartDate ? db.select().from(gaAcquisitionDaily).where(
|
|
31836
|
-
const leadRows = gaStartDate ? db.select().from(gaLeadEventsDaily).where(
|
|
31956
|
+
const acquisitionRows = gaStartDate ? db.select().from(gaAcquisitionDaily).where(and30(eq34(gaAcquisitionDaily.projectId, project.id), gte9(gaAcquisitionDaily.date, gaStartDate), lte7(gaAcquisitionDaily.date, gaAnchor))).all() : [];
|
|
31957
|
+
const leadRows = gaStartDate ? db.select().from(gaLeadEventsDaily).where(and30(eq34(gaLeadEventsDaily.projectId, project.id), gte9(gaLeadEventsDaily.date, gaStartDate), lte7(gaLeadEventsDaily.date, gaAnchor))).all() : [];
|
|
31837
31958
|
const engagementAnchor = db.select({ date: sql11`max(${gaDailyTotals.date})` }).from(gaDailyTotals).where(eq34(gaDailyTotals.projectId, project.id)).get()?.date ?? null;
|
|
31838
31959
|
const engagementPeriodWindow = engagementAnchor ? buildPeriods(engagementAnchor, days) : [];
|
|
31839
31960
|
const engagementStartDate = engagementPeriodWindow[0]?.startDate;
|
|
31840
|
-
const engagementRows = engagementStartDate ? db.select().from(gaDailyTotals).where(
|
|
31961
|
+
const engagementRows = engagementStartDate ? db.select().from(gaDailyTotals).where(and30(
|
|
31841
31962
|
eq34(gaDailyTotals.projectId, project.id),
|
|
31842
31963
|
gte9(gaDailyTotals.date, engagementStartDate),
|
|
31843
31964
|
lte7(gaDailyTotals.date, engagementAnchor)
|
|
31844
31965
|
)).all() : [];
|
|
31845
31966
|
const engagementAvailableFrom = db.select({
|
|
31846
31967
|
date: sql11`min(${gaDailyTotals.date})`
|
|
31847
|
-
}).from(gaDailyTotals).where(
|
|
31968
|
+
}).from(gaDailyTotals).where(and30(
|
|
31848
31969
|
eq34(gaDailyTotals.projectId, project.id),
|
|
31849
31970
|
or5(
|
|
31850
31971
|
sql11`${gaDailyTotals.engagementRate} is not null`,
|
|
@@ -31854,9 +31975,9 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
31854
31975
|
const gscAnchor = db.select({ date: sql11`max(${gscDailyTotals.date})` }).from(gscDailyTotals).where(eq34(gscDailyTotals.projectId, project.id)).get()?.date ?? null;
|
|
31855
31976
|
const gscPeriods = gscAnchor ? buildPeriods(gscAnchor, days) : [];
|
|
31856
31977
|
const gscStartDate = gscPeriods[0]?.startDate;
|
|
31857
|
-
const propertyRows = gscStartDate ? db.select().from(gscDailyTotals).where(
|
|
31858
|
-
const queryRows2 = gscStartDate ? db.select().from(gscQueryDailyTotals).where(
|
|
31859
|
-
const rawPageRows = gscStartDate ? db.select().from(gscSearchData).where(
|
|
31978
|
+
const propertyRows = gscStartDate ? db.select().from(gscDailyTotals).where(and30(eq34(gscDailyTotals.projectId, project.id), gte9(gscDailyTotals.date, gscStartDate), lte7(gscDailyTotals.date, gscAnchor))).all() : [];
|
|
31979
|
+
const queryRows2 = gscStartDate ? db.select().from(gscQueryDailyTotals).where(and30(eq34(gscQueryDailyTotals.projectId, project.id), gte9(gscQueryDailyTotals.date, gscStartDate), lte7(gscQueryDailyTotals.date, gscAnchor))).all() : [];
|
|
31980
|
+
const rawPageRows = gscStartDate ? db.select().from(gscSearchData).where(and30(eq34(gscSearchData.projectId, project.id), gte9(gscSearchData.date, gscStartDate), lte7(gscSearchData.date, gscAnchor))).all() : [];
|
|
31860
31981
|
const state = db.select().from(gaMeasurementSyncStates).where(eq34(gaMeasurementSyncStates.projectId, project.id)).get();
|
|
31861
31982
|
const acquisition = acquisitionRows.filter((row) => {
|
|
31862
31983
|
const landingPage = normalizeLandingPage(row.landingPageNormalized ?? row.landingPage);
|
|
@@ -32191,7 +32312,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
32191
32312
|
startDate: sql12`min(${gaAcquisitionDaily.date})`,
|
|
32192
32313
|
endDate: sql12`max(${gaAcquisitionDaily.date})`,
|
|
32193
32314
|
observedDays: sql12`count(distinct ${gaAcquisitionDaily.date})`
|
|
32194
|
-
}).from(gaAcquisitionDaily).where(
|
|
32315
|
+
}).from(gaAcquisitionDaily).where(and31(
|
|
32195
32316
|
eq35(gaAcquisitionDaily.projectId, project.id),
|
|
32196
32317
|
or6(...normalizedMarketingHosts.map((candidate) => sql12`lower(trim(${gaAcquisitionDaily.hostName})) = ${candidate} or lower(trim(${gaAcquisitionDaily.hostName})) like ${`%.${candidate}`}`))
|
|
32197
32318
|
)).get()) : null;
|
|
@@ -32206,17 +32327,17 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
32206
32327
|
const startDate = gscStartDate ?? gaStartDate ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
32207
32328
|
const endDate = gscEndDate ?? gaEndDate ?? startDate;
|
|
32208
32329
|
const isInWindow = (date) => inRange(date, startDate, endDate);
|
|
32209
|
-
const gscRows = gscStartDate && gscEndDate ? db.select().from(gscDailyTotals).where(
|
|
32330
|
+
const gscRows = gscStartDate && gscEndDate ? db.select().from(gscDailyTotals).where(and31(
|
|
32210
32331
|
eq35(gscDailyTotals.projectId, project.id),
|
|
32211
32332
|
gte10(gscDailyTotals.date, gscStartDate),
|
|
32212
32333
|
lte8(gscDailyTotals.date, gscEndDate)
|
|
32213
32334
|
)).all() : [];
|
|
32214
|
-
const gaRows = gaStartDate && gaEndDate ? db.select().from(gaTrafficSnapshots).where(
|
|
32335
|
+
const gaRows = gaStartDate && gaEndDate ? db.select().from(gaTrafficSnapshots).where(and31(
|
|
32215
32336
|
eq35(gaTrafficSnapshots.projectId, project.id),
|
|
32216
32337
|
gte10(gaTrafficSnapshots.date, gaStartDate),
|
|
32217
32338
|
lte8(gaTrafficSnapshots.date, gaEndDate)
|
|
32218
32339
|
)).all() : [];
|
|
32219
|
-
const nativeAcquisitionRows = nativeAcquisitionActive && nativeStartDate && nativeEndDate ? db.select().from(gaAcquisitionDaily).where(
|
|
32340
|
+
const nativeAcquisitionRows = nativeAcquisitionActive && nativeStartDate && nativeEndDate ? db.select().from(gaAcquisitionDaily).where(and31(
|
|
32220
32341
|
eq35(gaAcquisitionDaily.projectId, project.id),
|
|
32221
32342
|
gte10(gaAcquisitionDaily.date, nativeStartDate),
|
|
32222
32343
|
lte8(gaAcquisitionDaily.date, nativeEndDate)
|
|
@@ -32255,7 +32376,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
32255
32376
|
project.canonicalDomain,
|
|
32256
32377
|
[project.displayName, ...project.aliases]
|
|
32257
32378
|
);
|
|
32258
|
-
const namedRows = db.select().from(gscQueryDailyTotals).where(
|
|
32379
|
+
const namedRows = db.select().from(gscQueryDailyTotals).where(and31(
|
|
32259
32380
|
eq35(gscQueryDailyTotals.projectId, project.id),
|
|
32260
32381
|
gte10(gscQueryDailyTotals.date, startDate),
|
|
32261
32382
|
lte8(gscQueryDailyTotals.date, endDate)
|
|
@@ -32284,7 +32405,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
32284
32405
|
totals: sumSearchRows(gscRows.filter((row) => inRange(row.date, cohort.startDate, cohort.endDate)))
|
|
32285
32406
|
}))
|
|
32286
32407
|
} : null;
|
|
32287
|
-
const pageSearchRows = db.select().from(gscSearchData).where(
|
|
32408
|
+
const pageSearchRows = db.select().from(gscSearchData).where(and31(eq35(gscSearchData.projectId, project.id), gte10(gscSearchData.date, startDate), lte8(gscSearchData.date, endDate))).all().filter((row) => pageMatchesMarketingHost(row.page, marketingHosts));
|
|
32288
32409
|
const gaWindow = gaStartDate && gaEndDate ? gaRows.filter((row) => inRange(row.date, gaStartDate, gaEndDate)) : [];
|
|
32289
32410
|
const legacyGaCohorts = gaCohorts.map((cohort) => ({
|
|
32290
32411
|
...cohort,
|
|
@@ -32311,7 +32432,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
32311
32432
|
}))
|
|
32312
32433
|
};
|
|
32313
32434
|
}
|
|
32314
|
-
const allGaAiRows = db.select().from(gaAiReferrals).where(
|
|
32435
|
+
const allGaAiRows = db.select().from(gaAiReferrals).where(and31(eq35(gaAiReferrals.projectId, project.id), gte10(gaAiReferrals.date, gaStartDate ?? startDate), lte8(gaAiReferrals.date, gaEndDate ?? endDate))).all().filter((row) => row.sourceDimension === "session");
|
|
32315
32436
|
const aiRows = gaStartDate && gaEndDate ? allGaAiRows.filter((row) => inRange(row.date, gaStartDate, gaEndDate)) : [];
|
|
32316
32437
|
const gaAiReferralSummary = allGaAiRows.length ? {
|
|
32317
32438
|
paidSessions: aiRows.filter((row) => row.trafficClass === AiReferralTrafficClasses.paid).reduce((count4, row) => count4 + row.sessions, 0),
|
|
@@ -32320,9 +32441,9 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
32320
32441
|
const serverSources = db.select().from(trafficSources).where(eq35(trafficSources.projectId, project.id)).all();
|
|
32321
32442
|
const serverStart = `${startDate}T00:00:00`;
|
|
32322
32443
|
const serverEnd = `${endDate}T23:59:59.999Z`;
|
|
32323
|
-
const allCrawlers = db.select().from(crawlerEventsHourly).where(
|
|
32324
|
-
const allFetches = db.select().from(aiUserFetchEventsHourly).where(
|
|
32325
|
-
const allReferrals = db.select().from(aiReferralEventsHourly).where(
|
|
32444
|
+
const allCrawlers = db.select().from(crawlerEventsHourly).where(and31(eq35(crawlerEventsHourly.projectId, project.id), gte10(crawlerEventsHourly.tsHour, serverStart), lte8(crawlerEventsHourly.tsHour, serverEnd))).all();
|
|
32445
|
+
const allFetches = db.select().from(aiUserFetchEventsHourly).where(and31(eq35(aiUserFetchEventsHourly.projectId, project.id), gte10(aiUserFetchEventsHourly.tsHour, serverStart), lte8(aiUserFetchEventsHourly.tsHour, serverEnd))).all();
|
|
32446
|
+
const allReferrals = db.select().from(aiReferralEventsHourly).where(and31(eq35(aiReferralEventsHourly.projectId, project.id), countableReferralCondition(), gte10(aiReferralEventsHourly.tsHour, serverStart), lte8(aiReferralEventsHourly.tsHour, serverEnd))).all();
|
|
32326
32447
|
const [serverCoverageRow] = db.all(sql12`
|
|
32327
32448
|
select
|
|
32328
32449
|
min(day) as startDate,
|
|
@@ -32350,7 +32471,7 @@ function buildOrganicEvidence(db, projectName, periodDays) {
|
|
|
32350
32471
|
const referrals = allReferrals.filter((row) => serverInWindow(row.tsHour));
|
|
32351
32472
|
const serverSummary = summarizeServer(crawlers, fetches, referrals);
|
|
32352
32473
|
const server = serverSources.length ? serverSummary.summary : null;
|
|
32353
|
-
const latest = db.select().from(runs).where(
|
|
32474
|
+
const latest = db.select().from(runs).where(and31(
|
|
32354
32475
|
eq35(runs.projectId, project.id),
|
|
32355
32476
|
eq35(runs.kind, RunKinds["answer-visibility"]),
|
|
32356
32477
|
eq35(runs.status, RunStatuses.completed),
|
|
@@ -32595,7 +32716,7 @@ async function organicEvidenceRoutes(app) {
|
|
|
32595
32716
|
}
|
|
32596
32717
|
|
|
32597
32718
|
// ../api-routes/src/citations.ts
|
|
32598
|
-
import { and as
|
|
32719
|
+
import { and as and32, eq as eq36, inArray as inArray16 } from "drizzle-orm";
|
|
32599
32720
|
async function citationRoutes(app) {
|
|
32600
32721
|
app.get("/projects/:name/citations/visibility", async (request, reply) => {
|
|
32601
32722
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -32604,7 +32725,7 @@ async function citationRoutes(app) {
|
|
|
32604
32725
|
if (projectQueries.length === 0) {
|
|
32605
32726
|
return reply.send(emptyCitationVisibility("no-queries"));
|
|
32606
32727
|
}
|
|
32607
|
-
const projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
|
|
32728
|
+
const projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and32(eq36(runs.projectId, project.id), notProbeRun())).all();
|
|
32608
32729
|
if (projectRuns.length === 0) {
|
|
32609
32730
|
return reply.send(emptyCitationVisibility("no-runs-yet"));
|
|
32610
32731
|
}
|
|
@@ -32756,7 +32877,7 @@ function computeCitationVisibility(input) {
|
|
|
32756
32877
|
}
|
|
32757
32878
|
|
|
32758
32879
|
// ../api-routes/src/visibility-stats.ts
|
|
32759
|
-
import { and as
|
|
32880
|
+
import { and as and33, desc as desc16, eq as eq37, inArray as inArray17 } from "drizzle-orm";
|
|
32760
32881
|
|
|
32761
32882
|
// ../api-routes/src/visibility-compare.ts
|
|
32762
32883
|
var VISIBILITY_COMPARE_MIN_RUNS = 5;
|
|
@@ -33183,7 +33304,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
33183
33304
|
lastRuns = n;
|
|
33184
33305
|
}
|
|
33185
33306
|
const projectQueries = app.db.select({ id: queries.id, query: queries.query }).from(queries).where(eq37(queries.projectId, project.id)).all();
|
|
33186
|
-
let projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(
|
|
33307
|
+
let projectRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(and33(eq37(runs.projectId, project.id), eq37(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc16(runs.createdAt)).all().filter((r) => r.status === RunStatuses.completed || r.status === RunStatuses.partial);
|
|
33187
33308
|
if (sinceMs !== null) projectRuns = projectRuns.filter((r) => Date.parse(r.createdAt) >= sinceMs);
|
|
33188
33309
|
if (untilMs !== null) projectRuns = projectRuns.filter((r) => Date.parse(r.createdAt) <= untilMs);
|
|
33189
33310
|
if (lastRuns !== null) projectRuns = projectRuns.slice(0, lastRuns);
|
|
@@ -33266,7 +33387,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
33266
33387
|
const loadMonth = (bounds) => {
|
|
33267
33388
|
const sinceMs = Date.parse(bounds.since);
|
|
33268
33389
|
const untilMs = Date.parse(bounds.until);
|
|
33269
|
-
const monthRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(
|
|
33390
|
+
const monthRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt, status: runs.status }).from(runs).where(and33(eq37(runs.projectId, project.id), eq37(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).all().filter(
|
|
33270
33391
|
(r) => (r.status === RunStatuses.completed || r.status === RunStatuses.partial) && Date.parse(r.createdAt) >= sinceMs && Date.parse(r.createdAt) <= untilMs
|
|
33271
33392
|
);
|
|
33272
33393
|
const runIds = monthRuns.map((r) => r.id);
|
|
@@ -33297,7 +33418,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
33297
33418
|
}
|
|
33298
33419
|
|
|
33299
33420
|
// ../api-routes/src/results-export.ts
|
|
33300
|
-
import { and as
|
|
33421
|
+
import { and as and34, asc as asc5, eq as eq38, gte as gte11, lte as lte9 } from "drizzle-orm";
|
|
33301
33422
|
var CSV_COLUMNS = [
|
|
33302
33423
|
"export_schema_version",
|
|
33303
33424
|
"project_id",
|
|
@@ -33467,7 +33588,7 @@ async function resultsExportRoutes(app) {
|
|
|
33467
33588
|
recommendedCompetitors: querySnapshots.recommendedCompetitors,
|
|
33468
33589
|
answerText: querySnapshots.answerText,
|
|
33469
33590
|
rawResponse: querySnapshots.rawResponse
|
|
33470
|
-
}).from(querySnapshots).innerJoin(runs, eq38(querySnapshots.runId, runs.id)).leftJoin(queries, eq38(querySnapshots.queryId, queries.id)).where(
|
|
33591
|
+
}).from(querySnapshots).innerJoin(runs, eq38(querySnapshots.runId, runs.id)).leftJoin(queries, eq38(querySnapshots.queryId, queries.id)).where(and34(...conditions)).orderBy(asc5(runs.createdAt), asc5(runs.id), asc5(querySnapshots.createdAt), asc5(querySnapshots.id)).all();
|
|
33471
33592
|
const records = rows.map((row) => {
|
|
33472
33593
|
const evidence = readEvidence(row.rawResponse);
|
|
33473
33594
|
const citationState = row.citationState === CitationStates.cited ? CitationStates.cited : CitationStates["not-cited"];
|
|
@@ -33535,7 +33656,7 @@ async function resultsExportRoutes(app) {
|
|
|
33535
33656
|
}
|
|
33536
33657
|
|
|
33537
33658
|
// ../api-routes/src/composites.ts
|
|
33538
|
-
import { eq as eq39, and as
|
|
33659
|
+
import { eq as eq39, and as and35, desc as desc17, sql as sql13, like as like2, or as or7, inArray as inArray18 } from "drizzle-orm";
|
|
33539
33660
|
var TOP_INSIGHT_LIMIT = 5;
|
|
33540
33661
|
var SEARCH_HIT_HARD_LIMIT = 50;
|
|
33541
33662
|
var SEARCH_SNIPPET_RADIUS = 80;
|
|
@@ -33555,7 +33676,7 @@ async function compositeRoutes(app) {
|
|
|
33555
33676
|
const project = resolveProject(app.db, request.params.name);
|
|
33556
33677
|
const filterLocation = (request.query.location ?? "").trim() || null;
|
|
33557
33678
|
const sinceIso = parseSinceFilter(request.query.since);
|
|
33558
|
-
const allRunsRaw = app.db.select().from(runs).where(
|
|
33679
|
+
const allRunsRaw = app.db.select().from(runs).where(and35(eq39(runs.projectId, project.id), notProbeRun())).orderBy(desc17(runs.createdAt), desc17(runs.id)).all();
|
|
33559
33680
|
const allRuns = allRunsRaw.filter((r) => runMatchesFilters(r, filterLocation, sinceIso));
|
|
33560
33681
|
const totalRuns = allRuns.length;
|
|
33561
33682
|
const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
|
|
@@ -33730,7 +33851,7 @@ async function compositeRoutes(app) {
|
|
|
33730
33851
|
rawResponse: querySnapshots.rawResponse,
|
|
33731
33852
|
createdAt: querySnapshots.createdAt
|
|
33732
33853
|
}).from(querySnapshots).innerJoin(queries, eq39(querySnapshots.queryId, queries.id)).where(
|
|
33733
|
-
|
|
33854
|
+
and35(
|
|
33734
33855
|
eq39(queries.projectId, project.id),
|
|
33735
33856
|
or7(
|
|
33736
33857
|
sql13`${querySnapshots.answerText} LIKE ${pattern} ESCAPE '\\'`,
|
|
@@ -33742,7 +33863,7 @@ async function compositeRoutes(app) {
|
|
|
33742
33863
|
)
|
|
33743
33864
|
).orderBy(desc17(querySnapshots.createdAt)).limit(limit + 1).all());
|
|
33744
33865
|
const insightMatches = app.db.select().from(insights).where(
|
|
33745
|
-
|
|
33866
|
+
and35(
|
|
33746
33867
|
eq39(insights.projectId, project.id),
|
|
33747
33868
|
or7(
|
|
33748
33869
|
like2(insights.title, pattern),
|
|
@@ -33977,7 +34098,7 @@ function buildSuggestedQueriesFromGsc(app, projectId, trackedQueries) {
|
|
|
33977
34098
|
// NULLIF guards the degenerate impressions=0 case (SQLite returns NULL,
|
|
33978
34099
|
// which the JS coerces to 0 — caught by the impression floor anyway).
|
|
33979
34100
|
avgPosition: sql13`COALESCE(SUM(${gscSearchData.position} * ${gscSearchData.impressions}) * 1.0 / NULLIF(SUM(${gscSearchData.impressions}), 0), 0)`
|
|
33980
|
-
}).from(gscSearchData).where(
|
|
34101
|
+
}).from(gscSearchData).where(and35(
|
|
33981
34102
|
eq39(gscSearchData.projectId, projectId),
|
|
33982
34103
|
sql13`${gscSearchData.date} >= ${cutoff}`,
|
|
33983
34104
|
// Same upper bound as the accurate source below. The merge picks a source
|
|
@@ -34504,6 +34625,7 @@ var SCHEMA_TABLE = {
|
|
|
34504
34625
|
RunDetailDto: runDetailDtoSchema,
|
|
34505
34626
|
RunDto: runDtoSchema,
|
|
34506
34627
|
SchedulableRunKind: schedulableRunKindSchema,
|
|
34628
|
+
CalendarRecurrence: calendarRecurrenceSchema,
|
|
34507
34629
|
ScheduleDto: scheduleDtoSchema,
|
|
34508
34630
|
SettingsDto: settingsDtoSchema,
|
|
34509
34631
|
SiteAuditLivePageHealthDto: siteAuditLivePageHealthSchema,
|
|
@@ -37252,6 +37374,7 @@ var routeCatalog = [
|
|
|
37252
37374
|
method: "put",
|
|
37253
37375
|
path: "/api/v1/projects/{name}/schedule",
|
|
37254
37376
|
summary: "Create or update a schedule",
|
|
37377
|
+
description: "Provide exactly one of preset, cron, or recurrence. Calendar recurrence repeats every N local calendar days from startDate at time in the IANA timezone; it retains the anchor across daylight-saving changes.",
|
|
37255
37378
|
tags: ["schedules"],
|
|
37256
37379
|
parameters: [nameParameter, scheduleKindQueryParameter],
|
|
37257
37380
|
requestBody: {
|
|
@@ -37264,6 +37387,7 @@ var routeCatalog = [
|
|
|
37264
37387
|
kind: { $ref: "#/components/schemas/SchedulableRunKind" },
|
|
37265
37388
|
preset: stringSchema,
|
|
37266
37389
|
cron: stringSchema,
|
|
37390
|
+
recurrence: { $ref: "#/components/schemas/CalendarRecurrence" },
|
|
37267
37391
|
timezone: stringSchema,
|
|
37268
37392
|
providers: stringArraySchema,
|
|
37269
37393
|
enabled: booleanSchema,
|
|
@@ -42078,7 +42202,7 @@ async function telemetryRoutes(app, opts) {
|
|
|
42078
42202
|
|
|
42079
42203
|
// ../api-routes/src/schedules.ts
|
|
42080
42204
|
import crypto26 from "crypto";
|
|
42081
|
-
import { and as
|
|
42205
|
+
import { and as and36, asc as asc7, eq as eq42 } from "drizzle-orm";
|
|
42082
42206
|
function parseKindParam(raw) {
|
|
42083
42207
|
if (raw === void 0 || raw === null || raw === "") return SchedulableRunKinds["answer-visibility"];
|
|
42084
42208
|
const parsed = schedulableRunKindSchema.safeParse(raw);
|
|
@@ -42106,7 +42230,7 @@ async function scheduleRoutes(app, opts) {
|
|
|
42106
42230
|
});
|
|
42107
42231
|
}
|
|
42108
42232
|
const kind = parsedBody.data.kind ?? parseKindParam(request.query?.kind);
|
|
42109
|
-
const { preset, cron, timezone, providers, enabled, sourceId, expectedUpdatedAt } = parsedBody.data;
|
|
42233
|
+
const { preset, cron, recurrence, timezone, providers, enabled, sourceId, expectedUpdatedAt } = parsedBody.data;
|
|
42110
42234
|
if (kind === SchedulableRunKinds["traffic-sync"]) {
|
|
42111
42235
|
if (!sourceId) {
|
|
42112
42236
|
throw validationError('"sourceId" is required when kind is "traffic-sync"');
|
|
@@ -42141,7 +42265,9 @@ async function scheduleRoutes(app, opts) {
|
|
|
42141
42265
|
throw validationError(`Invalid timezone: ${timezone}`);
|
|
42142
42266
|
}
|
|
42143
42267
|
let cronExpr;
|
|
42144
|
-
if (
|
|
42268
|
+
if (recurrence) {
|
|
42269
|
+
cronExpr = "";
|
|
42270
|
+
} else if (preset) {
|
|
42145
42271
|
try {
|
|
42146
42272
|
cronExpr = resolvePreset(preset);
|
|
42147
42273
|
} catch (err) {
|
|
@@ -42155,8 +42281,12 @@ async function scheduleRoutes(app, opts) {
|
|
|
42155
42281
|
}
|
|
42156
42282
|
}
|
|
42157
42283
|
const enabledBool = enabled !== false;
|
|
42284
|
+
const nextRunAt = enabledBool ? nextRunFromSchedule({ cronExpr, timezone, recurrence }) : null;
|
|
42285
|
+
if (recurrence && enabledBool && !nextRunAt) {
|
|
42286
|
+
throw validationError("Calendar recurrence has no valid future occurrence");
|
|
42287
|
+
}
|
|
42158
42288
|
const mutation = app.db.transaction((tx) => {
|
|
42159
|
-
const existing = tx.select().from(schedules).where(
|
|
42289
|
+
const existing = tx.select().from(schedules).where(and36(eq42(schedules.projectId, project.id), eq42(schedules.kind, kind))).get();
|
|
42160
42290
|
const actualUpdatedAt = existing?.updatedAt ?? null;
|
|
42161
42291
|
if (expectedUpdatedAt !== void 0 && expectedUpdatedAt !== actualUpdatedAt) {
|
|
42162
42292
|
throw scheduleVersionConflict(expectedUpdatedAt, actualUpdatedAt);
|
|
@@ -42165,6 +42295,8 @@ async function scheduleRoutes(app, opts) {
|
|
|
42165
42295
|
const scheduleId = existing?.id ?? crypto26.randomUUID();
|
|
42166
42296
|
const values = {
|
|
42167
42297
|
cronExpr,
|
|
42298
|
+
recurrence: recurrence ?? null,
|
|
42299
|
+
nextRunAt,
|
|
42168
42300
|
preset: preset ?? null,
|
|
42169
42301
|
timezone,
|
|
42170
42302
|
providers: providers ?? [],
|
|
@@ -42174,7 +42306,7 @@ async function scheduleRoutes(app, opts) {
|
|
|
42174
42306
|
};
|
|
42175
42307
|
if (existing) {
|
|
42176
42308
|
const changed = tx.update(schedules).set(values).where(
|
|
42177
|
-
expectedUpdatedAt === void 0 ? eq42(schedules.id, existing.id) :
|
|
42309
|
+
expectedUpdatedAt === void 0 ? eq42(schedules.id, existing.id) : and36(eq42(schedules.id, existing.id), eq42(schedules.updatedAt, expectedUpdatedAt ?? existing.updatedAt))
|
|
42178
42310
|
).run();
|
|
42179
42311
|
if (changed.changes !== 1) {
|
|
42180
42312
|
const actual = tx.select().from(schedules).where(eq42(schedules.id, existing.id)).get();
|
|
@@ -42190,7 +42322,7 @@ async function scheduleRoutes(app, opts) {
|
|
|
42190
42322
|
});
|
|
42191
42323
|
const inserted = expectedUpdatedAt === null ? insert.onConflictDoNothing().run() : insert.run();
|
|
42192
42324
|
if (expectedUpdatedAt === null && inserted.changes !== 1) {
|
|
42193
|
-
const actual = tx.select().from(schedules).where(
|
|
42325
|
+
const actual = tx.select().from(schedules).where(and36(eq42(schedules.projectId, project.id), eq42(schedules.kind, kind))).get();
|
|
42194
42326
|
throw scheduleVersionConflict(null, actual?.updatedAt ?? null);
|
|
42195
42327
|
}
|
|
42196
42328
|
}
|
|
@@ -42199,14 +42331,14 @@ async function scheduleRoutes(app, opts) {
|
|
|
42199
42331
|
actor: "api",
|
|
42200
42332
|
action: existing ? "schedule.updated" : "schedule.created",
|
|
42201
42333
|
entityType: "schedule",
|
|
42202
|
-
diff: { kind, cronExpr, preset, timezone, providers, sourceId }
|
|
42334
|
+
diff: { kind, cronExpr, preset, recurrence, timezone, providers, sourceId }
|
|
42203
42335
|
});
|
|
42204
42336
|
return {
|
|
42205
42337
|
existed: existing !== void 0
|
|
42206
42338
|
};
|
|
42207
42339
|
});
|
|
42208
42340
|
opts.onScheduleUpdated?.("upsert", project.id, kind);
|
|
42209
|
-
const schedule = app.db.select().from(schedules).where(
|
|
42341
|
+
const schedule = app.db.select().from(schedules).where(and36(eq42(schedules.projectId, project.id), eq42(schedules.kind, kind))).get();
|
|
42210
42342
|
return reply.status(mutation.existed ? 200 : 201).send(formatSchedule(schedule));
|
|
42211
42343
|
});
|
|
42212
42344
|
app.get("/projects/:name/schedules", async (request, reply) => {
|
|
@@ -42217,7 +42349,7 @@ async function scheduleRoutes(app, opts) {
|
|
|
42217
42349
|
app.get("/projects/:name/schedule", async (request, reply) => {
|
|
42218
42350
|
const project = resolveProject(app.db, request.params.name);
|
|
42219
42351
|
const kind = parseKindParam(request.query?.kind);
|
|
42220
|
-
const schedule = app.db.select().from(schedules).where(
|
|
42352
|
+
const schedule = app.db.select().from(schedules).where(and36(eq42(schedules.projectId, project.id), eq42(schedules.kind, kind))).get();
|
|
42221
42353
|
if (!schedule) {
|
|
42222
42354
|
throw notFound("Schedule", `${request.params.name} (kind=${kind})`);
|
|
42223
42355
|
}
|
|
@@ -42228,7 +42360,7 @@ async function scheduleRoutes(app, opts) {
|
|
|
42228
42360
|
const kind = parseKindParam(request.query?.kind);
|
|
42229
42361
|
const expectedUpdatedAt = parseExpectedUpdatedAtParam(request.query?.expectedUpdatedAt);
|
|
42230
42362
|
app.db.transaction((tx) => {
|
|
42231
|
-
const schedule = tx.select().from(schedules).where(
|
|
42363
|
+
const schedule = tx.select().from(schedules).where(and36(eq42(schedules.projectId, project.id), eq42(schedules.kind, kind))).get();
|
|
42232
42364
|
if (!schedule) {
|
|
42233
42365
|
if (expectedUpdatedAt !== void 0) throw scheduleVersionConflict(expectedUpdatedAt, null);
|
|
42234
42366
|
throw notFound("Schedule", `${request.params.name} (kind=${kind})`);
|
|
@@ -42237,7 +42369,7 @@ async function scheduleRoutes(app, opts) {
|
|
|
42237
42369
|
throw scheduleVersionConflict(expectedUpdatedAt, schedule.updatedAt);
|
|
42238
42370
|
}
|
|
42239
42371
|
const deleted = tx.delete(schedules).where(
|
|
42240
|
-
expectedUpdatedAt === void 0 ? eq42(schedules.id, schedule.id) :
|
|
42372
|
+
expectedUpdatedAt === void 0 ? eq42(schedules.id, schedule.id) : and36(eq42(schedules.id, schedule.id), eq42(schedules.updatedAt, expectedUpdatedAt))
|
|
42241
42373
|
).run();
|
|
42242
42374
|
if (deleted.changes !== 1) {
|
|
42243
42375
|
const actual = tx.select().from(schedules).where(eq42(schedules.id, schedule.id)).get();
|
|
@@ -42262,6 +42394,7 @@ function formatSchedule(row) {
|
|
|
42262
42394
|
projectId: row.projectId,
|
|
42263
42395
|
kind: row.kind,
|
|
42264
42396
|
cronExpr: row.cronExpr,
|
|
42397
|
+
recurrence: row.recurrence,
|
|
42265
42398
|
preset: row.preset,
|
|
42266
42399
|
timezone: row.timezone,
|
|
42267
42400
|
enabled: row.enabled,
|
|
@@ -42609,7 +42742,7 @@ function formatNotification(row) {
|
|
|
42609
42742
|
|
|
42610
42743
|
// ../api-routes/src/google.ts
|
|
42611
42744
|
import crypto32 from "crypto";
|
|
42612
|
-
import { eq as eq44, and as
|
|
42745
|
+
import { eq as eq44, and as and37, desc as desc19, sql as sql14, inArray as inArray19 } from "drizzle-orm";
|
|
42613
42746
|
|
|
42614
42747
|
// ../api-routes/src/gsc-period-comparison.ts
|
|
42615
42748
|
var DAY_MS = 864e5;
|
|
@@ -45050,8 +45183,8 @@ async function googleRoutes(app, opts) {
|
|
|
45050
45183
|
impressions: [desc19(gscSearchData.impressions), desc19(gscSearchData.date), gscSearchData.query],
|
|
45051
45184
|
date: [desc19(gscSearchData.date), desc19(gscSearchData.clicks), gscSearchData.query]
|
|
45052
45185
|
}[orderBy];
|
|
45053
|
-
const rows = app.db.select().from(gscSearchData).where(
|
|
45054
|
-
const totalMatching = app.db.select({ total: sql14`COUNT(*)` }).from(gscSearchData).where(
|
|
45186
|
+
const rows = app.db.select().from(gscSearchData).where(and37(...conditions)).orderBy(...orderColumns).limit(limitVal).offset(offsetVal).all();
|
|
45187
|
+
const totalMatching = app.db.select({ total: sql14`COUNT(*)` }).from(gscSearchData).where(and37(...conditions)).get()?.total ?? 0;
|
|
45055
45188
|
const latestAvailableDate = app.db.select({ latest: sql14`MAX(${gscSearchData.date})` }).from(gscSearchData).where(eq44(gscSearchData.projectId, project.id)).get()?.latest ?? null;
|
|
45056
45189
|
return {
|
|
45057
45190
|
rows: rows.map((r) => ({
|
|
@@ -45102,7 +45235,7 @@ async function googleRoutes(app, opts) {
|
|
|
45102
45235
|
date: gscSearchData.date,
|
|
45103
45236
|
clicks: sql14`COALESCE(SUM(${gscSearchData.clicks}), 0)`,
|
|
45104
45237
|
impressions: sql14`COALESCE(SUM(${gscSearchData.impressions}), 0)`
|
|
45105
|
-
}).from(gscSearchData).where(
|
|
45238
|
+
}).from(gscSearchData).where(and37(...conditions)).groupBy(gscSearchData.date).orderBy(gscSearchData.date).all();
|
|
45106
45239
|
const propertyDates = new Set(dailyTotals.map((d) => d.date));
|
|
45107
45240
|
const comparisonDaily = mergeGscDailyTotalsWithFallback(
|
|
45108
45241
|
dailyTotals,
|
|
@@ -45207,7 +45340,7 @@ async function googleRoutes(app, opts) {
|
|
|
45207
45340
|
page: gscSearchData.page,
|
|
45208
45341
|
clicks: sql14`COALESCE(SUM(${gscSearchData.clicks}), 0)`,
|
|
45209
45342
|
impressions: sql14`COALESCE(SUM(${gscSearchData.impressions}), 0)`
|
|
45210
|
-
}).from(gscSearchData).where(
|
|
45343
|
+
}).from(gscSearchData).where(and37(...conditions)).groupBy(gscSearchData.page).orderBy(desc19(sql14`SUM(${gscSearchData.clicks})`), desc19(sql14`SUM(${gscSearchData.impressions})`)).limit(limitVal).all();
|
|
45211
45344
|
const windowStart = startDate ?? cutoffDate ?? "";
|
|
45212
45345
|
const windowEnd = endDate ?? resolvedWindow.endDate ?? "9999-12-31";
|
|
45213
45346
|
const dailyTotals = readGscDailyTotals(app.db, project.id, windowStart, windowEnd);
|
|
@@ -45216,7 +45349,7 @@ async function googleRoutes(app, opts) {
|
|
|
45216
45349
|
const rankedSpan = app.db.select({
|
|
45217
45350
|
first: sql14`MIN(${gscSearchData.date})`,
|
|
45218
45351
|
last: sql14`MAX(${gscSearchData.date})`
|
|
45219
|
-
}).from(gscSearchData).where(
|
|
45352
|
+
}).from(gscSearchData).where(and37(...conditions)).get();
|
|
45220
45353
|
const coveredFrom = dailyTotals.length > 0 ? dailyTotals[0].date : null;
|
|
45221
45354
|
const coveredThrough = dailyTotals.length > 0 ? dailyTotals[dailyTotals.length - 1].date : null;
|
|
45222
45355
|
const totalsComplete = Boolean(
|
|
@@ -45310,7 +45443,7 @@ async function googleRoutes(app, opts) {
|
|
|
45310
45443
|
const { url, limit } = request.query;
|
|
45311
45444
|
const conditions = [eq44(gscUrlInspections.projectId, project.id)];
|
|
45312
45445
|
if (url) conditions.push(eq44(gscUrlInspections.url, url));
|
|
45313
|
-
const rows = app.db.select().from(gscUrlInspections).where(
|
|
45446
|
+
const rows = app.db.select().from(gscUrlInspections).where(and37(...conditions)).orderBy(desc19(gscUrlInspections.inspectedAt)).limit(parseInt(limit ?? "100", 10)).all();
|
|
45314
45447
|
return rows.map((r) => ({
|
|
45315
45448
|
id: r.id,
|
|
45316
45449
|
url: r.url,
|
|
@@ -45876,7 +46009,7 @@ async function googleRoutes(app, opts) {
|
|
|
45876
46009
|
app.db.transaction((tx) => {
|
|
45877
46010
|
if (switching) clearGbpProjectData(tx, project.id);
|
|
45878
46011
|
for (const remote of remoteLocations) {
|
|
45879
|
-
const existing = tx.select().from(gbpLocations).where(
|
|
46012
|
+
const existing = tx.select().from(gbpLocations).where(and37(eq44(gbpLocations.projectId, project.id), eq44(gbpLocations.locationName, remote.name))).get();
|
|
45880
46013
|
const profile = buildLocationProfileFields(remote);
|
|
45881
46014
|
if (existing) {
|
|
45882
46015
|
tx.update(gbpLocations).set({
|
|
@@ -45974,7 +46107,7 @@ async function googleRoutes(app, opts) {
|
|
|
45974
46107
|
throw validationError(parsed.error.issues[0]?.message ?? "Invalid selection request");
|
|
45975
46108
|
}
|
|
45976
46109
|
const { selected } = parsed.data;
|
|
45977
|
-
const existing = app.db.select().from(gbpLocations).where(
|
|
46110
|
+
const existing = app.db.select().from(gbpLocations).where(and37(eq44(gbpLocations.projectId, project.id), eq44(gbpLocations.locationName, locationName))).get();
|
|
45978
46111
|
if (!existing) throw notFound("GBP location", locationName);
|
|
45979
46112
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
45980
46113
|
app.db.transaction((tx) => {
|
|
@@ -46034,7 +46167,7 @@ async function googleRoutes(app, opts) {
|
|
|
46034
46167
|
const conditions = [eq44(gbpDailyMetrics.projectId, project.id)];
|
|
46035
46168
|
if (request.query.locationName) conditions.push(eq44(gbpDailyMetrics.locationName, request.query.locationName));
|
|
46036
46169
|
if (request.query.metric) conditions.push(eq44(gbpDailyMetrics.metric, request.query.metric));
|
|
46037
|
-
const rows = app.db.select().from(gbpDailyMetrics).where(
|
|
46170
|
+
const rows = app.db.select().from(gbpDailyMetrics).where(and37(...conditions)).orderBy(desc19(gbpDailyMetrics.date)).all();
|
|
46038
46171
|
return {
|
|
46039
46172
|
metrics: rows.map((r) => ({ locationName: r.locationName, date: r.date, metric: r.metric, value: r.value })),
|
|
46040
46173
|
total: rows.length
|
|
@@ -46044,7 +46177,7 @@ async function googleRoutes(app, opts) {
|
|
|
46044
46177
|
const project = resolveProject(app.db, request.params.name);
|
|
46045
46178
|
const conditions = [eq44(gbpKeywordImpressions.projectId, project.id)];
|
|
46046
46179
|
if (request.query.locationName) conditions.push(eq44(gbpKeywordImpressions.locationName, request.query.locationName));
|
|
46047
|
-
const rows = app.db.select().from(gbpKeywordImpressions).where(
|
|
46180
|
+
const rows = app.db.select().from(gbpKeywordImpressions).where(and37(...conditions)).all();
|
|
46048
46181
|
rows.sort((a, b) => (b.valueCount ?? -1) - (a.valueCount ?? -1));
|
|
46049
46182
|
const thresholded = rows.filter((r) => r.valueThreshold !== null).length;
|
|
46050
46183
|
return {
|
|
@@ -46064,7 +46197,7 @@ async function googleRoutes(app, opts) {
|
|
|
46064
46197
|
const project = resolveProject(app.db, request.params.name);
|
|
46065
46198
|
const conditions = [eq44(gbpPlaceActions.projectId, project.id)];
|
|
46066
46199
|
if (request.query.locationName) conditions.push(eq44(gbpPlaceActions.locationName, request.query.locationName));
|
|
46067
|
-
const rows = app.db.select().from(gbpPlaceActions).where(
|
|
46200
|
+
const rows = app.db.select().from(gbpPlaceActions).where(and37(...conditions)).all();
|
|
46068
46201
|
return {
|
|
46069
46202
|
placeActions: rows.map((r) => ({
|
|
46070
46203
|
locationName: r.locationName,
|
|
@@ -46081,7 +46214,7 @@ async function googleRoutes(app, opts) {
|
|
|
46081
46214
|
const project = resolveProject(app.db, request.params.name);
|
|
46082
46215
|
const conditions = [eq44(gbpLodgingSnapshots.projectId, project.id)];
|
|
46083
46216
|
if (request.query.locationName) conditions.push(eq44(gbpLodgingSnapshots.locationName, request.query.locationName));
|
|
46084
|
-
const rows = app.db.select().from(gbpLodgingSnapshots).where(
|
|
46217
|
+
const rows = app.db.select().from(gbpLodgingSnapshots).where(and37(...conditions)).orderBy(desc19(gbpLodgingSnapshots.syncedAt)).all();
|
|
46085
46218
|
const latestByLocation = /* @__PURE__ */ new Map();
|
|
46086
46219
|
for (const row of rows) {
|
|
46087
46220
|
if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
|
|
@@ -46098,7 +46231,7 @@ async function googleRoutes(app, opts) {
|
|
|
46098
46231
|
const project = resolveProject(app.db, request.params.name);
|
|
46099
46232
|
const conditions = [eq44(gbpAttributesSnapshots.projectId, project.id)];
|
|
46100
46233
|
if (request.query.locationName) conditions.push(eq44(gbpAttributesSnapshots.locationName, request.query.locationName));
|
|
46101
|
-
const rows = app.db.select().from(gbpAttributesSnapshots).where(
|
|
46234
|
+
const rows = app.db.select().from(gbpAttributesSnapshots).where(and37(...conditions)).orderBy(desc19(gbpAttributesSnapshots.syncedAt)).all();
|
|
46102
46235
|
const latestByLocation = /* @__PURE__ */ new Map();
|
|
46103
46236
|
for (const row of rows) {
|
|
46104
46237
|
if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
|
|
@@ -46118,7 +46251,7 @@ async function googleRoutes(app, opts) {
|
|
|
46118
46251
|
const project = resolveProject(app.db, request.params.name);
|
|
46119
46252
|
const conditions = [eq44(gbpPlaceDetails.projectId, project.id)];
|
|
46120
46253
|
if (request.query.locationName) conditions.push(eq44(gbpPlaceDetails.locationName, request.query.locationName));
|
|
46121
|
-
const rows = app.db.select().from(gbpPlaceDetails).where(
|
|
46254
|
+
const rows = app.db.select().from(gbpPlaceDetails).where(and37(...conditions)).orderBy(desc19(gbpPlaceDetails.syncedAt)).all();
|
|
46122
46255
|
const latestByLocation = /* @__PURE__ */ new Map();
|
|
46123
46256
|
for (const row of rows) {
|
|
46124
46257
|
if (!latestByLocation.has(row.locationName)) latestByLocation.set(row.locationName, row);
|
|
@@ -46137,7 +46270,7 @@ async function googleRoutes(app, opts) {
|
|
|
46137
46270
|
app.get("/projects/:name/gbp/summary", async (request) => {
|
|
46138
46271
|
const project = resolveProject(app.db, request.params.name);
|
|
46139
46272
|
const locationName = request.query.locationName ?? null;
|
|
46140
|
-
const locationNames = locationName ? [locationName] : app.db.select({ n: gbpLocations.locationName }).from(gbpLocations).where(
|
|
46273
|
+
const locationNames = locationName ? [locationName] : app.db.select({ n: gbpLocations.locationName }).from(gbpLocations).where(and37(eq44(gbpLocations.projectId, project.id), eq44(gbpLocations.selected, true))).all().map((r) => r.n);
|
|
46141
46274
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
46142
46275
|
if (locationNames.length === 0) {
|
|
46143
46276
|
return buildGbpSummary({
|
|
@@ -46151,10 +46284,10 @@ async function googleRoutes(app, opts) {
|
|
|
46151
46284
|
locationProfiles: []
|
|
46152
46285
|
});
|
|
46153
46286
|
}
|
|
46154
|
-
const metricRows = app.db.select().from(gbpDailyMetrics).where(
|
|
46155
|
-
const keywordRows = app.db.select().from(gbpKeywordImpressions).where(
|
|
46156
|
-
const placeActionRows = app.db.select().from(gbpPlaceActions).where(
|
|
46157
|
-
const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(
|
|
46287
|
+
const metricRows = app.db.select().from(gbpDailyMetrics).where(and37(eq44(gbpDailyMetrics.projectId, project.id), inArray19(gbpDailyMetrics.locationName, locationNames))).all();
|
|
46288
|
+
const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and37(eq44(gbpKeywordImpressions.projectId, project.id), inArray19(gbpKeywordImpressions.locationName, locationNames))).all();
|
|
46289
|
+
const placeActionRows = app.db.select().from(gbpPlaceActions).where(and37(eq44(gbpPlaceActions.projectId, project.id), inArray19(gbpPlaceActions.locationName, locationNames))).all();
|
|
46290
|
+
const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and37(eq44(gbpLodgingSnapshots.projectId, project.id), inArray19(gbpLodgingSnapshots.locationName, locationNames))).orderBy(desc19(gbpLodgingSnapshots.syncedAt)).all();
|
|
46158
46291
|
const latestLodgingByLocation = /* @__PURE__ */ new Map();
|
|
46159
46292
|
for (const row of lodgingRows) {
|
|
46160
46293
|
if (!latestLodgingByLocation.has(row.locationName)) {
|
|
@@ -46168,7 +46301,7 @@ async function googleRoutes(app, opts) {
|
|
|
46168
46301
|
regularHours: gbpLocations.regularHours,
|
|
46169
46302
|
primaryPhone: gbpLocations.primaryPhone,
|
|
46170
46303
|
openStatus: gbpLocations.openStatus
|
|
46171
|
-
}).from(gbpLocations).where(
|
|
46304
|
+
}).from(gbpLocations).where(and37(eq44(gbpLocations.projectId, project.id), inArray19(gbpLocations.locationName, locationNames))).all();
|
|
46172
46305
|
return buildGbpSummary({
|
|
46173
46306
|
locationName,
|
|
46174
46307
|
locationCount: locationNames.length,
|
|
@@ -46184,7 +46317,7 @@ async function googleRoutes(app, opts) {
|
|
|
46184
46317
|
|
|
46185
46318
|
// ../api-routes/src/google-marketing.ts
|
|
46186
46319
|
import crypto33 from "crypto";
|
|
46187
|
-
import { and as
|
|
46320
|
+
import { and as and38, desc as desc20, eq as eq45, isNull as isNull6, lt as lt6, ne as ne6, or as or8, sql as sql15 } from "drizzle-orm";
|
|
46188
46321
|
import { z as z4 } from "zod";
|
|
46189
46322
|
var snapshotPageQuerySchema = z4.object({
|
|
46190
46323
|
limit: z4.coerce.number().int().min(1).max(GOOGLE_MARKETING_STORED_SNAPSHOT_PAGE_MAX).optional(),
|
|
@@ -46466,7 +46599,7 @@ function toGtmSnapshot(row) {
|
|
|
46466
46599
|
}
|
|
46467
46600
|
function selectedGoogleAdsCustomer(app, projectId, selection) {
|
|
46468
46601
|
if (!selection.lastCustomerSnapshotId) return null;
|
|
46469
|
-
const row = app.db.select().from(googleAdsRawSnapshots).where(
|
|
46602
|
+
const row = app.db.select().from(googleAdsRawSnapshots).where(and38(
|
|
46470
46603
|
eq45(googleAdsRawSnapshots.projectId, projectId),
|
|
46471
46604
|
eq45(googleAdsRawSnapshots.id, selection.lastCustomerSnapshotId),
|
|
46472
46605
|
eq45(googleAdsRawSnapshots.connectionId, selection.connectionId),
|
|
@@ -46489,7 +46622,7 @@ function hasMatchingGtmGraphEvidence(app, projectId, selection) {
|
|
|
46489
46622
|
eq45(gtmRawSnapshots.capturedAt, selection.lastSnapshotAt)
|
|
46490
46623
|
];
|
|
46491
46624
|
conditions.push(selection.workspaceId === null ? isNull6(gtmRawSnapshots.workspaceId) : eq45(gtmRawSnapshots.workspaceId, selection.workspaceId));
|
|
46492
|
-
const row = app.db.select().from(gtmRawSnapshots).where(
|
|
46625
|
+
const row = app.db.select().from(gtmRawSnapshots).where(and38(...conditions)).get();
|
|
46493
46626
|
if (!row) return false;
|
|
46494
46627
|
const snapshot = toGtmSnapshot(row);
|
|
46495
46628
|
return Boolean(
|
|
@@ -46609,7 +46742,7 @@ function latestGoogleAdsSnapshot(app, projectId) {
|
|
|
46609
46742
|
eq45(googleAdsRawSnapshots.kind, GoogleAdsSnapshotKinds.inventory),
|
|
46610
46743
|
eq45(googleAdsRawSnapshots.capturedAt, connection.lastInventorySnapshotAt)
|
|
46611
46744
|
];
|
|
46612
|
-
const row = app.db.select().from(googleAdsRawSnapshots).where(
|
|
46745
|
+
const row = app.db.select().from(googleAdsRawSnapshots).where(and38(...conditions)).get();
|
|
46613
46746
|
const snapshot = row ? toGoogleAdsSnapshot(row) : null;
|
|
46614
46747
|
if (!snapshot || snapshot.metadata.id !== connection.lastInventorySnapshotId || snapshot.metadata.connectionId !== connection.id || snapshot.metadata.customerId !== connection.selectedCustomerId || snapshot.metadata.capturedAt !== connection.lastInventorySnapshotAt || snapshot.payload.kind !== GoogleAdsSnapshotKinds.inventory || snapshot.payload.data.customerId !== connection.selectedCustomerId) return null;
|
|
46615
46748
|
return snapshot;
|
|
@@ -46630,7 +46763,7 @@ function latestGtmSnapshot(app, projectId) {
|
|
|
46630
46763
|
eq45(gtmRawSnapshots.kind, GtmSnapshotKinds.container)
|
|
46631
46764
|
];
|
|
46632
46765
|
conditions.push(connection.selectedWorkspaceId === null ? isNull6(gtmRawSnapshots.workspaceId) : eq45(gtmRawSnapshots.workspaceId, connection.selectedWorkspaceId));
|
|
46633
|
-
const row = app.db.select().from(gtmRawSnapshots).where(
|
|
46766
|
+
const row = app.db.select().from(gtmRawSnapshots).where(and38(...conditions)).get();
|
|
46634
46767
|
const snapshot = row ? toGtmSnapshot(row) : null;
|
|
46635
46768
|
if (!snapshot || snapshot.metadata.id !== connection.lastSnapshotId || snapshot.metadata.connectionId !== connection.id || snapshot.metadata.accountId !== connection.selectedAccountId || snapshot.metadata.containerId !== connection.selectedContainerId || snapshot.metadata.workspaceId !== connection.selectedWorkspaceId || snapshot.metadata.capturedAt !== connection.lastSnapshotAt || snapshot.payload.kind !== GtmSnapshotKinds.container) return null;
|
|
46636
46769
|
return snapshot;
|
|
@@ -46680,7 +46813,7 @@ function latestGoogleAdsMetricsEvidence(app, projectId) {
|
|
|
46680
46813
|
eq45(googleAdsRawSnapshots.kind, GoogleAdsSnapshotKinds["campaign-metrics"]),
|
|
46681
46814
|
eq45(googleAdsRawSnapshots.capturedAt, connection.lastMetricsSnapshotAt)
|
|
46682
46815
|
];
|
|
46683
|
-
const row = app.db.select().from(googleAdsRawSnapshots).where(
|
|
46816
|
+
const row = app.db.select().from(googleAdsRawSnapshots).where(and38(...conditions)).get();
|
|
46684
46817
|
const snapshot = row ? toGoogleAdsSnapshot(row) : null;
|
|
46685
46818
|
if (!snapshot || snapshot.metadata.id !== connection.lastMetricsSnapshotId || snapshot.metadata.connectionId !== connection.id || snapshot.metadata.customerId !== connection.selectedCustomerId || snapshot.metadata.capturedAt !== connection.lastMetricsSnapshotAt || snapshot.payload.kind !== GoogleAdsSnapshotKinds["campaign-metrics"]) return null;
|
|
46686
46819
|
return {
|
|
@@ -47396,7 +47529,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
47396
47529
|
let run = candidateRun;
|
|
47397
47530
|
let queued = false;
|
|
47398
47531
|
app.db.transaction((tx) => {
|
|
47399
|
-
const existing = tx.select().from(runs).where(
|
|
47532
|
+
const existing = tx.select().from(runs).where(and38(
|
|
47400
47533
|
eq45(runs.projectId, project.id),
|
|
47401
47534
|
eq45(runs.kind, RunKinds["google-ads-sync"]),
|
|
47402
47535
|
or8(eq45(runs.status, RunStatuses.queued), eq45(runs.status, RunStatuses.running))
|
|
@@ -47432,7 +47565,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
47432
47565
|
let run = candidateRun;
|
|
47433
47566
|
let queued = false;
|
|
47434
47567
|
app.db.transaction((tx) => {
|
|
47435
|
-
const existing = tx.select().from(runs).where(
|
|
47568
|
+
const existing = tx.select().from(runs).where(and38(
|
|
47436
47569
|
eq45(runs.projectId, project.id),
|
|
47437
47570
|
eq45(runs.kind, RunKinds["gtm-sync"]),
|
|
47438
47571
|
or8(eq45(runs.status, RunStatuses.queued), eq45(runs.status, RunStatuses.running))
|
|
@@ -47467,11 +47600,11 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
47467
47600
|
if (cursor) {
|
|
47468
47601
|
conditions.push(or8(
|
|
47469
47602
|
lt6(googleAdsRawSnapshots.capturedAt, cursor.capturedAt),
|
|
47470
|
-
|
|
47603
|
+
and38(eq45(googleAdsRawSnapshots.capturedAt, cursor.capturedAt), lt6(googleAdsRawSnapshots.id, cursor.id))
|
|
47471
47604
|
));
|
|
47472
47605
|
}
|
|
47473
47606
|
const limit = query.limit ?? 50;
|
|
47474
|
-
const rows = app.db.select().from(googleAdsRawSnapshots).where(
|
|
47607
|
+
const rows = app.db.select().from(googleAdsRawSnapshots).where(and38(...conditions)).orderBy(desc20(googleAdsRawSnapshots.capturedAt), desc20(googleAdsRawSnapshots.id)).limit(limit + 1).all();
|
|
47475
47608
|
const page3 = rows.slice(0, limit);
|
|
47476
47609
|
const total = app.db.select({ total: sql15`COUNT(*)`.mapWith(Number).as("total") }).from(googleAdsRawSnapshots).where(eq45(googleAdsRawSnapshots.projectId, project.id)).get();
|
|
47477
47610
|
return {
|
|
@@ -47482,7 +47615,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
47482
47615
|
});
|
|
47483
47616
|
app.get("/projects/:name/google-ads/snapshots/:snapshotId", async (request) => {
|
|
47484
47617
|
const project = resolveProject(app.db, request.params.name);
|
|
47485
|
-
const row = app.db.select().from(googleAdsRawSnapshots).where(
|
|
47618
|
+
const row = app.db.select().from(googleAdsRawSnapshots).where(and38(
|
|
47486
47619
|
eq45(googleAdsRawSnapshots.projectId, project.id),
|
|
47487
47620
|
eq45(googleAdsRawSnapshots.id, request.params.snapshotId)
|
|
47488
47621
|
)).get();
|
|
@@ -47499,11 +47632,11 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
47499
47632
|
if (cursor) {
|
|
47500
47633
|
conditions.push(or8(
|
|
47501
47634
|
lt6(gtmRawSnapshots.capturedAt, cursor.capturedAt),
|
|
47502
|
-
|
|
47635
|
+
and38(eq45(gtmRawSnapshots.capturedAt, cursor.capturedAt), lt6(gtmRawSnapshots.id, cursor.id))
|
|
47503
47636
|
));
|
|
47504
47637
|
}
|
|
47505
47638
|
const limit = query.limit ?? 50;
|
|
47506
|
-
const rows = app.db.select().from(gtmRawSnapshots).where(
|
|
47639
|
+
const rows = app.db.select().from(gtmRawSnapshots).where(and38(...conditions)).orderBy(desc20(gtmRawSnapshots.capturedAt), desc20(gtmRawSnapshots.id)).limit(limit + 1).all();
|
|
47507
47640
|
const page3 = rows.slice(0, limit);
|
|
47508
47641
|
const total = app.db.select({ total: sql15`COUNT(*)`.mapWith(Number).as("total") }).from(gtmRawSnapshots).where(eq45(gtmRawSnapshots.projectId, project.id)).get();
|
|
47509
47642
|
return {
|
|
@@ -47514,7 +47647,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
47514
47647
|
});
|
|
47515
47648
|
app.get("/projects/:name/gtm/snapshots/:snapshotId", async (request) => {
|
|
47516
47649
|
const project = resolveProject(app.db, request.params.name);
|
|
47517
|
-
const row = app.db.select().from(gtmRawSnapshots).where(
|
|
47650
|
+
const row = app.db.select().from(gtmRawSnapshots).where(and38(
|
|
47518
47651
|
eq45(gtmRawSnapshots.projectId, project.id),
|
|
47519
47652
|
eq45(gtmRawSnapshots.id, request.params.snapshotId)
|
|
47520
47653
|
)).get();
|
|
@@ -47639,7 +47772,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
47639
47772
|
parseBody2(conversionTrackingContractWriteRequestSchema, request.body, "conversion tracking contract")
|
|
47640
47773
|
);
|
|
47641
47774
|
const project = resolveProject(app.db, request.params.name);
|
|
47642
|
-
const duplicate = app.db.select({ id: conversionTrackingContracts.id }).from(conversionTrackingContracts).where(
|
|
47775
|
+
const duplicate = app.db.select({ id: conversionTrackingContracts.id }).from(conversionTrackingContracts).where(and38(eq45(conversionTrackingContracts.projectId, project.id), eq45(conversionTrackingContracts.name, body.name))).get();
|
|
47643
47776
|
if (duplicate) throw alreadyExists("Conversion tracking contract", body.name);
|
|
47644
47777
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
47645
47778
|
const contract = {
|
|
@@ -47664,7 +47797,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
47664
47797
|
});
|
|
47665
47798
|
app.get("/projects/:name/conversion-tracking/contracts/:contractId", async (request) => {
|
|
47666
47799
|
const project = resolveProject(app.db, request.params.name);
|
|
47667
|
-
const row = app.db.select().from(conversionTrackingContracts).where(
|
|
47800
|
+
const row = app.db.select().from(conversionTrackingContracts).where(and38(
|
|
47668
47801
|
eq45(conversionTrackingContracts.projectId, project.id),
|
|
47669
47802
|
eq45(conversionTrackingContracts.id, request.params.contractId)
|
|
47670
47803
|
)).get();
|
|
@@ -47677,12 +47810,12 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
47677
47810
|
parseBody2(conversionTrackingContractWriteRequestSchema, request.body, "conversion tracking contract")
|
|
47678
47811
|
);
|
|
47679
47812
|
const project = resolveProject(app.db, request.params.name);
|
|
47680
|
-
const existing = app.db.select().from(conversionTrackingContracts).where(
|
|
47813
|
+
const existing = app.db.select().from(conversionTrackingContracts).where(and38(
|
|
47681
47814
|
eq45(conversionTrackingContracts.projectId, project.id),
|
|
47682
47815
|
eq45(conversionTrackingContracts.id, request.params.contractId)
|
|
47683
47816
|
)).get();
|
|
47684
47817
|
if (!existing) throw notFound("Conversion tracking contract", request.params.contractId);
|
|
47685
|
-
const duplicate = app.db.select({ id: conversionTrackingContracts.id }).from(conversionTrackingContracts).where(
|
|
47818
|
+
const duplicate = app.db.select({ id: conversionTrackingContracts.id }).from(conversionTrackingContracts).where(and38(
|
|
47686
47819
|
eq45(conversionTrackingContracts.projectId, project.id),
|
|
47687
47820
|
eq45(conversionTrackingContracts.name, body.name),
|
|
47688
47821
|
ne6(conversionTrackingContracts.id, existing.id)
|
|
@@ -47719,7 +47852,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
47719
47852
|
app.delete("/projects/:name/conversion-tracking/contracts/:contractId", async (request, reply) => {
|
|
47720
47853
|
requireWrite(request);
|
|
47721
47854
|
const project = resolveProject(app.db, request.params.name);
|
|
47722
|
-
const existing = app.db.select().from(conversionTrackingContracts).where(
|
|
47855
|
+
const existing = app.db.select().from(conversionTrackingContracts).where(and38(
|
|
47723
47856
|
eq45(conversionTrackingContracts.projectId, project.id),
|
|
47724
47857
|
eq45(conversionTrackingContracts.id, request.params.contractId)
|
|
47725
47858
|
)).get();
|
|
@@ -47739,7 +47872,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
47739
47872
|
});
|
|
47740
47873
|
app.get("/projects/:name/conversion-tracking/contracts/:contractId/integrity", async (request) => {
|
|
47741
47874
|
const project = resolveProject(app.db, request.params.name);
|
|
47742
|
-
const row = app.db.select().from(conversionTrackingContracts).where(
|
|
47875
|
+
const row = app.db.select().from(conversionTrackingContracts).where(and38(
|
|
47743
47876
|
eq45(conversionTrackingContracts.projectId, project.id),
|
|
47744
47877
|
eq45(conversionTrackingContracts.id, request.params.contractId)
|
|
47745
47878
|
)).get();
|
|
@@ -47774,7 +47907,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
47774
47907
|
|
|
47775
47908
|
// ../api-routes/src/ads.ts
|
|
47776
47909
|
import crypto36 from "crypto";
|
|
47777
|
-
import { eq as eq47, and as
|
|
47910
|
+
import { eq as eq47, and as and40, asc as asc9, desc as desc21, gt as gt3, gte as gte12, lt as lt7, lte as lte11, ne as ne7, inArray as inArray20, or as or10, isNull as isNull8, isNotNull as isNotNull4, sql as sql17 } from "drizzle-orm";
|
|
47778
47911
|
|
|
47779
47912
|
// ../api-routes/src/ads-activation.ts
|
|
47780
47913
|
import crypto34 from "crypto";
|
|
@@ -49160,7 +49293,7 @@ async function executeApprovedAdsActivation(dependencies, request) {
|
|
|
49160
49293
|
|
|
49161
49294
|
// ../api-routes/src/ads-activation-routes.ts
|
|
49162
49295
|
import crypto35 from "crypto";
|
|
49163
|
-
import { and as
|
|
49296
|
+
import { and as and39, asc as asc8, eq as eq46, gt as gt2, isNotNull as isNotNull3, isNull as isNull7, lte as lte10, or as or9, sql as sql16 } from "drizzle-orm";
|
|
49164
49297
|
var MAX_ACTIVATION_GRANT_LIFETIME_MS = 24 * 60 * 60 * 1e3;
|
|
49165
49298
|
var ACTIVATION_LEASE_MS = 5 * 6e4;
|
|
49166
49299
|
var ACTIVATION_REVOCATION_SETTLEMENT_MS = ACTIVATION_LEASE_MS;
|
|
@@ -49258,7 +49391,7 @@ function createActivationStore(app, request) {
|
|
|
49258
49391
|
const bindingRejection = validateGrantBinding(grantRow, input);
|
|
49259
49392
|
if (bindingRejection) return bindingRejection;
|
|
49260
49393
|
const grant = grantRow;
|
|
49261
|
-
const existing = tx.select().from(adsOperations).where(
|
|
49394
|
+
const existing = tx.select().from(adsOperations).where(and39(
|
|
49262
49395
|
eq46(adsOperations.projectId, input.projectId),
|
|
49263
49396
|
eq46(adsOperations.operationKey, input.operationKey)
|
|
49264
49397
|
)).get();
|
|
@@ -49283,7 +49416,7 @@ function createActivationStore(app, request) {
|
|
|
49283
49416
|
leaseOwner: input.leaseOwner,
|
|
49284
49417
|
leaseExpiresAt: input.leaseExpiresAt,
|
|
49285
49418
|
updatedAt: input.now
|
|
49286
|
-
}).where(
|
|
49419
|
+
}).where(and39(
|
|
49287
49420
|
eq46(adsOperations.id, existing.id),
|
|
49288
49421
|
eq46(adsOperations.state, AdsOperationStates.pending),
|
|
49289
49422
|
or9(
|
|
@@ -49305,7 +49438,7 @@ function createActivationStore(app, request) {
|
|
|
49305
49438
|
state: AdsActivationGrantStates.expired,
|
|
49306
49439
|
expiredAt: input.now,
|
|
49307
49440
|
updatedAt: input.now
|
|
49308
|
-
}).where(
|
|
49441
|
+
}).where(and39(
|
|
49309
49442
|
eq46(adsActivationGrants.id, grant.id),
|
|
49310
49443
|
eq46(adsActivationGrants.state, AdsActivationGrantStates.approved)
|
|
49311
49444
|
)).run();
|
|
@@ -49341,7 +49474,7 @@ function createActivationStore(app, request) {
|
|
|
49341
49474
|
operationId: input.operationId,
|
|
49342
49475
|
executionStartedAt: input.now,
|
|
49343
49476
|
updatedAt: input.now
|
|
49344
|
-
}).where(
|
|
49477
|
+
}).where(and39(
|
|
49345
49478
|
eq46(adsActivationGrants.id, grant.id),
|
|
49346
49479
|
eq46(adsActivationGrants.projectId, input.projectId),
|
|
49347
49480
|
eq46(adsActivationGrants.adAccountId, input.adAccountId),
|
|
@@ -49377,7 +49510,7 @@ function createActivationStore(app, request) {
|
|
|
49377
49510
|
const changed = tx.update(adsOperations).set({
|
|
49378
49511
|
leaseExpiresAt: input.leaseExpiresAt,
|
|
49379
49512
|
updatedAt: input.now
|
|
49380
|
-
}).where(
|
|
49513
|
+
}).where(and39(
|
|
49381
49514
|
eq46(adsOperations.id, input.operationId),
|
|
49382
49515
|
eq46(adsOperations.state, AdsOperationStates.pending),
|
|
49383
49516
|
eq46(adsOperations.leaseOwner, input.leaseOwner),
|
|
@@ -49392,7 +49525,7 @@ function createActivationStore(app, request) {
|
|
|
49392
49525
|
leaseOwner: null,
|
|
49393
49526
|
leaseExpiresAt: null,
|
|
49394
49527
|
updatedAt: input.now
|
|
49395
|
-
}).where(
|
|
49528
|
+
}).where(and39(
|
|
49396
49529
|
eq46(adsOperations.id, input.operationId),
|
|
49397
49530
|
eq46(adsOperations.state, AdsOperationStates.pending),
|
|
49398
49531
|
eq46(adsOperations.leaseOwner, input.leaseOwner)
|
|
@@ -49405,7 +49538,7 @@ function createActivationStore(app, request) {
|
|
|
49405
49538
|
if (input.fromState !== AdsOperationStepStates.pending || input.next.state !== AdsOperationStepStates.executing) {
|
|
49406
49539
|
throw internalError("Ads activation forward authorization transition is invalid");
|
|
49407
49540
|
}
|
|
49408
|
-
const grant = tx.select().from(adsActivationGrants).where(
|
|
49541
|
+
const grant = tx.select().from(adsActivationGrants).where(and39(
|
|
49409
49542
|
eq46(adsActivationGrants.id, input.grantId),
|
|
49410
49543
|
eq46(adsActivationGrants.operationId, input.operationId)
|
|
49411
49544
|
)).get();
|
|
@@ -49421,7 +49554,7 @@ function createActivationStore(app, request) {
|
|
|
49421
49554
|
if (!Number.isFinite(expiresAt) || expiresAt <= Date.parse(input.now)) {
|
|
49422
49555
|
return { applied: false, operation, rejection: "expired" };
|
|
49423
49556
|
}
|
|
49424
|
-
const existing = tx.select().from(adsOperationSteps).where(
|
|
49557
|
+
const existing = tx.select().from(adsOperationSteps).where(and39(
|
|
49425
49558
|
eq46(adsOperationSteps.id, input.next.id),
|
|
49426
49559
|
eq46(adsOperationSteps.operationId, input.operationId)
|
|
49427
49560
|
)).get();
|
|
@@ -49433,7 +49566,7 @@ function createActivationStore(app, request) {
|
|
|
49433
49566
|
const lease = tx.update(adsOperations).set({
|
|
49434
49567
|
leaseExpiresAt: input.leaseExpiresAt,
|
|
49435
49568
|
updatedAt: input.next.updatedAt
|
|
49436
|
-
}).where(
|
|
49569
|
+
}).where(and39(
|
|
49437
49570
|
eq46(adsOperations.id, input.operationId),
|
|
49438
49571
|
eq46(adsOperations.state, AdsOperationStates.pending),
|
|
49439
49572
|
eq46(adsOperations.leaseOwner, input.leaseOwner),
|
|
@@ -49453,7 +49586,7 @@ function createActivationStore(app, request) {
|
|
|
49453
49586
|
startedAt: input.next.startedAt,
|
|
49454
49587
|
finishedAt: input.next.finishedAt,
|
|
49455
49588
|
updatedAt: input.next.updatedAt
|
|
49456
|
-
}).where(
|
|
49589
|
+
}).where(and39(
|
|
49457
49590
|
eq46(adsOperationSteps.id, input.next.id),
|
|
49458
49591
|
eq46(adsOperationSteps.operationId, input.operationId),
|
|
49459
49592
|
eq46(adsOperationSteps.state, input.fromState)
|
|
@@ -49463,7 +49596,7 @@ function createActivationStore(app, request) {
|
|
|
49463
49596
|
return { applied: changed.changes === 1, operation: current };
|
|
49464
49597
|
}, { behavior: "immediate" }),
|
|
49465
49598
|
transitionStep: async (input) => app.db.transaction((tx) => {
|
|
49466
|
-
const existing = tx.select().from(adsOperationSteps).where(
|
|
49599
|
+
const existing = tx.select().from(adsOperationSteps).where(and39(
|
|
49467
49600
|
eq46(adsOperationSteps.id, input.next.id),
|
|
49468
49601
|
eq46(adsOperationSteps.operationId, input.operationId)
|
|
49469
49602
|
)).get();
|
|
@@ -49475,7 +49608,7 @@ function createActivationStore(app, request) {
|
|
|
49475
49608
|
const lease = tx.update(adsOperations).set({
|
|
49476
49609
|
leaseExpiresAt: input.leaseExpiresAt,
|
|
49477
49610
|
updatedAt: input.next.updatedAt
|
|
49478
|
-
}).where(
|
|
49611
|
+
}).where(and39(
|
|
49479
49612
|
eq46(adsOperations.id, input.operationId),
|
|
49480
49613
|
eq46(adsOperations.state, AdsOperationStates.pending),
|
|
49481
49614
|
eq46(adsOperations.leaseOwner, input.leaseOwner),
|
|
@@ -49495,7 +49628,7 @@ function createActivationStore(app, request) {
|
|
|
49495
49628
|
startedAt: input.next.startedAt,
|
|
49496
49629
|
finishedAt: input.next.finishedAt,
|
|
49497
49630
|
updatedAt: input.next.updatedAt
|
|
49498
|
-
}).where(
|
|
49631
|
+
}).where(and39(
|
|
49499
49632
|
eq46(adsOperationSteps.id, input.next.id),
|
|
49500
49633
|
eq46(adsOperationSteps.operationId, input.operationId),
|
|
49501
49634
|
eq46(adsOperationSteps.state, input.fromState)
|
|
@@ -49505,7 +49638,7 @@ function createActivationStore(app, request) {
|
|
|
49505
49638
|
return { applied: changed.changes === 1, operation };
|
|
49506
49639
|
}, { behavior: "immediate" }),
|
|
49507
49640
|
finishOperation: async (input) => app.db.transaction((tx) => {
|
|
49508
|
-
const currentGrant = tx.select().from(adsActivationGrants).where(
|
|
49641
|
+
const currentGrant = tx.select().from(adsActivationGrants).where(and39(
|
|
49509
49642
|
eq46(adsActivationGrants.id, input.grantId),
|
|
49510
49643
|
eq46(adsActivationGrants.operationId, input.operationId)
|
|
49511
49644
|
)).get();
|
|
@@ -49526,7 +49659,7 @@ function createActivationStore(app, request) {
|
|
|
49526
49659
|
);
|
|
49527
49660
|
}
|
|
49528
49661
|
const effectiveGrantState = input.operationState === AdsOperationStates.unknown ? AdsActivationGrantStates.unknown : input.grantState;
|
|
49529
|
-
const campaignStep = tx.select().from(adsOperationSteps).where(
|
|
49662
|
+
const campaignStep = tx.select().from(adsOperationSteps).where(and39(
|
|
49530
49663
|
eq46(adsOperationSteps.operationId, input.operationId),
|
|
49531
49664
|
eq46(adsOperationSteps.entityType, AdsActivationEntityTypes.campaign)
|
|
49532
49665
|
)).get();
|
|
@@ -49538,7 +49671,7 @@ function createActivationStore(app, request) {
|
|
|
49538
49671
|
leaseOwner: null,
|
|
49539
49672
|
leaseExpiresAt: null,
|
|
49540
49673
|
updatedAt: input.now
|
|
49541
|
-
}).where(
|
|
49674
|
+
}).where(and39(
|
|
49542
49675
|
eq46(adsOperations.id, input.operationId),
|
|
49543
49676
|
eq46(adsOperations.state, AdsOperationStates.pending),
|
|
49544
49677
|
eq46(adsOperations.leaseOwner, input.leaseOwner),
|
|
@@ -49549,7 +49682,7 @@ function createActivationStore(app, request) {
|
|
|
49549
49682
|
state: effectiveGrantState,
|
|
49550
49683
|
consumedAt: effectiveGrantState === AdsActivationGrantStates.consumed ? input.now : null,
|
|
49551
49684
|
updatedAt: input.now
|
|
49552
|
-
}).where(
|
|
49685
|
+
}).where(and39(
|
|
49553
49686
|
eq46(adsActivationGrants.id, input.grantId),
|
|
49554
49687
|
eq46(adsActivationGrants.operationId, input.operationId),
|
|
49555
49688
|
eq46(adsActivationGrants.state, AdsActivationGrantStates.executing)
|
|
@@ -49718,14 +49851,14 @@ function selectWatchdogOperations(app, nowIso, batchSize, allowLiveRevocationLea
|
|
|
49718
49851
|
);
|
|
49719
49852
|
const eligibleState = allowLiveRevocationLease ? or9(
|
|
49720
49853
|
eq46(adsOperations.state, AdsOperationStates.unknown),
|
|
49721
|
-
|
|
49854
|
+
and39(
|
|
49722
49855
|
eq46(adsOperations.state, AdsOperationStates.pending),
|
|
49723
49856
|
or9(
|
|
49724
49857
|
isNotNull3(adsActivationGrants.revocationRequestedAt),
|
|
49725
|
-
|
|
49858
|
+
and39(leaseAvailable, campaignHasMutationEvidence)
|
|
49726
49859
|
)
|
|
49727
49860
|
)
|
|
49728
|
-
) :
|
|
49861
|
+
) : and39(
|
|
49729
49862
|
or9(
|
|
49730
49863
|
eq46(adsOperations.state, AdsOperationStates.unknown),
|
|
49731
49864
|
eq46(adsOperations.state, AdsOperationStates.pending)
|
|
@@ -49747,11 +49880,11 @@ function selectWatchdogOperations(app, nowIso, batchSize, allowLiveRevocationLea
|
|
|
49747
49880
|
eq46(adsActivationGrants.operationId, adsOperations.id)
|
|
49748
49881
|
).leftJoin(
|
|
49749
49882
|
adsOperationSteps,
|
|
49750
|
-
|
|
49883
|
+
and39(
|
|
49751
49884
|
eq46(adsOperationSteps.operationId, adsOperations.id),
|
|
49752
49885
|
eq46(adsOperationSteps.entityType, AdsActivationEntityTypes.campaign)
|
|
49753
49886
|
)
|
|
49754
|
-
).where(
|
|
49887
|
+
).where(and39(
|
|
49755
49888
|
eq46(adsOperations.kind, AdsOperationKinds.campaign_tree_activate),
|
|
49756
49889
|
eligibleState
|
|
49757
49890
|
)).orderBy(
|
|
@@ -49778,7 +49911,7 @@ function finalizeContainedRevokedUnknownActivation(app, operation, grant) {
|
|
|
49778
49911
|
leaseExpiresAt: null,
|
|
49779
49912
|
lastReconciledAt: nowIso,
|
|
49780
49913
|
updatedAt: nowIso
|
|
49781
|
-
}).where(
|
|
49914
|
+
}).where(and39(
|
|
49782
49915
|
eq46(adsOperations.id, operation.id),
|
|
49783
49916
|
eq46(adsOperations.state, AdsOperationStates.unknown)
|
|
49784
49917
|
)).run();
|
|
@@ -49787,7 +49920,7 @@ function finalizeContainedRevokedUnknownActivation(app, operation, grant) {
|
|
|
49787
49920
|
state: AdsActivationGrantStates.consumed,
|
|
49788
49921
|
consumedAt: nowIso,
|
|
49789
49922
|
updatedAt: nowIso
|
|
49790
|
-
}).where(
|
|
49923
|
+
}).where(and39(
|
|
49791
49924
|
eq46(adsActivationGrants.id, grant.id),
|
|
49792
49925
|
eq46(adsActivationGrants.operationId, operation.id),
|
|
49793
49926
|
eq46(adsActivationGrants.state, AdsActivationGrantStates.unknown),
|
|
@@ -49868,7 +50001,7 @@ async function containUrgentAdsActivationCampaignsOnce(app, opts) {
|
|
|
49868
50001
|
}
|
|
49869
50002
|
app.db.update(adsOperations).set({
|
|
49870
50003
|
lastReconciledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
49871
|
-
}).where(
|
|
50004
|
+
}).where(and39(
|
|
49872
50005
|
eq46(adsOperations.id, operation.id),
|
|
49873
50006
|
or9(
|
|
49874
50007
|
eq46(adsOperations.state, AdsOperationStates.unknown),
|
|
@@ -49894,11 +50027,11 @@ async function sweepStaleAdsActivationsOnce(app, opts) {
|
|
|
49894
50027
|
leaseOwner: null,
|
|
49895
50028
|
leaseExpiresAt: null,
|
|
49896
50029
|
updatedAt: nowIso
|
|
49897
|
-
}).where(
|
|
50030
|
+
}).where(and39(
|
|
49898
50031
|
eq46(adsOperations.id, operation.id),
|
|
49899
50032
|
or9(
|
|
49900
50033
|
eq46(adsOperations.state, AdsOperationStates.unknown),
|
|
49901
|
-
|
|
50034
|
+
and39(
|
|
49902
50035
|
eq46(adsOperations.state, AdsOperationStates.pending),
|
|
49903
50036
|
or9(
|
|
49904
50037
|
isNull7(adsOperations.leaseOwner),
|
|
@@ -49912,7 +50045,7 @@ async function sweepStaleAdsActivationsOnce(app, opts) {
|
|
|
49912
50045
|
tx.update(adsActivationGrants).set({
|
|
49913
50046
|
state: AdsActivationGrantStates.unknown,
|
|
49914
50047
|
updatedAt: nowIso
|
|
49915
|
-
}).where(
|
|
50048
|
+
}).where(and39(
|
|
49916
50049
|
eq46(adsActivationGrants.id, grant.id),
|
|
49917
50050
|
eq46(adsActivationGrants.operationId, operation.id),
|
|
49918
50051
|
eq46(adsActivationGrants.state, AdsActivationGrantStates.executing)
|
|
@@ -49931,11 +50064,11 @@ async function sweepStaleAdsActivationsOnce(app, opts) {
|
|
|
49931
50064
|
}));
|
|
49932
50065
|
const markRecoveryIncomplete = (operation) => {
|
|
49933
50066
|
const failedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
49934
|
-
app.db.update(adsOperations).set({ updatedAt: failedAt }).where(
|
|
50067
|
+
app.db.update(adsOperations).set({ updatedAt: failedAt }).where(and39(
|
|
49935
50068
|
eq46(adsOperations.id, operation.id),
|
|
49936
50069
|
or9(
|
|
49937
50070
|
eq46(adsOperations.state, AdsOperationStates.unknown),
|
|
49938
|
-
|
|
50071
|
+
and39(
|
|
49939
50072
|
eq46(adsOperations.state, AdsOperationStates.pending),
|
|
49940
50073
|
or9(
|
|
49941
50074
|
isNull7(adsOperations.leaseOwner),
|
|
@@ -49974,7 +50107,7 @@ async function sweepStaleAdsActivationsOnce(app, opts) {
|
|
|
49974
50107
|
lastReconciledAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
49975
50108
|
errorMessage: safety.fullyVerified ? "Unknown activation was safety-paused; manual remediation is still required" : "Unknown activation safety pause could not be fully verified",
|
|
49976
50109
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
49977
|
-
}).where(
|
|
50110
|
+
}).where(and39(
|
|
49978
50111
|
eq46(adsOperations.id, operation.id),
|
|
49979
50112
|
eq46(adsOperations.state, AdsOperationStates.unknown)
|
|
49980
50113
|
)).run();
|
|
@@ -50137,13 +50270,13 @@ function registerAdsActivationRoutes(app, opts) {
|
|
|
50137
50270
|
adsActivationGrantRevokeRequestSchema,
|
|
50138
50271
|
request.body === void 0 ? {} : request.body
|
|
50139
50272
|
);
|
|
50140
|
-
const existing = app.db.select().from(adsActivationGrants).where(
|
|
50273
|
+
const existing = app.db.select().from(adsActivationGrants).where(and39(
|
|
50141
50274
|
eq46(adsActivationGrants.id, request.params.grantId),
|
|
50142
50275
|
eq46(adsActivationGrants.projectId, project.id)
|
|
50143
50276
|
)).get();
|
|
50144
50277
|
if (!existing) throw notFound("Ads activation grant", request.params.grantId);
|
|
50145
50278
|
const grant = app.db.transaction((tx) => {
|
|
50146
|
-
const current = tx.select().from(adsActivationGrants).where(
|
|
50279
|
+
const current = tx.select().from(adsActivationGrants).where(and39(
|
|
50147
50280
|
eq46(adsActivationGrants.id, request.params.grantId),
|
|
50148
50281
|
eq46(adsActivationGrants.projectId, project.id)
|
|
50149
50282
|
)).get();
|
|
@@ -50164,7 +50297,7 @@ function registerAdsActivationRoutes(app, opts) {
|
|
|
50164
50297
|
tx.update(adsActivationGrants).set({
|
|
50165
50298
|
revocationRequestedAt: nowIso,
|
|
50166
50299
|
updatedAt: nowIso
|
|
50167
|
-
}).where(
|
|
50300
|
+
}).where(and39(
|
|
50168
50301
|
eq46(adsActivationGrants.id, current.id),
|
|
50169
50302
|
eq46(adsActivationGrants.state, current.state),
|
|
50170
50303
|
isNull7(adsActivationGrants.revocationRequestedAt)
|
|
@@ -50175,7 +50308,7 @@ function registerAdsActivationRoutes(app, opts) {
|
|
|
50175
50308
|
revokedAt: expired ? null : nowIso,
|
|
50176
50309
|
expiredAt: expired ? nowIso : null,
|
|
50177
50310
|
updatedAt: nowIso
|
|
50178
|
-
}).where(
|
|
50311
|
+
}).where(and39(
|
|
50179
50312
|
eq46(adsActivationGrants.id, current.id),
|
|
50180
50313
|
eq46(adsActivationGrants.state, AdsActivationGrantStates.approved)
|
|
50181
50314
|
)).run();
|
|
@@ -50205,7 +50338,7 @@ function registerAdsActivationRoutes(app, opts) {
|
|
|
50205
50338
|
const executor = requireAuthenticatedKey(request);
|
|
50206
50339
|
const project = resolveProject(app.db, request.params.name);
|
|
50207
50340
|
const body = parseBody3(adsActivateTreeRequestSchema, request.body);
|
|
50208
|
-
const grant = app.db.select().from(adsActivationGrants).where(
|
|
50341
|
+
const grant = app.db.select().from(adsActivationGrants).where(and39(
|
|
50209
50342
|
eq46(adsActivationGrants.id, body.grantId),
|
|
50210
50343
|
eq46(adsActivationGrants.projectId, project.id)
|
|
50211
50344
|
)).get();
|
|
@@ -50252,14 +50385,14 @@ function registerAdsActivationRoutes(app, opts) {
|
|
|
50252
50385
|
if (request.body !== void 0) {
|
|
50253
50386
|
throw validationError("Ads activation recovery does not accept a request body");
|
|
50254
50387
|
}
|
|
50255
|
-
const operation = app.db.select().from(adsOperations).where(
|
|
50388
|
+
const operation = app.db.select().from(adsOperations).where(and39(
|
|
50256
50389
|
eq46(adsOperations.projectId, project.id),
|
|
50257
50390
|
eq46(adsOperations.operationKey, request.params.operationKey)
|
|
50258
50391
|
)).get();
|
|
50259
50392
|
if (!operation || operation.kind !== AdsOperationKinds.campaign_tree_activate) {
|
|
50260
50393
|
throw notFound("Ads activation operation", request.params.operationKey);
|
|
50261
50394
|
}
|
|
50262
|
-
const grant = app.db.select().from(adsActivationGrants).where(
|
|
50395
|
+
const grant = app.db.select().from(adsActivationGrants).where(and39(
|
|
50263
50396
|
eq46(adsActivationGrants.projectId, project.id),
|
|
50264
50397
|
eq46(adsActivationGrants.operationId, operation.id)
|
|
50265
50398
|
)).get();
|
|
@@ -50803,7 +50936,7 @@ function semanticallyMatchesMaterializedEntity(app, input) {
|
|
|
50803
50936
|
return AdsOperationKinds.ad_update;
|
|
50804
50937
|
}
|
|
50805
50938
|
})();
|
|
50806
|
-
const rows = app.db.select().from(adsOperations).where(
|
|
50939
|
+
const rows = app.db.select().from(adsOperations).where(and40(
|
|
50807
50940
|
eq47(adsOperations.projectId, input.projectId),
|
|
50808
50941
|
eq47(adsOperations.entityType, input.entityType),
|
|
50809
50942
|
eq47(adsOperations.entityId, input.entityId),
|
|
@@ -50992,7 +51125,7 @@ async function executeAdsOperation(app, request, input) {
|
|
|
50992
51125
|
}).onConflictDoNothing({
|
|
50993
51126
|
target: [adsOperations.projectId, adsOperations.operationKey]
|
|
50994
51127
|
}).returning({ id: adsOperations.id }).all();
|
|
50995
|
-
const canonical = app.db.select().from(adsOperations).where(
|
|
51128
|
+
const canonical = app.db.select().from(adsOperations).where(and40(
|
|
50996
51129
|
eq47(adsOperations.projectId, input.projectId),
|
|
50997
51130
|
eq47(adsOperations.operationKey, input.operationKey)
|
|
50998
51131
|
)).get();
|
|
@@ -51012,7 +51145,7 @@ async function executeAdsOperation(app, request, input) {
|
|
|
51012
51145
|
entityId: result.id,
|
|
51013
51146
|
upstreamUpdatedAt: result.updatedAt ?? null,
|
|
51014
51147
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
51015
|
-
}).where(
|
|
51148
|
+
}).where(and40(
|
|
51016
51149
|
eq47(adsOperations.id, id),
|
|
51017
51150
|
eq47(adsOperations.state, AdsOperationStates.pending),
|
|
51018
51151
|
isNull8(adsOperations.leaseOwner)
|
|
@@ -51033,7 +51166,7 @@ async function executeAdsOperation(app, request, input) {
|
|
|
51033
51166
|
errorCode: null,
|
|
51034
51167
|
errorMessage: null,
|
|
51035
51168
|
updatedAt
|
|
51036
|
-
}).where(
|
|
51169
|
+
}).where(and40(
|
|
51037
51170
|
eq47(adsOperations.id, id),
|
|
51038
51171
|
eq47(adsOperations.state, AdsOperationStates.pending),
|
|
51039
51172
|
isNull8(adsOperations.leaseOwner)
|
|
@@ -51062,7 +51195,7 @@ async function executeAdsOperation(app, request, input) {
|
|
|
51062
51195
|
errorCode: failure.code,
|
|
51063
51196
|
errorMessage: failure.message,
|
|
51064
51197
|
updatedAt
|
|
51065
|
-
}).where(
|
|
51198
|
+
}).where(and40(
|
|
51066
51199
|
eq47(adsOperations.id, id),
|
|
51067
51200
|
eq47(adsOperations.state, AdsOperationStates.pending),
|
|
51068
51201
|
isNull8(adsOperations.leaseOwner)
|
|
@@ -51080,7 +51213,7 @@ async function executeAdsOperation(app, request, input) {
|
|
|
51080
51213
|
return update.changes > 0;
|
|
51081
51214
|
});
|
|
51082
51215
|
if (!finalized) {
|
|
51083
|
-
const canonical2 = app.db.select().from(adsOperations).where(
|
|
51216
|
+
const canonical2 = app.db.select().from(adsOperations).where(and40(
|
|
51084
51217
|
eq47(adsOperations.id, id),
|
|
51085
51218
|
eq47(adsOperations.projectId, input.projectId)
|
|
51086
51219
|
)).get();
|
|
@@ -51097,7 +51230,7 @@ async function executeAdsOperation(app, request, input) {
|
|
|
51097
51230
|
}
|
|
51098
51231
|
}
|
|
51099
51232
|
function readOperationByKey(app, projectId, operationKey) {
|
|
51100
|
-
return app.db.select().from(adsOperations).where(
|
|
51233
|
+
return app.db.select().from(adsOperations).where(and40(
|
|
51101
51234
|
eq47(adsOperations.projectId, projectId),
|
|
51102
51235
|
eq47(adsOperations.operationKey, operationKey)
|
|
51103
51236
|
)).get();
|
|
@@ -51115,13 +51248,13 @@ function claimOperationForReconciliation(app, row, leaseOwner, now, leaseMs, pol
|
|
|
51115
51248
|
const pendingCutoff = new Date(now.getTime() - policy.pendingMinIdleMs).toISOString();
|
|
51116
51249
|
const backoffMs = policy.backoffBaseMs * 2 ** Math.max(0, row.reconcileAttempts - 1);
|
|
51117
51250
|
const unknownCutoff = new Date(now.getTime() - backoffMs).toISOString();
|
|
51118
|
-
const claimableState = row.state === AdsOperationStates.pending ?
|
|
51251
|
+
const claimableState = row.state === AdsOperationStates.pending ? and40(
|
|
51119
51252
|
eq47(adsOperations.state, AdsOperationStates.pending),
|
|
51120
51253
|
lte11(adsOperations.updatedAt, pendingCutoff)
|
|
51121
|
-
) : row.state === AdsOperationStates.unknown ?
|
|
51254
|
+
) : row.state === AdsOperationStates.unknown ? and40(
|
|
51122
51255
|
eq47(adsOperations.state, AdsOperationStates.unknown),
|
|
51123
51256
|
enforceBackoff ? lte11(adsOperations.updatedAt, unknownCutoff) : void 0
|
|
51124
|
-
) :
|
|
51257
|
+
) : and40(
|
|
51125
51258
|
eq47(adsOperations.state, AdsOperationStates.reconciling),
|
|
51126
51259
|
or10(isNull8(adsOperations.leaseExpiresAt), lte11(adsOperations.leaseExpiresAt, nowIso))
|
|
51127
51260
|
);
|
|
@@ -51131,7 +51264,7 @@ function claimOperationForReconciliation(app, row, leaseOwner, now, leaseMs, pol
|
|
|
51131
51264
|
leaseExpiresAt: leaseExpiresAt2,
|
|
51132
51265
|
reconcileAttempts: sql17`${adsOperations.reconcileAttempts} + 1`,
|
|
51133
51266
|
updatedAt: nowIso
|
|
51134
|
-
}).where(
|
|
51267
|
+
}).where(and40(
|
|
51135
51268
|
eq47(adsOperations.id, row.id),
|
|
51136
51269
|
eq47(adsOperations.projectId, row.projectId),
|
|
51137
51270
|
eq47(adsOperations.reconcileAttempts, row.reconcileAttempts),
|
|
@@ -51185,7 +51318,7 @@ function finishReconciliation(app, row, leaseOwner, context, outcome, maxAttempt
|
|
|
51185
51318
|
leaseOwner: null,
|
|
51186
51319
|
leaseExpiresAt: null,
|
|
51187
51320
|
updatedAt: now
|
|
51188
|
-
}).where(
|
|
51321
|
+
}).where(and40(
|
|
51189
51322
|
eq47(adsOperations.id, row.id),
|
|
51190
51323
|
eq47(adsOperations.projectId, row.projectId),
|
|
51191
51324
|
eq47(adsOperations.leaseOwner, leaseOwner),
|
|
@@ -51198,7 +51331,7 @@ function finishReconciliation(app, row, leaseOwner, context, outcome, maxAttempt
|
|
|
51198
51331
|
}));
|
|
51199
51332
|
}
|
|
51200
51333
|
});
|
|
51201
|
-
const canonical = app.db.select().from(adsOperations).where(
|
|
51334
|
+
const canonical = app.db.select().from(adsOperations).where(and40(
|
|
51202
51335
|
eq47(adsOperations.id, row.id),
|
|
51203
51336
|
eq47(adsOperations.projectId, row.projectId)
|
|
51204
51337
|
)).get();
|
|
@@ -51240,7 +51373,7 @@ function quarantineExhaustedReconciliation(app, row, now, policy, context) {
|
|
|
51240
51373
|
leaseOwner: null,
|
|
51241
51374
|
leaseExpiresAt: null,
|
|
51242
51375
|
updatedAt: nowIso
|
|
51243
|
-
}).where(
|
|
51376
|
+
}).where(and40(
|
|
51244
51377
|
eq47(adsOperations.id, row.id),
|
|
51245
51378
|
eq47(adsOperations.projectId, row.projectId),
|
|
51246
51379
|
gte12(adsOperations.reconcileAttempts, policy.maxAttempts),
|
|
@@ -51439,32 +51572,32 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
51439
51572
|
{ length: config.policy.maxAttempts },
|
|
51440
51573
|
(_, reconcileAttempts) => {
|
|
51441
51574
|
const backoffMs = config.policy.backoffBaseMs * 2 ** Math.max(0, reconcileAttempts - 1);
|
|
51442
|
-
return
|
|
51575
|
+
return and40(
|
|
51443
51576
|
eq47(adsOperations.reconcileAttempts, reconcileAttempts),
|
|
51444
51577
|
lte11(adsOperations.updatedAt, new Date(now.getTime() - backoffMs).toISOString())
|
|
51445
51578
|
);
|
|
51446
51579
|
}
|
|
51447
51580
|
);
|
|
51448
51581
|
const retryableStateWhere = or10(
|
|
51449
|
-
|
|
51582
|
+
and40(
|
|
51450
51583
|
eq47(adsOperations.state, AdsOperationStates.pending),
|
|
51451
51584
|
lte11(adsOperations.updatedAt, pendingCutoff)
|
|
51452
51585
|
),
|
|
51453
|
-
|
|
51586
|
+
and40(
|
|
51454
51587
|
eq47(adsOperations.state, AdsOperationStates.unknown),
|
|
51455
51588
|
or10(...unknownRetryWindows)
|
|
51456
51589
|
),
|
|
51457
|
-
|
|
51590
|
+
and40(
|
|
51458
51591
|
eq47(adsOperations.state, AdsOperationStates.reconciling),
|
|
51459
51592
|
or10(isNull8(adsOperations.leaseExpiresAt), lte11(adsOperations.leaseExpiresAt, nowIso))
|
|
51460
51593
|
)
|
|
51461
51594
|
);
|
|
51462
|
-
const staleReconcileWhere =
|
|
51595
|
+
const staleReconcileWhere = and40(
|
|
51463
51596
|
lt7(adsOperations.reconcileAttempts, config.policy.maxAttempts),
|
|
51464
51597
|
ne7(adsOperations.kind, AdsOperationKinds.campaign_tree_activate),
|
|
51465
51598
|
or10(
|
|
51466
51599
|
eq47(adsOperations.reconcileStrategy, AdsReconcileStrategies.known_entity),
|
|
51467
|
-
|
|
51600
|
+
and40(
|
|
51468
51601
|
eq47(adsOperations.reconcileStrategy, AdsReconcileStrategies.create_fingerprint),
|
|
51469
51602
|
or10(
|
|
51470
51603
|
isNotNull4(adsOperations.entityId),
|
|
@@ -51477,16 +51610,16 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
51477
51610
|
),
|
|
51478
51611
|
retryableStateWhere
|
|
51479
51612
|
);
|
|
51480
|
-
const exhaustedRows = app.db.select().from(adsOperations).where(
|
|
51613
|
+
const exhaustedRows = app.db.select().from(adsOperations).where(and40(
|
|
51481
51614
|
ne7(adsOperations.kind, AdsOperationKinds.campaign_tree_activate),
|
|
51482
51615
|
gte12(adsOperations.reconcileAttempts, config.policy.maxAttempts),
|
|
51483
51616
|
or10(
|
|
51484
|
-
|
|
51617
|
+
and40(
|
|
51485
51618
|
eq47(adsOperations.state, AdsOperationStates.pending),
|
|
51486
51619
|
lte11(adsOperations.updatedAt, pendingCutoff)
|
|
51487
51620
|
),
|
|
51488
51621
|
eq47(adsOperations.state, AdsOperationStates.unknown),
|
|
51489
|
-
|
|
51622
|
+
and40(
|
|
51490
51623
|
eq47(adsOperations.state, AdsOperationStates.reconciling),
|
|
51491
51624
|
or10(isNull8(adsOperations.leaseExpiresAt), lte11(adsOperations.leaseExpiresAt, nowIso))
|
|
51492
51625
|
)
|
|
@@ -51515,7 +51648,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
51515
51648
|
}
|
|
51516
51649
|
const eligibleProjectIds = [...credentialsByProjectId.keys()];
|
|
51517
51650
|
if (eligibleProjectIds.length === 0) return;
|
|
51518
|
-
const rows = app.db.select().from(adsOperations).where(
|
|
51651
|
+
const rows = app.db.select().from(adsOperations).where(and40(
|
|
51519
51652
|
inArray20(adsOperations.projectId, eligibleProjectIds),
|
|
51520
51653
|
staleReconcileWhere
|
|
51521
51654
|
)).orderBy(asc9(adsOperations.updatedAt)).limit(config.batchSize).all();
|
|
@@ -51836,12 +51969,12 @@ async function adsRoutes(app, opts) {
|
|
|
51836
51969
|
throw validationError("Invalid ads operation list query", { issues: parsed.error.issues });
|
|
51837
51970
|
}
|
|
51838
51971
|
const cursor = parsed.data.cursor ? decodeAdsOperationCursor(parsed.data.cursor, project.id, parsed.data.state) : void 0;
|
|
51839
|
-
const rows = app.db.select().from(adsOperations).where(
|
|
51972
|
+
const rows = app.db.select().from(adsOperations).where(and40(
|
|
51840
51973
|
eq47(adsOperations.projectId, project.id),
|
|
51841
51974
|
inArray20(adsOperations.state, parsed.data.state),
|
|
51842
51975
|
cursor ? or10(
|
|
51843
51976
|
gt3(adsOperations.createdAt, cursor.createdAt),
|
|
51844
|
-
|
|
51977
|
+
and40(
|
|
51845
51978
|
eq47(adsOperations.createdAt, cursor.createdAt),
|
|
51846
51979
|
gt3(adsOperations.id, cursor.id)
|
|
51847
51980
|
)
|
|
@@ -51885,7 +52018,7 @@ async function adsRoutes(app, opts) {
|
|
|
51885
52018
|
"/projects/:name/ads/operations/:operationKey",
|
|
51886
52019
|
async (request) => {
|
|
51887
52020
|
const project = resolveProject(app.db, request.params.name);
|
|
51888
|
-
const row = app.db.select().from(adsOperations).where(
|
|
52021
|
+
const row = app.db.select().from(adsOperations).where(and40(
|
|
51889
52022
|
eq47(adsOperations.projectId, project.id),
|
|
51890
52023
|
eq47(adsOperations.operationKey, request.params.operationKey)
|
|
51891
52024
|
)).get();
|
|
@@ -52269,7 +52402,7 @@ async function adsRoutes(app, opts) {
|
|
|
52269
52402
|
if (!row) {
|
|
52270
52403
|
throw validationError('No ads connection for this project. Run "canonry ads connect" first.');
|
|
52271
52404
|
}
|
|
52272
|
-
const inFlight = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(
|
|
52405
|
+
const inFlight = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and40(
|
|
52273
52406
|
eq47(runs.projectId, project.id),
|
|
52274
52407
|
eq47(runs.kind, RunKinds["ads-sync"]),
|
|
52275
52408
|
inArray20(runs.status, [RunStatuses.queued, RunStatuses.running])
|
|
@@ -52366,7 +52499,7 @@ async function adsRoutes(app, opts) {
|
|
|
52366
52499
|
if (entityId) conditions.push(eq47(adsInsightsDaily.entityId, entityId));
|
|
52367
52500
|
if (from) conditions.push(gte12(adsInsightsDaily.date, from));
|
|
52368
52501
|
if (to) conditions.push(lte11(adsInsightsDaily.date, to));
|
|
52369
|
-
const rows = app.db.select().from(adsInsightsDaily).where(
|
|
52502
|
+
const rows = app.db.select().from(adsInsightsDaily).where(and40(...conditions)).orderBy(asc9(adsInsightsDaily.date)).all();
|
|
52370
52503
|
const conn = app.db.select().from(adsConnections).where(eq47(adsConnections.projectId, project.id)).get();
|
|
52371
52504
|
const accountToday = adsAccountToday(conn?.timezone, (/* @__PURE__ */ new Date()).toISOString());
|
|
52372
52505
|
const dtoRows = rows.map((row) => ({
|
|
@@ -52393,11 +52526,11 @@ async function adsRoutes(app, opts) {
|
|
|
52393
52526
|
const entityRows = [...campaignRows, ...adGroupRows, ...adRows];
|
|
52394
52527
|
const hasEntityWithoutSyncRunId = entityRows.some((row) => row.syncRunId === null);
|
|
52395
52528
|
const entitySyncRunIds = new Set(entityRows.flatMap((row) => row.syncRunId === null ? [] : [row.syncRunId]));
|
|
52396
|
-
const sourceSync = entitySyncRunIds.size === 1 ? app.db.select({ id: runs.id, kind: runs.kind, status: runs.status }).from(runs).where(
|
|
52529
|
+
const sourceSync = entitySyncRunIds.size === 1 ? app.db.select({ id: runs.id, kind: runs.kind, status: runs.status }).from(runs).where(and40(
|
|
52397
52530
|
eq47(runs.id, [...entitySyncRunIds][0]),
|
|
52398
52531
|
eq47(runs.projectId, project.id)
|
|
52399
52532
|
)).get() : void 0;
|
|
52400
|
-
const latestAdsSync = app.db.select({ id: runs.id, kind: runs.kind, status: runs.status }).from(runs).where(
|
|
52533
|
+
const latestAdsSync = app.db.select({ id: runs.id, kind: runs.kind, status: runs.status }).from(runs).where(and40(
|
|
52401
52534
|
eq47(runs.projectId, project.id),
|
|
52402
52535
|
eq47(runs.kind, RunKinds["ads-sync"])
|
|
52403
52536
|
)).orderBy(desc21(runs.createdAt)).get();
|
|
@@ -52416,7 +52549,7 @@ async function adsRoutes(app, opts) {
|
|
|
52416
52549
|
clicks: adsInsightsDaily.clicks,
|
|
52417
52550
|
spendMicros: adsInsightsDaily.spendMicros,
|
|
52418
52551
|
conversions: adsInsightsDaily.conversions
|
|
52419
|
-
}).from(adsInsightsDaily).where(
|
|
52552
|
+
}).from(adsInsightsDaily).where(and40(
|
|
52420
52553
|
eq47(adsInsightsDaily.projectId, project.id),
|
|
52421
52554
|
eq47(adsInsightsDaily.level, AdsInsightLevels.campaign)
|
|
52422
52555
|
)).all();
|
|
@@ -52569,11 +52702,11 @@ async function adsRoutes(app, opts) {
|
|
|
52569
52702
|
const scopedCampaigns = campaignId === void 0 ? liveCampaigns : liveCampaigns.filter((campaign) => campaign.id === campaignId);
|
|
52570
52703
|
if (scopedCampaigns.length > ADS_LIVE_MAX_CAMPAIGNS) truncated = true;
|
|
52571
52704
|
const walkedCampaigns = scopedCampaigns.slice(0, ADS_LIVE_MAX_CAMPAIGNS);
|
|
52572
|
-
const storedCampaignRows = app.db.select().from(adsCampaigns).where(
|
|
52705
|
+
const storedCampaignRows = app.db.select().from(adsCampaigns).where(and40(
|
|
52573
52706
|
eq47(adsCampaigns.projectId, project.id),
|
|
52574
52707
|
campaignId === void 0 ? void 0 : eq47(adsCampaigns.id, campaignId)
|
|
52575
52708
|
)).all();
|
|
52576
|
-
const storedAdGroupRows = app.db.select().from(adsAdGroups).where(
|
|
52709
|
+
const storedAdGroupRows = app.db.select().from(adsAdGroups).where(and40(
|
|
52577
52710
|
eq47(adsAdGroups.projectId, project.id),
|
|
52578
52711
|
campaignId === void 0 ? void 0 : eq47(adsAdGroups.campaignId, campaignId)
|
|
52579
52712
|
)).all();
|
|
@@ -52755,7 +52888,7 @@ async function adsRoutes(app, opts) {
|
|
|
52755
52888
|
const campaignCount = app.db.select().from(adsCampaigns).where(eq47(adsCampaigns.projectId, project.id)).all().length;
|
|
52756
52889
|
const adGroupCount = app.db.select().from(adsAdGroups).where(eq47(adsAdGroups.projectId, project.id)).all().length;
|
|
52757
52890
|
const adCount = app.db.select().from(adsAds).where(eq47(adsAds.projectId, project.id)).all().length;
|
|
52758
|
-
const campaignInsights = app.db.select().from(adsInsightsDaily).where(
|
|
52891
|
+
const campaignInsights = app.db.select().from(adsInsightsDaily).where(and40(
|
|
52759
52892
|
eq47(adsInsightsDaily.projectId, project.id),
|
|
52760
52893
|
eq47(adsInsightsDaily.level, "campaign")
|
|
52761
52894
|
)).all();
|
|
@@ -52804,7 +52937,7 @@ async function adsRoutes(app, opts) {
|
|
|
52804
52937
|
|
|
52805
52938
|
// ../api-routes/src/bing.ts
|
|
52806
52939
|
import crypto38 from "crypto";
|
|
52807
|
-
import { eq as eq48, and as
|
|
52940
|
+
import { eq as eq48, and as and41, desc as desc22 } from "drizzle-orm";
|
|
52808
52941
|
|
|
52809
52942
|
// ../integration-bing/src/bing-client.ts
|
|
52810
52943
|
import crypto37 from "crypto";
|
|
@@ -53324,7 +53457,7 @@ async function bingRoutes(app, opts) {
|
|
|
53324
53457
|
requireConnectionStore();
|
|
53325
53458
|
const project = resolveProject(app.db, request.params.name);
|
|
53326
53459
|
const { url, limit } = request.query;
|
|
53327
|
-
const whereClause = url ?
|
|
53460
|
+
const whereClause = url ? and41(eq48(bingUrlInspections.projectId, project.id), eq48(bingUrlInspections.url, url)) : eq48(bingUrlInspections.projectId, project.id);
|
|
53328
53461
|
const filtered = app.db.select().from(bingUrlInspections).where(whereClause).orderBy(desc22(bingUrlInspections.inspectedAt)).limit(Math.max(1, Math.min(parseInt(limit ?? "100", 10) || 100, 1e3))).all();
|
|
53329
53462
|
return filtered.map((r) => ({
|
|
53330
53463
|
id: r.id,
|
|
@@ -53556,7 +53689,7 @@ async function bingRoutes(app, opts) {
|
|
|
53556
53689
|
import fs from "fs";
|
|
53557
53690
|
import path from "path";
|
|
53558
53691
|
import os from "os";
|
|
53559
|
-
import { eq as eq49, and as
|
|
53692
|
+
import { eq as eq49, and as and42 } from "drizzle-orm";
|
|
53560
53693
|
function getScreenshotDir() {
|
|
53561
53694
|
return path.join(os.homedir(), ".canonry", "screenshots");
|
|
53562
53695
|
}
|
|
@@ -53631,7 +53764,7 @@ async function cdpRoutes(app, opts) {
|
|
|
53631
53764
|
async (request, reply) => {
|
|
53632
53765
|
const project = resolveProject(app.db, request.params.name);
|
|
53633
53766
|
const { runId } = request.params;
|
|
53634
|
-
const run = app.db.select().from(runs).where(
|
|
53767
|
+
const run = app.db.select().from(runs).where(and42(eq49(runs.id, runId), eq49(runs.projectId, project.id))).get();
|
|
53635
53768
|
if (!run) {
|
|
53636
53769
|
const err = notFound("Run", runId);
|
|
53637
53770
|
return reply.code(err.statusCode).send(err.toJSON());
|
|
@@ -53728,7 +53861,7 @@ async function cdpRoutes(app, opts) {
|
|
|
53728
53861
|
|
|
53729
53862
|
// ../api-routes/src/ga.ts
|
|
53730
53863
|
import crypto39 from "crypto";
|
|
53731
|
-
import { eq as eq50, desc as desc23, and as
|
|
53864
|
+
import { eq as eq50, desc as desc23, and as and43, sql as sql18 } from "drizzle-orm";
|
|
53732
53865
|
|
|
53733
53866
|
// ../api-routes/src/ga-session-history.ts
|
|
53734
53867
|
function buildSessionHistory(landingPageDays, dailyTotals) {
|
|
@@ -53820,7 +53953,7 @@ function keepWinningDimensionRows(rows, groupKey) {
|
|
|
53820
53953
|
function persistAcquisitionMeasurement(db, input) {
|
|
53821
53954
|
const { startDate, endDate } = input.report;
|
|
53822
53955
|
db.transaction((tx) => {
|
|
53823
|
-
tx.delete(gaAcquisitionDaily).where(
|
|
53956
|
+
tx.delete(gaAcquisitionDaily).where(and43(
|
|
53824
53957
|
eq50(gaAcquisitionDaily.projectId, input.projectId),
|
|
53825
53958
|
sql18`${gaAcquisitionDaily.date} >= ${startDate}`,
|
|
53826
53959
|
sql18`${gaAcquisitionDaily.date} <= ${endDate}`
|
|
@@ -53862,7 +53995,7 @@ function persistAcquisitionMeasurement(db, input) {
|
|
|
53862
53995
|
function persistLeadMeasurement(db, input) {
|
|
53863
53996
|
const { startDate, endDate } = input.report;
|
|
53864
53997
|
db.transaction((tx) => {
|
|
53865
|
-
tx.delete(gaLeadEventsDaily).where(
|
|
53998
|
+
tx.delete(gaLeadEventsDaily).where(and43(
|
|
53866
53999
|
eq50(gaLeadEventsDaily.projectId, input.projectId),
|
|
53867
54000
|
sql18`${gaLeadEventsDaily.date} >= ${startDate}`,
|
|
53868
54001
|
sql18`${gaLeadEventsDaily.date} <= ${endDate}`
|
|
@@ -54238,7 +54371,7 @@ async function ga4Routes(app, opts) {
|
|
|
54238
54371
|
app.db.transaction((tx) => {
|
|
54239
54372
|
if (syncTraffic) {
|
|
54240
54373
|
tx.delete(gaTrafficSnapshots).where(
|
|
54241
|
-
|
|
54374
|
+
and43(
|
|
54242
54375
|
eq50(gaTrafficSnapshots.projectId, project.id),
|
|
54243
54376
|
sql18`${gaTrafficSnapshots.date} >= ${summary2.periodStart}`,
|
|
54244
54377
|
sql18`${gaTrafficSnapshots.date} <= ${summary2.periodEnd}`
|
|
@@ -54261,7 +54394,7 @@ async function ga4Routes(app, opts) {
|
|
|
54261
54394
|
}
|
|
54262
54395
|
}
|
|
54263
54396
|
tx.delete(gaDailyTotals).where(
|
|
54264
|
-
|
|
54397
|
+
and43(
|
|
54265
54398
|
eq50(gaDailyTotals.projectId, project.id),
|
|
54266
54399
|
sql18`${gaDailyTotals.date} >= ${summary2.periodStart}`,
|
|
54267
54400
|
sql18`${gaDailyTotals.date} <= ${summary2.periodEnd}`
|
|
@@ -54287,7 +54420,7 @@ async function ga4Routes(app, opts) {
|
|
|
54287
54420
|
}
|
|
54288
54421
|
if (syncAi) {
|
|
54289
54422
|
tx.delete(gaAiReferrals).where(
|
|
54290
|
-
|
|
54423
|
+
and43(
|
|
54291
54424
|
eq50(gaAiReferrals.projectId, project.id),
|
|
54292
54425
|
sql18`${gaAiReferrals.date} >= ${summary2.periodStart}`,
|
|
54293
54426
|
sql18`${gaAiReferrals.date} <= ${summary2.periodEnd}`
|
|
@@ -54319,7 +54452,7 @@ async function ga4Routes(app, opts) {
|
|
|
54319
54452
|
}
|
|
54320
54453
|
if (syncSocial) {
|
|
54321
54454
|
tx.delete(gaSocialReferrals).where(
|
|
54322
|
-
|
|
54455
|
+
and43(
|
|
54323
54456
|
eq50(gaSocialReferrals.projectId, project.id),
|
|
54324
54457
|
sql18`${gaSocialReferrals.date} >= ${summary2.periodStart}`,
|
|
54325
54458
|
sql18`${gaSocialReferrals.date} <= ${summary2.periodEnd}`
|
|
@@ -54491,7 +54624,7 @@ async function ga4Routes(app, opts) {
|
|
|
54491
54624
|
totalDirectSessions: gaTrafficWindowSummaries.totalDirectSessions,
|
|
54492
54625
|
totalUsers: gaTrafficWindowSummaries.totalUsers
|
|
54493
54626
|
}).from(gaTrafficWindowSummaries).where(
|
|
54494
|
-
|
|
54627
|
+
and43(
|
|
54495
54628
|
eq50(gaTrafficWindowSummaries.projectId, project.id),
|
|
54496
54629
|
eq50(gaTrafficWindowSummaries.windowKey, range.window)
|
|
54497
54630
|
)
|
|
@@ -54523,7 +54656,7 @@ async function ga4Routes(app, opts) {
|
|
|
54523
54656
|
totalSessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)`,
|
|
54524
54657
|
totalOrganicSessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)`,
|
|
54525
54658
|
totalUsers: sql18`COALESCE(SUM(${gaTrafficSnapshots.users}), 0)`
|
|
54526
|
-
}).from(gaTrafficSnapshots).where(
|
|
54659
|
+
}).from(gaTrafficSnapshots).where(and43(...snapshotConditions)).get();
|
|
54527
54660
|
return {
|
|
54528
54661
|
totalSessions: summed?.totalSessions ?? 0,
|
|
54529
54662
|
totalOrganicSessions: summed?.totalOrganicSessions ?? 0,
|
|
@@ -54536,21 +54669,21 @@ async function ga4Routes(app, opts) {
|
|
|
54536
54669
|
const summaryRow = denominatorRow ?? snapshotTotalsRow;
|
|
54537
54670
|
const directTotalRow = windowSummaryRow ? { totalDirectSessions: windowSummaryRow.totalDirectSessions } : app.db.select({
|
|
54538
54671
|
totalDirectSessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`
|
|
54539
|
-
}).from(gaTrafficSnapshots).where(
|
|
54672
|
+
}).from(gaTrafficSnapshots).where(and43(...snapshotConditions)).get();
|
|
54540
54673
|
const rows = app.db.select({
|
|
54541
54674
|
landingPage: sql18`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`,
|
|
54542
54675
|
sessions: sql18`SUM(${gaTrafficSnapshots.sessions})`,
|
|
54543
54676
|
organicSessions: sql18`SUM(${gaTrafficSnapshots.organicSessions})`,
|
|
54544
54677
|
directSessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)`,
|
|
54545
54678
|
users: sql18`SUM(${gaTrafficSnapshots.users})`
|
|
54546
|
-
}).from(gaTrafficSnapshots).where(
|
|
54679
|
+
}).from(gaTrafficSnapshots).where(and43(...snapshotConditions)).groupBy(sql18`COALESCE(${gaTrafficSnapshots.landingPageNormalized}, ${gaTrafficSnapshots.landingPage})`).orderBy(sql18`SUM(${gaTrafficSnapshots.sessions}) DESC`).limit(limit).all();
|
|
54547
54680
|
const aiReferralRows = app.db.select({
|
|
54548
54681
|
source: gaAiReferrals.source,
|
|
54549
54682
|
medium: gaAiReferrals.medium,
|
|
54550
54683
|
trafficClass: gaAiReferrals.trafficClass,
|
|
54551
54684
|
sourceDimension: gaAiReferrals.sourceDimension,
|
|
54552
54685
|
sessions: sql18`SUM(${gaAiReferrals.sessions})`
|
|
54553
|
-
}).from(gaAiReferrals).where(
|
|
54686
|
+
}).from(gaAiReferrals).where(and43(...aiConditions)).groupBy(gaAiReferrals.source, gaAiReferrals.medium, gaAiReferrals.trafficClass, gaAiReferrals.sourceDimension).all();
|
|
54554
54687
|
const aiReferralLandingPageRows = app.db.select({
|
|
54555
54688
|
source: gaAiReferrals.source,
|
|
54556
54689
|
medium: gaAiReferrals.medium,
|
|
@@ -54558,7 +54691,7 @@ async function ga4Routes(app, opts) {
|
|
|
54558
54691
|
sourceDimension: gaAiReferrals.sourceDimension,
|
|
54559
54692
|
landingPage: sql18`COALESCE(${gaAiReferrals.landingPageNormalized}, ${gaAiReferrals.landingPage})`,
|
|
54560
54693
|
sessions: sql18`SUM(${gaAiReferrals.sessions})`
|
|
54561
|
-
}).from(gaAiReferrals).where(
|
|
54694
|
+
}).from(gaAiReferrals).where(and43(...aiConditions)).groupBy(
|
|
54562
54695
|
gaAiReferrals.source,
|
|
54563
54696
|
gaAiReferrals.medium,
|
|
54564
54697
|
gaAiReferrals.trafficClass,
|
|
@@ -54573,7 +54706,7 @@ async function ga4Routes(app, opts) {
|
|
|
54573
54706
|
sourceDimension: gaAiReferrals.sourceDimension,
|
|
54574
54707
|
channelGroup: gaAiReferrals.channelGroup,
|
|
54575
54708
|
sessions: gaAiReferrals.sessions
|
|
54576
|
-
}).from(gaAiReferrals).where(
|
|
54709
|
+
}).from(gaAiReferrals).where(and43(...aiConditions)).all();
|
|
54577
54710
|
const aiReferrals = keepWinningDimensionRows(aiReferralRows, (r) => r.source);
|
|
54578
54711
|
const aiReferralLandingPages = keepWinningDimensionRows(
|
|
54579
54712
|
aiReferralLandingPageRows,
|
|
@@ -54590,10 +54723,10 @@ async function ga4Routes(app, opts) {
|
|
|
54590
54723
|
// dates counts a returning visitor once per day they returned. Same
|
|
54591
54724
|
// conclusion the AI-referral surfaces reached in 4.135.0.
|
|
54592
54725
|
sessions: sql18`SUM(${gaSocialReferrals.sessions})`
|
|
54593
|
-
}).from(gaSocialReferrals).where(
|
|
54726
|
+
}).from(gaSocialReferrals).where(and43(...socialConditions)).groupBy(gaSocialReferrals.source, gaSocialReferrals.medium, gaSocialReferrals.channelGroup).orderBy(sql18`SUM(${gaSocialReferrals.sessions}) DESC`).all();
|
|
54594
54727
|
const socialTotals = app.db.select({
|
|
54595
54728
|
sessions: sql18`SUM(${gaSocialReferrals.sessions})`
|
|
54596
|
-
}).from(gaSocialReferrals).where(
|
|
54729
|
+
}).from(gaSocialReferrals).where(and43(...socialConditions)).get();
|
|
54597
54730
|
const latestSync = app.db.select({ syncedAt: gaTrafficSummaries.syncedAt }).from(gaTrafficSummaries).where(eq50(gaTrafficSummaries.projectId, project.id)).orderBy(desc23(gaTrafficSummaries.syncedAt)).limit(1).get();
|
|
54598
54731
|
const total = summaryRow?.totalSessions ?? 0;
|
|
54599
54732
|
const totalDirectSessions = directTotalRow?.totalDirectSessions ?? 0;
|
|
@@ -54714,7 +54847,7 @@ async function ga4Routes(app, opts) {
|
|
|
54714
54847
|
// added up. ga4AiReferralDtoSchema.users was deprecated for this in
|
|
54715
54848
|
// 4.135.0; the history endpoint kept emitting one.
|
|
54716
54849
|
sessions: sql18`SUM(${gaAiReferrals.sessions})`
|
|
54717
|
-
}).from(gaAiReferrals).where(
|
|
54850
|
+
}).from(gaAiReferrals).where(and43(...conditions)).groupBy(
|
|
54718
54851
|
gaAiReferrals.date,
|
|
54719
54852
|
gaAiReferrals.source,
|
|
54720
54853
|
gaAiReferrals.medium,
|
|
@@ -54737,7 +54870,7 @@ async function ga4Routes(app, opts) {
|
|
|
54737
54870
|
sourceDimension: gaAiReferrals.sourceDimension,
|
|
54738
54871
|
channelGroup: gaAiReferrals.channelGroup,
|
|
54739
54872
|
sessions: gaAiReferrals.sessions
|
|
54740
|
-
}).from(gaAiReferrals).where(
|
|
54873
|
+
}).from(gaAiReferrals).where(and43(...conditions)).all();
|
|
54741
54874
|
return buildAiReferralDailySeries(rows);
|
|
54742
54875
|
});
|
|
54743
54876
|
app.get("/projects/:name/ga/social-referral-history", async (request, _reply) => {
|
|
@@ -54752,7 +54885,7 @@ async function ga4Routes(app, opts) {
|
|
|
54752
54885
|
channelGroup: gaSocialReferrals.channelGroup,
|
|
54753
54886
|
sessions: gaSocialReferrals.sessions,
|
|
54754
54887
|
users: gaSocialReferrals.users
|
|
54755
|
-
}).from(gaSocialReferrals).where(
|
|
54888
|
+
}).from(gaSocialReferrals).where(and43(...conditions)).orderBy(gaSocialReferrals.date).all();
|
|
54756
54889
|
return rows;
|
|
54757
54890
|
});
|
|
54758
54891
|
app.get("/projects/:name/ga/social-referral-trend", async (request, _reply) => {
|
|
@@ -54765,7 +54898,7 @@ async function ga4Routes(app, opts) {
|
|
|
54765
54898
|
d.setDate(d.getDate() - n);
|
|
54766
54899
|
return fmt(d);
|
|
54767
54900
|
};
|
|
54768
|
-
const sumSocial = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(
|
|
54901
|
+
const sumSocial = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and43(
|
|
54769
54902
|
eq50(gaSocialReferrals.projectId, project.id),
|
|
54770
54903
|
sql18`${gaSocialReferrals.date} >= ${from}`,
|
|
54771
54904
|
sql18`${gaSocialReferrals.date} < ${to}`
|
|
@@ -54777,7 +54910,7 @@ async function ga4Routes(app, opts) {
|
|
|
54777
54910
|
const sourceCurrent = app.db.select({
|
|
54778
54911
|
source: gaSocialReferrals.source,
|
|
54779
54912
|
sessions: sql18`SUM(${gaSocialReferrals.sessions})`
|
|
54780
|
-
}).from(gaSocialReferrals).where(
|
|
54913
|
+
}).from(gaSocialReferrals).where(and43(
|
|
54781
54914
|
eq50(gaSocialReferrals.projectId, project.id),
|
|
54782
54915
|
sql18`${gaSocialReferrals.date} >= ${daysAgo(7)}`,
|
|
54783
54916
|
sql18`${gaSocialReferrals.date} < ${fmt(today)}`
|
|
@@ -54785,7 +54918,7 @@ async function ga4Routes(app, opts) {
|
|
|
54785
54918
|
const sourcePrev = app.db.select({
|
|
54786
54919
|
source: gaSocialReferrals.source,
|
|
54787
54920
|
sessions: sql18`SUM(${gaSocialReferrals.sessions})`
|
|
54788
|
-
}).from(gaSocialReferrals).where(
|
|
54921
|
+
}).from(gaSocialReferrals).where(and43(
|
|
54789
54922
|
eq50(gaSocialReferrals.projectId, project.id),
|
|
54790
54923
|
sql18`${gaSocialReferrals.date} >= ${daysAgo(14)}`,
|
|
54791
54924
|
sql18`${gaSocialReferrals.date} < ${daysAgo(7)}`
|
|
@@ -54826,16 +54959,16 @@ async function ga4Routes(app, opts) {
|
|
|
54826
54959
|
d.setDate(d.getDate() - n);
|
|
54827
54960
|
return fmt(d);
|
|
54828
54961
|
};
|
|
54829
|
-
const sumTotal = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)` }).from(gaTrafficSnapshots).where(
|
|
54830
|
-
const sumOrganic = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)` }).from(gaTrafficSnapshots).where(
|
|
54831
|
-
const sumDirect = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)` }).from(gaTrafficSnapshots).where(
|
|
54832
|
-
const sumAi = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(
|
|
54962
|
+
const sumTotal = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.sessions}), 0)` }).from(gaTrafficSnapshots).where(and43(eq50(gaTrafficSnapshots.projectId, project.id), sql18`${gaTrafficSnapshots.date} >= ${from}`, sql18`${gaTrafficSnapshots.date} < ${to}`)).get();
|
|
54963
|
+
const sumOrganic = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.organicSessions}), 0)` }).from(gaTrafficSnapshots).where(and43(eq50(gaTrafficSnapshots.projectId, project.id), sql18`${gaTrafficSnapshots.date} >= ${from}`, sql18`${gaTrafficSnapshots.date} < ${to}`)).get();
|
|
54964
|
+
const sumDirect = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaTrafficSnapshots.directSessions}), 0)` }).from(gaTrafficSnapshots).where(and43(eq50(gaTrafficSnapshots.projectId, project.id), sql18`${gaTrafficSnapshots.date} >= ${from}`, sql18`${gaTrafficSnapshots.date} < ${to}`)).get();
|
|
54965
|
+
const sumAi = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and43(
|
|
54833
54966
|
eq50(gaAiReferrals.projectId, project.id),
|
|
54834
54967
|
sql18`${gaAiReferrals.date} >= ${from}`,
|
|
54835
54968
|
sql18`${gaAiReferrals.date} < ${to}`,
|
|
54836
54969
|
eq50(gaAiReferrals.sourceDimension, "session")
|
|
54837
54970
|
)).get();
|
|
54838
|
-
const sumSocial = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(
|
|
54971
|
+
const sumSocial = (from, to) => app.db.select({ sessions: sql18`COALESCE(SUM(${gaSocialReferrals.sessions}), 0)` }).from(gaSocialReferrals).where(and43(eq50(gaSocialReferrals.projectId, project.id), sql18`${gaSocialReferrals.date} >= ${from}`, sql18`${gaSocialReferrals.date} < ${to}`)).get();
|
|
54839
54972
|
const todayStr = fmt(today);
|
|
54840
54973
|
const buildTrend = (sum) => {
|
|
54841
54974
|
const c7 = sum(daysAgo(7), todayStr)?.sessions ?? 0;
|
|
@@ -54844,13 +54977,13 @@ async function ga4Routes(app, opts) {
|
|
|
54844
54977
|
const p30 = sum(daysAgo(60), daysAgo(30))?.sessions ?? 0;
|
|
54845
54978
|
return { sessions7d: c7, sessionsPrev7d: p7, trend7dPct: deltaPercent(c7, p7), sessions30d: c30, sessionsPrev30d: p30, trend30dPct: deltaPercent(c30, p30) };
|
|
54846
54979
|
};
|
|
54847
|
-
const aiSourceCurrent = app.db.select({ source: gaAiReferrals.source, sessions: sql18`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(
|
|
54980
|
+
const aiSourceCurrent = app.db.select({ source: gaAiReferrals.source, sessions: sql18`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and43(
|
|
54848
54981
|
eq50(gaAiReferrals.projectId, project.id),
|
|
54849
54982
|
sql18`${gaAiReferrals.date} >= ${daysAgo(7)}`,
|
|
54850
54983
|
sql18`${gaAiReferrals.date} < ${todayStr}`,
|
|
54851
54984
|
eq50(gaAiReferrals.sourceDimension, "session")
|
|
54852
54985
|
)).groupBy(gaAiReferrals.source).all();
|
|
54853
|
-
const aiSourcePrev = app.db.select({ source: gaAiReferrals.source, sessions: sql18`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(
|
|
54986
|
+
const aiSourcePrev = app.db.select({ source: gaAiReferrals.source, sessions: sql18`COALESCE(SUM(${gaAiReferrals.sessions}), 0)` }).from(gaAiReferrals).where(and43(
|
|
54854
54987
|
eq50(gaAiReferrals.projectId, project.id),
|
|
54855
54988
|
sql18`${gaAiReferrals.date} >= ${daysAgo(14)}`,
|
|
54856
54989
|
sql18`${gaAiReferrals.date} < ${daysAgo(7)}`,
|
|
@@ -54870,8 +55003,8 @@ async function ga4Routes(app, opts) {
|
|
|
54870
55003
|
}
|
|
54871
55004
|
return mover;
|
|
54872
55005
|
};
|
|
54873
|
-
const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions: sql18`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(
|
|
54874
|
-
const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions: sql18`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(
|
|
55006
|
+
const socialSourceCurrent = app.db.select({ source: gaSocialReferrals.source, sessions: sql18`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and43(eq50(gaSocialReferrals.projectId, project.id), sql18`${gaSocialReferrals.date} >= ${daysAgo(7)}`, sql18`${gaSocialReferrals.date} < ${todayStr}`)).groupBy(gaSocialReferrals.source).all();
|
|
55007
|
+
const socialSourcePrev = app.db.select({ source: gaSocialReferrals.source, sessions: sql18`SUM(${gaSocialReferrals.sessions})` }).from(gaSocialReferrals).where(and43(eq50(gaSocialReferrals.projectId, project.id), sql18`${gaSocialReferrals.date} >= ${daysAgo(14)}`, sql18`${gaSocialReferrals.date} < ${daysAgo(7)}`)).groupBy(gaSocialReferrals.source).all();
|
|
54875
55008
|
return {
|
|
54876
55009
|
total: buildTrend(sumTotal),
|
|
54877
55010
|
organic: buildTrend(sumOrganic),
|
|
@@ -54892,9 +55025,9 @@ async function ga4Routes(app, opts) {
|
|
|
54892
55025
|
sessions: sql18`SUM(${gaTrafficSnapshots.sessions})`,
|
|
54893
55026
|
organicSessions: sql18`SUM(${gaTrafficSnapshots.organicSessions})`,
|
|
54894
55027
|
users: sql18`SUM(${gaTrafficSnapshots.users})`
|
|
54895
|
-
}).from(gaTrafficSnapshots).where(
|
|
55028
|
+
}).from(gaTrafficSnapshots).where(and43(...conditions)).groupBy(gaTrafficSnapshots.date).orderBy(gaTrafficSnapshots.date).all();
|
|
54896
55029
|
const totalConditions = [eq50(gaDailyTotals.projectId, project.id), ...dateRangeConditions(gaDailyTotals.date, range)];
|
|
54897
|
-
const totals = app.db.select({ date: gaDailyTotals.date, users: gaDailyTotals.users }).from(gaDailyTotals).where(
|
|
55030
|
+
const totals = app.db.select({ date: gaDailyTotals.date, users: gaDailyTotals.users }).from(gaDailyTotals).where(and43(...totalConditions)).all();
|
|
54898
55031
|
return buildSessionHistory(
|
|
54899
55032
|
rows.map((r) => ({
|
|
54900
55033
|
date: r.date,
|
|
@@ -56568,7 +56701,7 @@ async function wordpressRoutes(app, opts) {
|
|
|
56568
56701
|
|
|
56569
56702
|
// ../api-routes/src/backlinks.ts
|
|
56570
56703
|
import crypto41 from "crypto";
|
|
56571
|
-
import { and as
|
|
56704
|
+
import { and as and45, asc as asc10, desc as desc24, eq as eq51, sql as sql19 } from "drizzle-orm";
|
|
56572
56705
|
|
|
56573
56706
|
// ../integration-commoncrawl/src/constants.ts
|
|
56574
56707
|
import os2 from "os";
|
|
@@ -56971,7 +57104,7 @@ function pruneCachedRelease(release, opts = {}) {
|
|
|
56971
57104
|
}
|
|
56972
57105
|
|
|
56973
57106
|
// ../api-routes/src/backlinks-filter.ts
|
|
56974
|
-
import { and as
|
|
57107
|
+
import { and as and44, ne as ne8, notLike } from "drizzle-orm";
|
|
56975
57108
|
var BACKLINK_FILTER_PATTERNS = [
|
|
56976
57109
|
"*.google.com",
|
|
56977
57110
|
"*.googleusercontent.com",
|
|
@@ -56994,7 +57127,7 @@ function backlinkCrawlerExclusionClause() {
|
|
|
56994
57127
|
conditions.push(ne8(backlinkDomains.linkingDomain, pattern));
|
|
56995
57128
|
}
|
|
56996
57129
|
}
|
|
56997
|
-
const combined =
|
|
57130
|
+
const combined = and44(...conditions);
|
|
56998
57131
|
if (!combined) throw new Error("BACKLINK_FILTER_PATTERNS is unexpectedly empty");
|
|
56999
57132
|
return combined;
|
|
57000
57133
|
}
|
|
@@ -57069,7 +57202,7 @@ function latestSummaryForProject(db, projectId, source, release) {
|
|
|
57069
57202
|
eq51(backlinkSummaries.source, source)
|
|
57070
57203
|
];
|
|
57071
57204
|
if (release) conditions.push(eq51(backlinkSummaries.release, release));
|
|
57072
|
-
return db.select().from(backlinkSummaries).where(
|
|
57205
|
+
return db.select().from(backlinkSummaries).where(and45(...conditions)).orderBy(desc24(backlinkSummaries.queriedAt)).limit(1).get();
|
|
57073
57206
|
}
|
|
57074
57207
|
function parseExcludeCrawlers(value) {
|
|
57075
57208
|
if (!value) return false;
|
|
@@ -57077,12 +57210,12 @@ function parseExcludeCrawlers(value) {
|
|
|
57077
57210
|
return lower === "1" || lower === "true" || lower === "yes";
|
|
57078
57211
|
}
|
|
57079
57212
|
function computeFilteredSummary(db, base) {
|
|
57080
|
-
const baseDomainCondition =
|
|
57213
|
+
const baseDomainCondition = and45(
|
|
57081
57214
|
eq51(backlinkDomains.projectId, base.projectId),
|
|
57082
57215
|
eq51(backlinkDomains.source, base.source),
|
|
57083
57216
|
eq51(backlinkDomains.release, base.release)
|
|
57084
57217
|
);
|
|
57085
|
-
const filteredCondition =
|
|
57218
|
+
const filteredCondition = and45(baseDomainCondition, backlinkCrawlerExclusionClause());
|
|
57086
57219
|
const unfilteredAgg = db.select({
|
|
57087
57220
|
count: sql19`count(*)`,
|
|
57088
57221
|
total: sql19`coalesce(sum(${backlinkDomains.numHosts}), 0)`
|
|
@@ -57112,10 +57245,10 @@ function computeFilteredSummary(db, base) {
|
|
|
57112
57245
|
};
|
|
57113
57246
|
}
|
|
57114
57247
|
function buildSourceAvailability(db, projectId, source, connected, excludeCrawlers) {
|
|
57115
|
-
const summary2 = db.select().from(backlinkSummaries).where(
|
|
57248
|
+
const summary2 = db.select().from(backlinkSummaries).where(and45(eq51(backlinkSummaries.projectId, projectId), eq51(backlinkSummaries.source, source))).orderBy(desc24(backlinkSummaries.queriedAt)).limit(1).get();
|
|
57116
57249
|
let totalLinkingDomains = summary2?.totalLinkingDomains ?? 0;
|
|
57117
57250
|
if (summary2 && excludeCrawlers) {
|
|
57118
|
-
const filtered = db.select({ count: sql19`count(*)` }).from(backlinkDomains).where(
|
|
57251
|
+
const filtered = db.select({ count: sql19`count(*)` }).from(backlinkDomains).where(and45(
|
|
57119
57252
|
eq51(backlinkDomains.projectId, projectId),
|
|
57120
57253
|
eq51(backlinkDomains.source, source),
|
|
57121
57254
|
eq51(backlinkDomains.release, summary2.release),
|
|
@@ -57297,12 +57430,12 @@ async function backlinksRoutes(app, opts) {
|
|
|
57297
57430
|
const limit = Math.min(Math.max(parseInt(request.query.limit ?? "50", 10) || 50, 1), 500);
|
|
57298
57431
|
const offset = Math.max(parseInt(request.query.offset ?? "0", 10) || 0, 0);
|
|
57299
57432
|
const excludeCrawlers = parseExcludeCrawlers(request.query.excludeCrawlers);
|
|
57300
|
-
const baseDomainCondition =
|
|
57433
|
+
const baseDomainCondition = and45(
|
|
57301
57434
|
eq51(backlinkDomains.projectId, project.id),
|
|
57302
57435
|
eq51(backlinkDomains.source, source),
|
|
57303
57436
|
eq51(backlinkDomains.release, targetRelease)
|
|
57304
57437
|
);
|
|
57305
|
-
const domainCondition = excludeCrawlers ?
|
|
57438
|
+
const domainCondition = excludeCrawlers ? and45(baseDomainCondition, backlinkCrawlerExclusionClause()) : baseDomainCondition;
|
|
57306
57439
|
const totalRow = app.db.select({ count: sql19`count(*)` }).from(backlinkDomains).where(domainCondition).get();
|
|
57307
57440
|
const rows = app.db.select({
|
|
57308
57441
|
linkingDomain: backlinkDomains.linkingDomain,
|
|
@@ -57326,7 +57459,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
57326
57459
|
async (request, reply) => {
|
|
57327
57460
|
const project = resolveProject(app.db, request.params.name);
|
|
57328
57461
|
const source = parseSourceParam(request.query.source);
|
|
57329
|
-
const rows = app.db.select().from(backlinkSummaries).where(
|
|
57462
|
+
const rows = app.db.select().from(backlinkSummaries).where(and45(eq51(backlinkSummaries.projectId, project.id), eq51(backlinkSummaries.source, source))).orderBy(asc10(backlinkSummaries.queriedAt)).all();
|
|
57330
57463
|
const response = rows.map((r) => ({
|
|
57331
57464
|
release: r.release,
|
|
57332
57465
|
totalLinkingDomains: r.totalLinkingDomains,
|
|
@@ -57354,7 +57487,7 @@ import crypto44 from "crypto";
|
|
|
57354
57487
|
import { isIP } from "net";
|
|
57355
57488
|
import { isDeepStrictEqual } from "util";
|
|
57356
57489
|
import { Agent as UndiciAgent } from "undici";
|
|
57357
|
-
import { and as
|
|
57490
|
+
import { and as and49, desc as desc25, eq as eq55, gte as gte14, inArray as inArray21, lte as lte14, sql as sql22 } from "drizzle-orm";
|
|
57358
57491
|
|
|
57359
57492
|
// ../api-routes/src/cloudflare-worker-version.ts
|
|
57360
57493
|
var CURRENT_CLOUDFLARE_WORKER_VERSION = "1.0.1";
|
|
@@ -74025,10 +74158,10 @@ async function ackCloudflareQueueMessages(client, options) {
|
|
|
74025
74158
|
|
|
74026
74159
|
// ../api-routes/src/traffic-event-ingest.ts
|
|
74027
74160
|
import crypto43 from "crypto";
|
|
74028
|
-
import { and as
|
|
74161
|
+
import { and as and47, eq as eq53, gte as gte13, lt as lt9, lte as lte12, sql as sql21 } from "drizzle-orm";
|
|
74029
74162
|
|
|
74030
74163
|
// ../api-routes/src/raw-event-sample-retention.ts
|
|
74031
|
-
import { and as
|
|
74164
|
+
import { and as and46, eq as eq52, lt as lt8, sql as sql20 } from "drizzle-orm";
|
|
74032
74165
|
var RAW_EVENT_SAMPLE_RETENTION_MS = 30 * 24 * 60 * 6e4;
|
|
74033
74166
|
var RAW_EVENT_SAMPLE_RETENTION_SWEEP_INTERVAL_MS = 24 * 60 * 6e4;
|
|
74034
74167
|
var CANONICAL_UTC_TIMESTAMP_GLOB = "[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9]Z";
|
|
@@ -74039,13 +74172,13 @@ function rawEventSampleRetentionCutoff(referenceAt) {
|
|
|
74039
74172
|
}
|
|
74040
74173
|
function deleteExpiredRawEventSamples(db, cutoff, sourceId) {
|
|
74041
74174
|
const sourceScope = sourceId === void 0 ? void 0 : eq52(rawEventSamples.sourceId, sourceId);
|
|
74042
|
-
db.delete(rawEventSamples).where(
|
|
74043
|
-
db.delete(rawEventSamples).where(
|
|
74175
|
+
db.delete(rawEventSamples).where(and46(sourceScope, sql20`julianday(${rawEventSamples.ts}) IS NULL`)).run();
|
|
74176
|
+
db.delete(rawEventSamples).where(and46(
|
|
74044
74177
|
sourceScope,
|
|
74045
74178
|
sql20`${rawEventSamples.ts} GLOB ${CANONICAL_UTC_TIMESTAMP_GLOB}`,
|
|
74046
74179
|
lt8(rawEventSamples.ts, cutoff)
|
|
74047
74180
|
)).run();
|
|
74048
|
-
db.delete(rawEventSamples).where(
|
|
74181
|
+
db.delete(rawEventSamples).where(and46(
|
|
74049
74182
|
sourceScope,
|
|
74050
74183
|
sql20`${rawEventSamples.ts} NOT GLOB ${CANONICAL_UTC_TIMESTAMP_GLOB}`,
|
|
74051
74184
|
sql20`julianday(${rawEventSamples.ts}) < julianday(${cutoff})`
|
|
@@ -74102,7 +74235,7 @@ function writeTrafficEventBatch(opts) {
|
|
|
74102
74235
|
opts.sourceId,
|
|
74103
74236
|
opts.receivedAt
|
|
74104
74237
|
);
|
|
74105
|
-
tx.delete(trafficEventReceipts).where(
|
|
74238
|
+
tx.delete(trafficEventReceipts).where(and47(
|
|
74106
74239
|
eq53(trafficEventReceipts.sourceId, opts.sourceId),
|
|
74107
74240
|
lte12(trafficEventReceipts.expiresAt, opts.receivedAt)
|
|
74108
74241
|
)).run();
|
|
@@ -74302,7 +74435,7 @@ function writeTrafficEventBatch(opts) {
|
|
|
74302
74435
|
if (!hour || hourlySampleLimit === 0) continue;
|
|
74303
74436
|
let remaining = remainingSamplesByHour.get(hour.start);
|
|
74304
74437
|
if (remaining === void 0) {
|
|
74305
|
-
const existing = tx.select({ total: sql21`COUNT(*)` }).from(rawEventSamples).where(
|
|
74438
|
+
const existing = tx.select({ total: sql21`COUNT(*)` }).from(rawEventSamples).where(and47(
|
|
74306
74439
|
eq53(rawEventSamples.sourceId, opts.sourceId),
|
|
74307
74440
|
gte13(rawEventSamples.ts, hour.start),
|
|
74308
74441
|
lt9(rawEventSamples.ts, hour.end)
|
|
@@ -74362,7 +74495,7 @@ function writeTrafficEventBatch(opts) {
|
|
|
74362
74495
|
}
|
|
74363
74496
|
|
|
74364
74497
|
// ../api-routes/src/traffic-sync-lease.ts
|
|
74365
|
-
import { and as
|
|
74498
|
+
import { and as and48, eq as eq54, isNull as isNull9, lte as lte13, or as or11 } from "drizzle-orm";
|
|
74366
74499
|
function leaseExpiresAt(now, ttlMs) {
|
|
74367
74500
|
const nowMs = Date.parse(now);
|
|
74368
74501
|
if (!Number.isFinite(nowMs)) throw new RangeError("Traffic sync lease now must be an ISO instant");
|
|
@@ -74375,7 +74508,7 @@ function tryClaimTrafficSyncLease(input) {
|
|
|
74375
74508
|
const changed = tx.update(trafficSources).set({
|
|
74376
74509
|
syncLeaseOwner: input.owner,
|
|
74377
74510
|
syncLeaseExpiresAt: expiresAt
|
|
74378
|
-
}).where(
|
|
74511
|
+
}).where(and48(
|
|
74379
74512
|
eq54(trafficSources.id, input.sourceId),
|
|
74380
74513
|
or11(
|
|
74381
74514
|
isNull9(trafficSources.syncLeaseOwner),
|
|
@@ -74391,7 +74524,7 @@ function releaseTrafficSyncLease(input) {
|
|
|
74391
74524
|
const changed = tx.update(trafficSources).set({
|
|
74392
74525
|
syncLeaseOwner: null,
|
|
74393
74526
|
syncLeaseExpiresAt: null
|
|
74394
|
-
}).where(
|
|
74527
|
+
}).where(and48(
|
|
74395
74528
|
eq54(trafficSources.id, input.sourceId),
|
|
74396
74529
|
eq54(trafficSources.syncLeaseOwner, input.owner)
|
|
74397
74530
|
)).run();
|
|
@@ -74741,7 +74874,7 @@ function wordpressBaseUrlIdentity(value) {
|
|
|
74741
74874
|
}
|
|
74742
74875
|
}
|
|
74743
74876
|
function bindTrafficSyncSchedule(tx, projectId, sourceId, now, createIfMissing = true) {
|
|
74744
|
-
const schedule = tx.select().from(schedules).where(
|
|
74877
|
+
const schedule = tx.select().from(schedules).where(and49(
|
|
74745
74878
|
eq55(schedules.projectId, projectId),
|
|
74746
74879
|
eq55(schedules.kind, SchedulableRunKinds["traffic-sync"])
|
|
74747
74880
|
)).get();
|
|
@@ -74873,28 +75006,28 @@ async function runBackfillTask(options) {
|
|
|
74873
75006
|
finishedAt
|
|
74874
75007
|
);
|
|
74875
75008
|
tx.delete(crawlerEventsHourly).where(
|
|
74876
|
-
|
|
75009
|
+
and49(
|
|
74877
75010
|
eq55(crawlerEventsHourly.sourceId, sourceRow2.id),
|
|
74878
75011
|
gte14(crawlerEventsHourly.tsHour, windowStartIso),
|
|
74879
75012
|
lte14(crawlerEventsHourly.tsHour, windowEndIso)
|
|
74880
75013
|
)
|
|
74881
75014
|
).run();
|
|
74882
75015
|
tx.delete(aiUserFetchEventsHourly).where(
|
|
74883
|
-
|
|
75016
|
+
and49(
|
|
74884
75017
|
eq55(aiUserFetchEventsHourly.sourceId, sourceRow2.id),
|
|
74885
75018
|
gte14(aiUserFetchEventsHourly.tsHour, windowStartIso),
|
|
74886
75019
|
lte14(aiUserFetchEventsHourly.tsHour, windowEndIso)
|
|
74887
75020
|
)
|
|
74888
75021
|
).run();
|
|
74889
75022
|
tx.delete(aiReferralEventsHourly).where(
|
|
74890
|
-
|
|
75023
|
+
and49(
|
|
74891
75024
|
eq55(aiReferralEventsHourly.sourceId, sourceRow2.id),
|
|
74892
75025
|
gte14(aiReferralEventsHourly.tsHour, windowStartIso),
|
|
74893
75026
|
lte14(aiReferralEventsHourly.tsHour, windowEndIso)
|
|
74894
75027
|
)
|
|
74895
75028
|
).run();
|
|
74896
75029
|
tx.delete(rawEventSamples).where(
|
|
74897
|
-
|
|
75030
|
+
and49(
|
|
74898
75031
|
eq55(rawEventSamples.sourceId, sourceRow2.id),
|
|
74899
75032
|
gte14(rawEventSamples.ts, windowStartIso),
|
|
74900
75033
|
lte14(rawEventSamples.ts, windowEndIso)
|
|
@@ -75756,7 +75889,7 @@ async function trafficRoutes(app, opts) {
|
|
|
75756
75889
|
}
|
|
75757
75890
|
let removed = false;
|
|
75758
75891
|
if (row.status === TrafficSourceStatuses.connected) {
|
|
75759
|
-
const schedule = tx.select().from(schedules).where(
|
|
75892
|
+
const schedule = tx.select().from(schedules).where(and49(
|
|
75760
75893
|
eq55(schedules.projectId, project.id),
|
|
75761
75894
|
eq55(schedules.kind, SchedulableRunKinds["traffic-sync"])
|
|
75762
75895
|
)).get();
|
|
@@ -75842,7 +75975,7 @@ async function trafficRoutes(app, opts) {
|
|
|
75842
75975
|
bindTrafficSyncSchedule(tx, project.id, target.id, now);
|
|
75843
75976
|
scheduleAction = "upsert";
|
|
75844
75977
|
} else {
|
|
75845
|
-
const schedule = tx.select().from(schedules).where(
|
|
75978
|
+
const schedule = tx.select().from(schedules).where(and49(
|
|
75846
75979
|
eq55(schedules.projectId, project.id),
|
|
75847
75980
|
eq55(schedules.kind, SchedulableRunKinds["traffic-sync"])
|
|
75848
75981
|
)).get();
|
|
@@ -76191,7 +76324,7 @@ async function trafficRoutes(app, opts) {
|
|
|
76191
76324
|
tx.update(runs).set({ status: RunStatuses.failed, error: safeError, finishedAt: failedAt }).where(eq55(runs.id, runId)).run();
|
|
76192
76325
|
const latestSource = tx.select().from(trafficSources).where(eq55(trafficSources.id, sourceRow2.id)).get();
|
|
76193
76326
|
if (latestSource && latestSource.status === TrafficSourceStatuses.connected && latestSource.syncLeaseOwner === leaseOwner && isDeepStrictEqual(latestSource.configJson, sourceRow2.configJson)) {
|
|
76194
|
-
tx.update(trafficSources).set({ lastError: safeError, updatedAt: failedAt }).where(
|
|
76327
|
+
tx.update(trafficSources).set({ lastError: safeError, updatedAt: failedAt }).where(and49(
|
|
76195
76328
|
eq55(trafficSources.id, sourceRow2.id),
|
|
76196
76329
|
eq55(trafficSources.status, TrafficSourceStatuses.connected),
|
|
76197
76330
|
eq55(trafficSources.syncLeaseOwner, leaseOwner)
|
|
@@ -77059,7 +77192,7 @@ async function trafficRoutes(app, opts) {
|
|
|
77059
77192
|
pathNormalized: crawlerEventsHourly.pathNormalized,
|
|
77060
77193
|
hits: sql22`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
77061
77194
|
}).from(crawlerEventsHourly).where(
|
|
77062
|
-
|
|
77195
|
+
and49(
|
|
77063
77196
|
eq55(crawlerEventsHourly.sourceId, row.id),
|
|
77064
77197
|
gte14(crawlerEventsHourly.tsHour, since)
|
|
77065
77198
|
)
|
|
@@ -77069,7 +77202,7 @@ async function trafficRoutes(app, opts) {
|
|
|
77069
77202
|
);
|
|
77070
77203
|
const crawlerTotal = crawlerSegments.content + crawlerSegments.sitemap + crawlerSegments.robots + crawlerSegments.asset + crawlerSegments.other;
|
|
77071
77204
|
const aiUserFetchTotals = app.db.select({ total: sql22`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
77072
|
-
|
|
77205
|
+
and49(
|
|
77073
77206
|
eq55(aiUserFetchEventsHourly.sourceId, row.id),
|
|
77074
77207
|
gte14(aiUserFetchEventsHourly.tsHour, since)
|
|
77075
77208
|
)
|
|
@@ -77079,19 +77212,19 @@ async function trafficRoutes(app, opts) {
|
|
|
77079
77212
|
nonhop: sql22`COALESCE(SUM(CASE WHEN ${referralLandedCondition()} THEN ${aiReferralEventsHourly.sessionsOrHits} ELSE 0 END), 0)`,
|
|
77080
77213
|
landed: sql22`COALESCE(SUM(CASE WHEN ${countableReferralCondition()} THEN ${aiReferralEventsHourly.sessionsOrHits} ELSE 0 END), 0)`
|
|
77081
77214
|
}).from(aiReferralEventsHourly).where(
|
|
77082
|
-
|
|
77215
|
+
and49(
|
|
77083
77216
|
eq55(aiReferralEventsHourly.sourceId, row.id),
|
|
77084
77217
|
gte14(aiReferralEventsHourly.tsHour, since)
|
|
77085
77218
|
)
|
|
77086
77219
|
).get();
|
|
77087
77220
|
const sampleTotals = app.db.select({ total: sql22`COUNT(*)` }).from(rawEventSamples).where(
|
|
77088
|
-
|
|
77221
|
+
and49(
|
|
77089
77222
|
eq55(rawEventSamples.sourceId, row.id),
|
|
77090
77223
|
gte14(rawEventSamples.ts, since)
|
|
77091
77224
|
)
|
|
77092
77225
|
).get();
|
|
77093
77226
|
const latestRun = app.db.select().from(runs).where(
|
|
77094
|
-
|
|
77227
|
+
and49(
|
|
77095
77228
|
eq55(runs.projectId, projectId),
|
|
77096
77229
|
eq55(runs.kind, RunKinds["traffic-sync"]),
|
|
77097
77230
|
eq55(runs.sourceId, row.id)
|
|
@@ -77130,7 +77263,7 @@ async function trafficRoutes(app, opts) {
|
|
|
77130
77263
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
77131
77264
|
let updatedRow;
|
|
77132
77265
|
app.db.transaction((tx) => {
|
|
77133
|
-
const sourceRow2 = tx.select().from(trafficSources).where(
|
|
77266
|
+
const sourceRow2 = tx.select().from(trafficSources).where(and49(eq55(trafficSources.projectId, project.id), eq55(trafficSources.id, request.params.id))).get();
|
|
77134
77267
|
if (!sourceRow2) {
|
|
77135
77268
|
throw notFound("traffic source", request.params.id);
|
|
77136
77269
|
}
|
|
@@ -77270,7 +77403,7 @@ async function trafficRoutes(app, opts) {
|
|
|
77270
77403
|
lte14(crawlerEventsHourly.tsHour, untilIso)
|
|
77271
77404
|
];
|
|
77272
77405
|
if (sourceIdParam) crawlerFilters.push(eq55(crawlerEventsHourly.sourceId, sourceIdParam));
|
|
77273
|
-
const crawlerWhere =
|
|
77406
|
+
const crawlerWhere = and49(...crawlerFilters);
|
|
77274
77407
|
const pathTotals = app.db.select({
|
|
77275
77408
|
pathNormalized: crawlerEventsHourly.pathNormalized,
|
|
77276
77409
|
hits: sql22`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`,
|
|
@@ -77345,7 +77478,7 @@ async function trafficRoutes(app, opts) {
|
|
|
77345
77478
|
lte14(aiUserFetchEventsHourly.tsHour, untilIso)
|
|
77346
77479
|
];
|
|
77347
77480
|
if (sourceIdParam) userFetchFilters.push(eq55(aiUserFetchEventsHourly.sourceId, sourceIdParam));
|
|
77348
|
-
const userFetchWhere =
|
|
77481
|
+
const userFetchWhere = and49(...userFetchFilters);
|
|
77349
77482
|
const total = app.db.select({
|
|
77350
77483
|
total: sql22`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`,
|
|
77351
77484
|
rows: sql22`COUNT(*)`
|
|
@@ -77384,7 +77517,7 @@ async function trafficRoutes(app, opts) {
|
|
|
77384
77517
|
lte14(aiReferralEventsHourly.tsHour, untilIso)
|
|
77385
77518
|
];
|
|
77386
77519
|
if (sourceIdParam) aiFilters.push(eq55(aiReferralEventsHourly.sourceId, sourceIdParam));
|
|
77387
|
-
const aiWhere =
|
|
77520
|
+
const aiWhere = and49(...aiFilters);
|
|
77388
77521
|
const total = app.db.select({
|
|
77389
77522
|
total: sql22`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
|
|
77390
77523
|
nonhop: sql22`COALESCE(SUM(CASE WHEN ${referralLandedCondition()} THEN ${aiReferralEventsHourly.sessionsOrHits} ELSE 0 END), 0)`,
|
|
@@ -77459,7 +77592,7 @@ async function trafficRoutes(app, opts) {
|
|
|
77459
77592
|
windowEnd: untilIso,
|
|
77460
77593
|
series: (() => {
|
|
77461
77594
|
const points = completeTrafficSeries(since, until, granularity, seriesByBucket);
|
|
77462
|
-
const coverageScope = (col, srcCol) => sourceIdParam ?
|
|
77595
|
+
const coverageScope = (col, srcCol) => sourceIdParam ? and49(eq55(col, project.id), eq55(srcCol, sourceIdParam)) : eq55(col, project.id);
|
|
77463
77596
|
const firsts = [
|
|
77464
77597
|
app.db.select({ v: sql22`MIN(${crawlerEventsHourly.tsHour})` }).from(crawlerEventsHourly).where(coverageScope(crawlerEventsHourly.projectId, crawlerEventsHourly.sourceId)).get()?.v,
|
|
77465
77598
|
app.db.select({ v: sql22`MIN(${aiUserFetchEventsHourly.tsHour})` }).from(aiUserFetchEventsHourly).where(coverageScope(aiUserFetchEventsHourly.projectId, aiUserFetchEventsHourly.sourceId)).get()?.v,
|
|
@@ -77861,7 +77994,7 @@ var skillsTriggerSurfaceCheck = {
|
|
|
77861
77994
|
var AGENT_CHECKS = [skillsInstalledCheck, skillsCurrentCheck, skillsTriggerSurfaceCheck];
|
|
77862
77995
|
|
|
77863
77996
|
// ../api-routes/src/doctor/checks/backlinks.ts
|
|
77864
|
-
import { and as
|
|
77997
|
+
import { and as and50, eq as eq56 } from "drizzle-orm";
|
|
77865
77998
|
function skippedNoProject() {
|
|
77866
77999
|
return {
|
|
77867
78000
|
status: CheckStatuses.skipped,
|
|
@@ -77891,7 +78024,7 @@ var BACKLINKS_CHECKS = [
|
|
|
77891
78024
|
details: { commoncrawl: ccConnected }
|
|
77892
78025
|
};
|
|
77893
78026
|
}
|
|
77894
|
-
const ccHasData = ccConnected ? !!ctx.db.select({ id: backlinkSummaries.id }).from(backlinkSummaries).where(
|
|
78027
|
+
const ccHasData = ccConnected ? !!ctx.db.select({ id: backlinkSummaries.id }).from(backlinkSummaries).where(and50(
|
|
77895
78028
|
eq56(backlinkSummaries.projectId, ctx.project.id),
|
|
77896
78029
|
eq56(backlinkSummaries.source, BacklinkSources.commoncrawl)
|
|
77897
78030
|
)).limit(1).get() : false;
|
|
@@ -78416,7 +78549,7 @@ var ga4ConnectionCheck = {
|
|
|
78416
78549
|
var GA_AUTH_CHECKS = [ga4ConnectionCheck];
|
|
78417
78550
|
|
|
78418
78551
|
// ../api-routes/src/doctor/checks/gbp-auth.ts
|
|
78419
|
-
import { and as
|
|
78552
|
+
import { and as and51, eq as eq59 } from "drizzle-orm";
|
|
78420
78553
|
var RECENT_SYNC_WARN_DAYS2 = 7;
|
|
78421
78554
|
var RECENT_SYNC_FAIL_DAYS2 = 30;
|
|
78422
78555
|
function skippedNoProject3() {
|
|
@@ -78649,7 +78782,7 @@ var recentSyncCheck = {
|
|
|
78649
78782
|
title: "GBP recent sync",
|
|
78650
78783
|
run: (ctx) => {
|
|
78651
78784
|
if (!ctx.project) return skippedNoProject3();
|
|
78652
|
-
const selected = ctx.db.select({ locationName: gbpLocations.locationName, syncedAt: gbpLocations.syncedAt }).from(gbpLocations).where(
|
|
78785
|
+
const selected = ctx.db.select({ locationName: gbpLocations.locationName, syncedAt: gbpLocations.syncedAt }).from(gbpLocations).where(and51(eq59(gbpLocations.projectId, ctx.project.id), eq59(gbpLocations.selected, true))).all();
|
|
78653
78786
|
if (selected.length === 0) {
|
|
78654
78787
|
return {
|
|
78655
78788
|
status: CheckStatuses.skipped,
|
|
@@ -79269,7 +79402,7 @@ var RUNTIME_STATE_CHECKS = [
|
|
|
79269
79402
|
];
|
|
79270
79403
|
|
|
79271
79404
|
// ../api-routes/src/doctor/checks/traffic-source.ts
|
|
79272
|
-
import { and as
|
|
79405
|
+
import { and as and52, eq as eq61, gte as gte15, inArray as inArray22, ne as ne9, sql as sql23 } from "drizzle-orm";
|
|
79273
79406
|
var RECENT_DATA_WARN_DAYS = 7;
|
|
79274
79407
|
var RECENT_DATA_FAIL_DAYS = 30;
|
|
79275
79408
|
function isCloudflareDirectPush(source) {
|
|
@@ -79308,7 +79441,7 @@ function skippedNoProject5() {
|
|
|
79308
79441
|
function loadProbes(ctx) {
|
|
79309
79442
|
if (!ctx.project) return [];
|
|
79310
79443
|
const rows = ctx.db.select().from(trafficSources).where(
|
|
79311
|
-
|
|
79444
|
+
and52(
|
|
79312
79445
|
eq61(trafficSources.projectId, ctx.project.id),
|
|
79313
79446
|
ne9(trafficSources.status, TrafficSourceStatuses.archived)
|
|
79314
79447
|
)
|
|
@@ -79415,7 +79548,7 @@ var recentDataCheck = {
|
|
|
79415
79548
|
const failCutoff = new Date(now.getTime() - RECENT_DATA_FAIL_DAYS * 24 * 60 * 6e4).toISOString();
|
|
79416
79549
|
const recentCrawlers = Number(
|
|
79417
79550
|
ctx.db.select({ total: sql23`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
79418
|
-
|
|
79551
|
+
and52(
|
|
79419
79552
|
eq61(crawlerEventsHourly.projectId, ctx.project.id),
|
|
79420
79553
|
inArray22(crawlerEventsHourly.sourceId, activeSourceIds),
|
|
79421
79554
|
gte15(crawlerEventsHourly.tsHour, warnCutoff)
|
|
@@ -79424,7 +79557,7 @@ var recentDataCheck = {
|
|
|
79424
79557
|
);
|
|
79425
79558
|
const recentReferrals = Number(
|
|
79426
79559
|
ctx.db.select({ total: sql23`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
79427
|
-
|
|
79560
|
+
and52(
|
|
79428
79561
|
eq61(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
79429
79562
|
inArray22(aiReferralEventsHourly.sourceId, activeSourceIds),
|
|
79430
79563
|
gte15(aiReferralEventsHourly.tsHour, warnCutoff)
|
|
@@ -79433,7 +79566,7 @@ var recentDataCheck = {
|
|
|
79433
79566
|
);
|
|
79434
79567
|
const recentUserFetches = Number(
|
|
79435
79568
|
ctx.db.select({ total: sql23`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
79436
|
-
|
|
79569
|
+
and52(
|
|
79437
79570
|
eq61(aiUserFetchEventsHourly.projectId, ctx.project.id),
|
|
79438
79571
|
inArray22(aiUserFetchEventsHourly.sourceId, activeSourceIds),
|
|
79439
79572
|
gte15(aiUserFetchEventsHourly.tsHour, warnCutoff)
|
|
@@ -79459,7 +79592,7 @@ var recentDataCheck = {
|
|
|
79459
79592
|
}
|
|
79460
79593
|
const olderCrawlers = Number(
|
|
79461
79594
|
ctx.db.select({ total: sql23`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
79462
|
-
|
|
79595
|
+
and52(
|
|
79463
79596
|
eq61(crawlerEventsHourly.projectId, ctx.project.id),
|
|
79464
79597
|
inArray22(crawlerEventsHourly.sourceId, activeSourceIds),
|
|
79465
79598
|
gte15(crawlerEventsHourly.tsHour, failCutoff)
|
|
@@ -79468,7 +79601,7 @@ var recentDataCheck = {
|
|
|
79468
79601
|
);
|
|
79469
79602
|
const olderReferrals = Number(
|
|
79470
79603
|
ctx.db.select({ total: sql23`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
79471
|
-
|
|
79604
|
+
and52(
|
|
79472
79605
|
eq61(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
79473
79606
|
inArray22(aiReferralEventsHourly.sourceId, activeSourceIds),
|
|
79474
79607
|
gte15(aiReferralEventsHourly.tsHour, failCutoff)
|
|
@@ -79477,7 +79610,7 @@ var recentDataCheck = {
|
|
|
79477
79610
|
);
|
|
79478
79611
|
const olderUserFetches = Number(
|
|
79479
79612
|
ctx.db.select({ total: sql23`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
79480
|
-
|
|
79613
|
+
and52(
|
|
79481
79614
|
eq61(aiUserFetchEventsHourly.projectId, ctx.project.id),
|
|
79482
79615
|
inArray22(aiUserFetchEventsHourly.sourceId, activeSourceIds),
|
|
79483
79616
|
gte15(aiUserFetchEventsHourly.tsHour, failCutoff)
|
|
@@ -80395,7 +80528,7 @@ async function doctorRoutes(app, opts) {
|
|
|
80395
80528
|
|
|
80396
80529
|
// ../api-routes/src/discovery/routes.ts
|
|
80397
80530
|
import crypto46 from "crypto";
|
|
80398
|
-
import { and as
|
|
80531
|
+
import { and as and53, desc as desc26, eq as eq62, gte as gte16, inArray as inArray23, isNull as isNull10, or as or12 } from "drizzle-orm";
|
|
80399
80532
|
var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
|
|
80400
80533
|
async function discoveryRoutes(app, opts) {
|
|
80401
80534
|
app.post("/projects/:name/discover/run", async (request, reply) => {
|
|
@@ -80429,7 +80562,7 @@ async function discoveryRoutes(app, opts) {
|
|
|
80429
80562
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
80430
80563
|
const ageFloorIso = new Date(Date.now() - MAX_INFLIGHT_DISCOVERY_AGE_MS).toISOString();
|
|
80431
80564
|
const decision = app.db.transaction((tx) => {
|
|
80432
|
-
const existing = tx.select({ id: discoverySessions.id, runId: discoverySessions.runId }).from(discoverySessions).where(
|
|
80565
|
+
const existing = tx.select({ id: discoverySessions.id, runId: discoverySessions.runId }).from(discoverySessions).where(and53(
|
|
80433
80566
|
eq62(discoverySessions.projectId, project.id),
|
|
80434
80567
|
eq62(discoverySessions.icpDescription, icpDescription),
|
|
80435
80568
|
// Buyer is part of session identity: it changes the seed prompt's
|
|
@@ -81075,7 +81208,7 @@ function dedupeStrings(input) {
|
|
|
81075
81208
|
|
|
81076
81209
|
// ../api-routes/src/technical-aeo.ts
|
|
81077
81210
|
import crypto48 from "crypto";
|
|
81078
|
-
import { and as
|
|
81211
|
+
import { and as and54, asc as asc11, count as count2, desc as desc27, eq as eq64, inArray as inArray24, isNotNull as isNotNull5, isNull as isNull11, lt as lt10, or as or13, sql as sql24 } from "drizzle-orm";
|
|
81079
81212
|
import { alias } from "drizzle-orm/sqlite-core";
|
|
81080
81213
|
var FETCHED_SITE_CRAWL_STATES = /* @__PURE__ */ new Set([
|
|
81081
81214
|
...SiteCrawlFetchedStates,
|
|
@@ -81405,25 +81538,25 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
81405
81538
|
} else {
|
|
81406
81539
|
filters.push(eq64(siteCrawlSnapshots.complete, true), eq64(runs.status, RunStatuses.completed));
|
|
81407
81540
|
}
|
|
81408
|
-
return app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq64(siteCrawlSnapshots.runId, runs.id)).where(
|
|
81541
|
+
return app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq64(siteCrawlSnapshots.runId, runs.id)).where(and54(...filters)).orderBy(desc27(siteCrawlSnapshots.createdAt), desc27(siteCrawlSnapshots.runId)).limit(1).get();
|
|
81409
81542
|
};
|
|
81410
81543
|
const detailScopeFor = (projectId, snapshot) => snapshot.detailsAvailable && snapshot.attemptId ? { projectId, runId: snapshot.runId, attemptId: snapshot.attemptId } : null;
|
|
81411
81544
|
const pageInScope = (scope, selector) => {
|
|
81412
81545
|
if (!selector.nodeKey && !selector.url) return null;
|
|
81413
|
-
return app.db.select().from(siteCrawlPages).where(
|
|
81546
|
+
return app.db.select().from(siteCrawlPages).where(and54(
|
|
81414
81547
|
eq64(siteCrawlPages.projectId, scope.projectId),
|
|
81415
81548
|
eq64(siteCrawlPages.runId, scope.runId),
|
|
81416
81549
|
eq64(siteCrawlPages.attemptId, scope.attemptId),
|
|
81417
81550
|
selector.nodeKey ? eq64(siteCrawlPages.nodeKey, selector.nodeKey) : eq64(siteCrawlPages.url, selector.url)
|
|
81418
81551
|
)).orderBy(asc11(siteCrawlPages.nodeKey)).limit(1).get() ?? null;
|
|
81419
81552
|
};
|
|
81420
|
-
const rootPageInScope = (scope, rootUrl) => pageInScope(scope, { url: rootUrl }) ?? app.db.select().from(siteCrawlPages).where(
|
|
81553
|
+
const rootPageInScope = (scope, rootUrl) => pageInScope(scope, { url: rootUrl }) ?? app.db.select().from(siteCrawlPages).where(and54(
|
|
81421
81554
|
eq64(siteCrawlPages.projectId, scope.projectId),
|
|
81422
81555
|
eq64(siteCrawlPages.runId, scope.runId),
|
|
81423
81556
|
eq64(siteCrawlPages.attemptId, scope.attemptId),
|
|
81424
81557
|
eq64(siteCrawlPages.depth, 0)
|
|
81425
81558
|
)).orderBy(asc11(siteCrawlPages.nodeKey)).limit(1).get() ?? null;
|
|
81426
|
-
const isSurfaceableAuditRun = (projectId, runId) => Boolean(app.db.select({ id: runs.id }).from(runs).where(
|
|
81559
|
+
const isSurfaceableAuditRun = (projectId, runId) => Boolean(app.db.select({ id: runs.id }).from(runs).where(and54(
|
|
81427
81560
|
eq64(runs.id, runId),
|
|
81428
81561
|
eq64(runs.projectId, projectId),
|
|
81429
81562
|
eq64(runs.kind, RunKinds["site-audit"]),
|
|
@@ -81433,7 +81566,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
81433
81566
|
const assertKnownAuditRun = (projectId, runId) => {
|
|
81434
81567
|
if (runId && !isSurfaceableAuditRun(projectId, runId)) throw notFound("Site crawl run", runId);
|
|
81435
81568
|
};
|
|
81436
|
-
const hasLegacyAudit = (projectId) => Boolean(app.db.select({ runId: siteAuditSnapshots.runId }).from(siteAuditSnapshots).innerJoin(runs, eq64(siteAuditSnapshots.runId, runs.id)).where(
|
|
81569
|
+
const hasLegacyAudit = (projectId) => Boolean(app.db.select({ runId: siteAuditSnapshots.runId }).from(siteAuditSnapshots).innerJoin(runs, eq64(siteAuditSnapshots.runId, runs.id)).where(and54(
|
|
81437
81570
|
eq64(siteAuditSnapshots.projectId, projectId),
|
|
81438
81571
|
eq64(runs.projectId, projectId),
|
|
81439
81572
|
eq64(runs.kind, RunKinds["site-audit"]),
|
|
@@ -81465,13 +81598,13 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
81465
81598
|
notProbeRun()
|
|
81466
81599
|
];
|
|
81467
81600
|
const targetFilters = request.query.runId ? [...baseFilters, eq64(siteAuditSnapshots.runId, request.query.runId)] : baseFilters;
|
|
81468
|
-
const latest = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq64(siteAuditSnapshots.runId, runs.id)).where(
|
|
81601
|
+
const latest = app.db.select({ snap: siteAuditSnapshots, runStatus: runs.status }).from(siteAuditSnapshots).innerJoin(runs, eq64(siteAuditSnapshots.runId, runs.id)).where(and54(...targetFilters)).orderBy(desc27(siteAuditSnapshots.createdAt)).limit(1).get();
|
|
81469
81602
|
if (!latest) {
|
|
81470
81603
|
if (request.query.runId) throw notFound("Site audit run", request.query.runId);
|
|
81471
81604
|
return emptyScore(project.name);
|
|
81472
81605
|
}
|
|
81473
81606
|
const snap = latest.snap;
|
|
81474
|
-
const previous = app.db.select({ snap: siteAuditSnapshots }).from(siteAuditSnapshots).innerJoin(runs, eq64(siteAuditSnapshots.runId, runs.id)).where(
|
|
81607
|
+
const previous = app.db.select({ snap: siteAuditSnapshots }).from(siteAuditSnapshots).innerJoin(runs, eq64(siteAuditSnapshots.runId, runs.id)).where(and54(...baseFilters, lt10(siteAuditSnapshots.createdAt, snap.createdAt))).orderBy(desc27(siteAuditSnapshots.createdAt)).limit(1).get()?.snap ?? null;
|
|
81475
81608
|
const deltaScore = previous ? snap.aggregateScore - previous.aggregateScore : null;
|
|
81476
81609
|
const trend = deltaScore == null ? null : deltaScore > 0 ? SiteAuditTrendDirections.up : deltaScore < 0 ? SiteAuditTrendDirections.down : SiteAuditTrendDirections.flat;
|
|
81477
81610
|
return {
|
|
@@ -81505,7 +81638,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
81505
81638
|
notProbeRun()
|
|
81506
81639
|
];
|
|
81507
81640
|
if (request.query.runId) targetFilters.push(eq64(siteAuditSnapshots.runId, request.query.runId));
|
|
81508
|
-
const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq64(siteAuditSnapshots.runId, runs.id)).where(
|
|
81641
|
+
const latest = app.db.select({ runId: siteAuditSnapshots.runId, auditedAt: siteAuditSnapshots.auditedAt }).from(siteAuditSnapshots).innerJoin(runs, eq64(siteAuditSnapshots.runId, runs.id)).where(and54(...targetFilters)).orderBy(desc27(siteAuditSnapshots.createdAt)).limit(1).get();
|
|
81509
81642
|
if (!latest && request.query.runId) {
|
|
81510
81643
|
throw notFound("Site audit run", request.query.runId);
|
|
81511
81644
|
}
|
|
@@ -81515,7 +81648,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
81515
81648
|
const statusFilter = request.query.status === "success" || request.query.status === "error" ? request.query.status : null;
|
|
81516
81649
|
const conds = [eq64(siteAuditPages.projectId, project.id), eq64(siteAuditPages.runId, latest.runId)];
|
|
81517
81650
|
if (statusFilter) conds.push(eq64(siteAuditPages.status, statusFilter));
|
|
81518
|
-
const where =
|
|
81651
|
+
const where = and54(...conds);
|
|
81519
81652
|
const totalRow = app.db.select({ value: count2() }).from(siteAuditPages).where(where).get();
|
|
81520
81653
|
const total = totalRow?.value ?? 0;
|
|
81521
81654
|
const limit = parsePositiveInt(request.query.limit, 100, 500);
|
|
@@ -81539,7 +81672,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
81539
81672
|
auditedAt: siteAuditSnapshots.auditedAt,
|
|
81540
81673
|
aggregateScore: siteAuditSnapshots.aggregateScore,
|
|
81541
81674
|
pagesAudited: siteAuditSnapshots.pagesAudited
|
|
81542
|
-
}).from(siteAuditSnapshots).innerJoin(runs, eq64(siteAuditSnapshots.runId, runs.id)).where(
|
|
81675
|
+
}).from(siteAuditSnapshots).innerJoin(runs, eq64(siteAuditSnapshots.runId, runs.id)).where(and54(
|
|
81543
81676
|
eq64(siteAuditSnapshots.projectId, project.id),
|
|
81544
81677
|
eq64(runs.projectId, project.id),
|
|
81545
81678
|
eq64(runs.kind, RunKinds["site-audit"]),
|
|
@@ -81637,7 +81770,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
81637
81770
|
{ projectId: project.id, runId: snapshot.runId, attemptId: snapshot.attemptId },
|
|
81638
81771
|
snapshot.rootUrl
|
|
81639
81772
|
)?.nodeKey ?? null;
|
|
81640
|
-
const persistedLayout = app.db.select().from(siteCrawlGraphLayouts).where(
|
|
81773
|
+
const persistedLayout = app.db.select().from(siteCrawlGraphLayouts).where(and54(
|
|
81641
81774
|
eq64(siteCrawlGraphLayouts.projectId, project.id),
|
|
81642
81775
|
eq64(siteCrawlGraphLayouts.runId, snapshot.runId),
|
|
81643
81776
|
eq64(siteCrawlGraphLayouts.attemptId, snapshot.attemptId)
|
|
@@ -81712,12 +81845,12 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
81712
81845
|
linkScoreNormalized: siteCrawlPages.linkScoreNormalized,
|
|
81713
81846
|
x: siteCrawlGraphNodes.x,
|
|
81714
81847
|
y: siteCrawlGraphNodes.y
|
|
81715
|
-
}).from(siteCrawlGraphNodes).innerJoin(siteCrawlPages,
|
|
81848
|
+
}).from(siteCrawlGraphNodes).innerJoin(siteCrawlPages, and54(
|
|
81716
81849
|
eq64(siteCrawlPages.projectId, siteCrawlGraphNodes.projectId),
|
|
81717
81850
|
eq64(siteCrawlPages.runId, siteCrawlGraphNodes.runId),
|
|
81718
81851
|
eq64(siteCrawlPages.attemptId, siteCrawlGraphNodes.attemptId),
|
|
81719
81852
|
eq64(siteCrawlPages.nodeKey, siteCrawlGraphNodes.nodeKey)
|
|
81720
|
-
)).where(
|
|
81853
|
+
)).where(and54(...graphScope, lt10(siteCrawlGraphNodes.sampleRank, maxNodes))).orderBy(asc11(siteCrawlGraphNodes.sampleRank)).all();
|
|
81721
81854
|
const nodes = nodeRows.map(({ indexabilityReasons, canonicalNodeKey, ...row }) => ({
|
|
81722
81855
|
...row,
|
|
81723
81856
|
healthState: deriveSiteHealthState({ ...row, indexabilityReasons, canonicalNodeKey })
|
|
@@ -81730,19 +81863,19 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
81730
81863
|
followable: siteCrawlGraphEdges.followable,
|
|
81731
81864
|
occurrences: siteCrawlGraphEdges.occurrences,
|
|
81732
81865
|
isTemplate: siteCrawlGraphEdges.isTemplate
|
|
81733
|
-
}).from(siteCrawlGraphEdges).innerJoin(graphSourceNode,
|
|
81866
|
+
}).from(siteCrawlGraphEdges).innerJoin(graphSourceNode, and54(
|
|
81734
81867
|
eq64(graphSourceNode.projectId, siteCrawlGraphEdges.projectId),
|
|
81735
81868
|
eq64(graphSourceNode.runId, siteCrawlGraphEdges.runId),
|
|
81736
81869
|
eq64(graphSourceNode.attemptId, siteCrawlGraphEdges.attemptId),
|
|
81737
81870
|
eq64(graphSourceNode.nodeKey, siteCrawlGraphEdges.sourceNodeKey),
|
|
81738
81871
|
lt10(graphSourceNode.sampleRank, maxNodes)
|
|
81739
|
-
)).innerJoin(graphTargetNode,
|
|
81872
|
+
)).innerJoin(graphTargetNode, and54(
|
|
81740
81873
|
eq64(graphTargetNode.projectId, siteCrawlGraphEdges.projectId),
|
|
81741
81874
|
eq64(graphTargetNode.runId, siteCrawlGraphEdges.runId),
|
|
81742
81875
|
eq64(graphTargetNode.attemptId, siteCrawlGraphEdges.attemptId),
|
|
81743
81876
|
eq64(graphTargetNode.nodeKey, siteCrawlGraphEdges.targetNodeKey),
|
|
81744
81877
|
lt10(graphTargetNode.sampleRank, maxNodes)
|
|
81745
|
-
)).where(
|
|
81878
|
+
)).where(and54(
|
|
81746
81879
|
eq64(siteCrawlGraphEdges.projectId, project.id),
|
|
81747
81880
|
eq64(siteCrawlGraphEdges.runId, snapshot.runId),
|
|
81748
81881
|
eq64(siteCrawlGraphEdges.attemptId, snapshot.attemptId),
|
|
@@ -81839,7 +81972,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
81839
81972
|
let frontier = [focus.nodeKey];
|
|
81840
81973
|
let queryTruncated = false;
|
|
81841
81974
|
for (let distance = 0; distance < hops && frontier.length > 0; distance += 1) {
|
|
81842
|
-
const candidates = app.db.select().from(siteCrawlEdges).where(
|
|
81975
|
+
const candidates = app.db.select().from(siteCrawlEdges).where(and54(
|
|
81843
81976
|
eq64(siteCrawlEdges.projectId, scope.projectId),
|
|
81844
81977
|
eq64(siteCrawlEdges.runId, scope.runId),
|
|
81845
81978
|
eq64(siteCrawlEdges.attemptId, scope.attemptId),
|
|
@@ -81880,7 +82013,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
81880
82013
|
frontier = [...next].sort();
|
|
81881
82014
|
}
|
|
81882
82015
|
const nodeKeys = [...distances.keys()];
|
|
81883
|
-
const pageRows = nodeKeys.length === 0 ? [] : app.db.select().from(siteCrawlPages).where(
|
|
82016
|
+
const pageRows = nodeKeys.length === 0 ? [] : app.db.select().from(siteCrawlPages).where(and54(
|
|
81884
82017
|
eq64(siteCrawlPages.projectId, scope.projectId),
|
|
81885
82018
|
eq64(siteCrawlPages.runId, scope.runId),
|
|
81886
82019
|
eq64(siteCrawlPages.attemptId, scope.attemptId),
|
|
@@ -81888,7 +82021,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
81888
82021
|
)).all();
|
|
81889
82022
|
const persistedNodeKeys = new Set(pageRows.map((row) => row.nodeKey));
|
|
81890
82023
|
const outermostNodeKeys = pageRows.filter((row) => distances.get(row.nodeKey) === hops).map((row) => row.nodeKey);
|
|
81891
|
-
const omittedOutermostEdge = outermostNodeKeys.length === 0 ? void 0 : app.db.select({ edgeKey: siteCrawlEdges.edgeKey }).from(siteCrawlEdges).where(
|
|
82024
|
+
const omittedOutermostEdge = outermostNodeKeys.length === 0 ? void 0 : app.db.select({ edgeKey: siteCrawlEdges.edgeKey }).from(siteCrawlEdges).where(and54(
|
|
81892
82025
|
eq64(siteCrawlEdges.projectId, scope.projectId),
|
|
81893
82026
|
eq64(siteCrawlEdges.runId, scope.runId),
|
|
81894
82027
|
eq64(siteCrawlEdges.attemptId, scope.attemptId),
|
|
@@ -81990,7 +82123,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
81990
82123
|
let found = fromPage.nodeKey === toPage.nodeKey;
|
|
81991
82124
|
let truncated = false;
|
|
81992
82125
|
for (let depth = 0; depth < maxDepth && frontier.length > 0 && !found; depth += 1) {
|
|
81993
|
-
const candidates = app.db.select().from(siteCrawlEdges).where(
|
|
82126
|
+
const candidates = app.db.select().from(siteCrawlEdges).where(and54(
|
|
81994
82127
|
eq64(siteCrawlEdges.projectId, scope.projectId),
|
|
81995
82128
|
eq64(siteCrawlEdges.runId, scope.runId),
|
|
81996
82129
|
eq64(siteCrawlEdges.attemptId, scope.attemptId),
|
|
@@ -82002,7 +82135,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82002
82135
|
)).orderBy(asc11(siteCrawlEdges.edgeKey)).limit(SITE_HEALTH_PATH_MAX_VISITED_NODES + 1).all();
|
|
82003
82136
|
if (candidates.length > SITE_HEALTH_PATH_MAX_VISITED_NODES) truncated = true;
|
|
82004
82137
|
const candidateTargetKeys = [...new Set(candidates.map((edge) => edge.targetNodeKey).filter((nodeKey) => nodeKey != null))];
|
|
82005
|
-
const persistedTargetKeys = new Set(candidateTargetKeys.length === 0 ? [] : app.db.select({ nodeKey: siteCrawlPages.nodeKey }).from(siteCrawlPages).where(
|
|
82138
|
+
const persistedTargetKeys = new Set(candidateTargetKeys.length === 0 ? [] : app.db.select({ nodeKey: siteCrawlPages.nodeKey }).from(siteCrawlPages).where(and54(
|
|
82006
82139
|
eq64(siteCrawlPages.projectId, scope.projectId),
|
|
82007
82140
|
eq64(siteCrawlPages.runId, scope.runId),
|
|
82008
82141
|
eq64(siteCrawlPages.attemptId, scope.attemptId),
|
|
@@ -82048,7 +82181,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82048
82181
|
pathEdges.unshift(step.edge);
|
|
82049
82182
|
pathKeys.unshift(step.nodeKey);
|
|
82050
82183
|
}
|
|
82051
|
-
const pathRows = app.db.select().from(siteCrawlPages).where(
|
|
82184
|
+
const pathRows = app.db.select().from(siteCrawlPages).where(and54(
|
|
82052
82185
|
eq64(siteCrawlPages.projectId, scope.projectId),
|
|
82053
82186
|
eq64(siteCrawlPages.runId, scope.runId),
|
|
82054
82187
|
eq64(siteCrawlPages.attemptId, scope.attemptId),
|
|
@@ -82088,13 +82221,13 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82088
82221
|
eq64(siteCrawlSnapshots.complete, true),
|
|
82089
82222
|
notProbeRun()
|
|
82090
82223
|
];
|
|
82091
|
-
const afterTarget = request.query.toRunId ? resolveCrawl(project.id, request.query.toRunId) : app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq64(siteCrawlSnapshots.runId, runs.id)).where(
|
|
82224
|
+
const afterTarget = request.query.toRunId ? resolveCrawl(project.id, request.query.toRunId) : app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq64(siteCrawlSnapshots.runId, runs.id)).where(and54(...completeSnapshotFilters)).orderBy(desc27(siteCrawlSnapshots.createdAt), desc27(siteCrawlSnapshots.runId)).limit(1).get();
|
|
82092
82225
|
if (request.query.toRunId && !afterTarget) throw notFound("Site crawl run", request.query.toRunId);
|
|
82093
|
-
const beforeTarget = request.query.fromRunId ? resolveCrawl(project.id, request.query.fromRunId) : afterTarget ? app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq64(siteCrawlSnapshots.runId, runs.id)).where(
|
|
82226
|
+
const beforeTarget = request.query.fromRunId ? resolveCrawl(project.id, request.query.fromRunId) : afterTarget ? app.db.select({ snapshot: siteCrawlSnapshots, runStatus: runs.status }).from(siteCrawlSnapshots).innerJoin(runs, eq64(siteCrawlSnapshots.runId, runs.id)).where(and54(
|
|
82094
82227
|
...completeSnapshotFilters,
|
|
82095
82228
|
or13(
|
|
82096
82229
|
lt10(siteCrawlSnapshots.createdAt, afterTarget.snapshot.createdAt),
|
|
82097
|
-
|
|
82230
|
+
and54(
|
|
82098
82231
|
eq64(siteCrawlSnapshots.createdAt, afterTarget.snapshot.createdAt),
|
|
82099
82232
|
lt10(siteCrawlSnapshots.runId, afterTarget.snapshot.runId)
|
|
82100
82233
|
)
|
|
@@ -82330,13 +82463,13 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82330
82463
|
const visibleKeys = keyRows.slice(0, limit);
|
|
82331
82464
|
const pageKeys = visibleKeys.filter((row) => row.entity === "page").map((row) => row.key);
|
|
82332
82465
|
const linkKeys = visibleKeys.filter((row) => row.entity === "link").map((row) => row.key);
|
|
82333
|
-
const pageRowsFor = (scope) => pageKeys.length === 0 ? [] : app.db.select().from(siteCrawlPages).where(
|
|
82466
|
+
const pageRowsFor = (scope) => pageKeys.length === 0 ? [] : app.db.select().from(siteCrawlPages).where(and54(
|
|
82334
82467
|
eq64(siteCrawlPages.projectId, scope.projectId),
|
|
82335
82468
|
eq64(siteCrawlPages.runId, scope.runId),
|
|
82336
82469
|
eq64(siteCrawlPages.attemptId, scope.attemptId),
|
|
82337
82470
|
inArray24(siteCrawlPages.nodeKey, pageKeys)
|
|
82338
82471
|
)).all();
|
|
82339
|
-
const edgeRowsFor = (scope) => linkKeys.length === 0 ? [] : app.db.select().from(siteCrawlEdges).where(
|
|
82472
|
+
const edgeRowsFor = (scope) => linkKeys.length === 0 ? [] : app.db.select().from(siteCrawlEdges).where(and54(
|
|
82340
82473
|
eq64(siteCrawlEdges.projectId, scope.projectId),
|
|
82341
82474
|
eq64(siteCrawlEdges.runId, scope.runId),
|
|
82342
82475
|
eq64(siteCrawlEdges.attemptId, scope.attemptId),
|
|
@@ -82482,7 +82615,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82482
82615
|
const orderBy = request.query.sort === "score-desc" ? [desc27(siteCrawlPages.auditScore), asc11(siteCrawlPages.nodeKey)] : request.query.sort === "score-asc" ? [asc11(siteCrawlPages.auditScore), asc11(siteCrawlPages.nodeKey)] : request.query.sort === "path" ? [asc11(siteCrawlPages.path), asc11(siteCrawlPages.nodeKey)] : [asc11(siteCrawlPages.url), asc11(siteCrawlPages.nodeKey)];
|
|
82483
82616
|
let healthStateFilter = null;
|
|
82484
82617
|
if (healthState) {
|
|
82485
|
-
const legacyRow = app.db.select({ id: siteCrawlPages.id }).from(siteCrawlPages).where(
|
|
82618
|
+
const legacyRow = app.db.select({ id: siteCrawlPages.id }).from(siteCrawlPages).where(and54(
|
|
82486
82619
|
eq64(siteCrawlPages.projectId, project.id),
|
|
82487
82620
|
eq64(siteCrawlPages.runId, snapshot.runId),
|
|
82488
82621
|
eq64(siteCrawlPages.attemptId, snapshot.attemptId),
|
|
@@ -82502,7 +82635,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82502
82635
|
pages: []
|
|
82503
82636
|
};
|
|
82504
82637
|
}
|
|
82505
|
-
const where =
|
|
82638
|
+
const where = and54(...filters);
|
|
82506
82639
|
const total = app.db.select({ value: count2() }).from(siteCrawlPages).where(where).get()?.value ?? 0;
|
|
82507
82640
|
const rows = app.db.select().from(siteCrawlPages).where(where).orderBy(...orderBy).limit(limit).offset(offset).all();
|
|
82508
82641
|
const nextOffset = offset + rows.length;
|
|
@@ -82533,7 +82666,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82533
82666
|
url: siteCrawlPages.url,
|
|
82534
82667
|
inventoryEligible: siteCrawlPages.inventoryEligible,
|
|
82535
82668
|
fetchState: siteCrawlPages.fetchState
|
|
82536
|
-
}).from(siteCrawlPages).where(
|
|
82669
|
+
}).from(siteCrawlPages).where(and54(
|
|
82537
82670
|
eq64(siteCrawlPages.projectId, project.id),
|
|
82538
82671
|
eq64(siteCrawlPages.runId, snapshot.runId),
|
|
82539
82672
|
eq64(siteCrawlPages.attemptId, snapshot.attemptId)
|
|
@@ -82625,7 +82758,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82625
82758
|
if (request.query.targetUrl) filters.push(eq64(siteCrawlEdges.targetUrl, request.query.targetUrl));
|
|
82626
82759
|
const followable = parseBoolean2(request.query.followable);
|
|
82627
82760
|
if (followable != null) filters.push(eq64(siteCrawlEdges.followable, followable));
|
|
82628
|
-
const where =
|
|
82761
|
+
const where = and54(...filters);
|
|
82629
82762
|
const total = app.db.select({ value: count2() }).from(siteCrawlEdges).where(where).get()?.value ?? 0;
|
|
82630
82763
|
const limit = parseBoundedLimit(request.query.limit, 100, 200);
|
|
82631
82764
|
const offset = decodeCursor(request.query.cursor);
|
|
@@ -82692,8 +82825,8 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82692
82825
|
const inboundMatch = request.query.nodeKey && request.query.url ? or13(eq64(siteCrawlEdges.targetNodeKey, request.query.nodeKey), eq64(siteCrawlEdges.targetUrl, request.query.url)) : request.query.nodeKey ? eq64(siteCrawlEdges.targetNodeKey, request.query.nodeKey) : eq64(siteCrawlEdges.targetUrl, request.query.url);
|
|
82693
82826
|
const outboundMatch = request.query.nodeKey && request.query.url ? or13(eq64(siteCrawlEdges.sourceNodeKey, request.query.nodeKey), eq64(siteCrawlEdges.sourceUrl, request.query.url)) : request.query.nodeKey ? eq64(siteCrawlEdges.sourceNodeKey, request.query.nodeKey) : eq64(siteCrawlEdges.sourceUrl, request.query.url);
|
|
82694
82827
|
const limit = parseBoundedLimit(request.query.limit, 50, 100);
|
|
82695
|
-
const inboundRows = app.db.select().from(siteCrawlEdges).where(
|
|
82696
|
-
const outboundRows = app.db.select().from(siteCrawlEdges).where(
|
|
82828
|
+
const inboundRows = app.db.select().from(siteCrawlEdges).where(and54(...scope, inboundMatch)).orderBy(asc11(siteCrawlEdges.edgeKey)).limit(limit + 1).all();
|
|
82829
|
+
const outboundRows = app.db.select().from(siteCrawlEdges).where(and54(...scope, outboundMatch)).orderBy(asc11(siteCrawlEdges.edgeKey)).limit(limit + 1).all();
|
|
82697
82830
|
return {
|
|
82698
82831
|
project: project.name,
|
|
82699
82832
|
hasCrawlData: true,
|
|
@@ -82726,7 +82859,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82726
82859
|
if (!snapshot.attemptId) {
|
|
82727
82860
|
return { project: project.name, runId: snapshot.runId, state: "partial", checkDeadLinks: true, checked: snapshot.deadLinksChecked, found: snapshot.deadLinksFound, unverified: snapshot.deadLinksUnverified, total: 0, nextCursor: null, deadLinks: [] };
|
|
82728
82861
|
}
|
|
82729
|
-
const where =
|
|
82862
|
+
const where = and54(
|
|
82730
82863
|
eq64(siteCrawlFindings.projectId, project.id),
|
|
82731
82864
|
eq64(siteCrawlFindings.runId, snapshot.runId),
|
|
82732
82865
|
eq64(siteCrawlFindings.attemptId, snapshot.attemptId),
|
|
@@ -82779,13 +82912,13 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82779
82912
|
createdAt: runs.createdAt,
|
|
82780
82913
|
startedAt: runs.startedAt,
|
|
82781
82914
|
finishedAt: runs.finishedAt
|
|
82782
|
-
}).from(runs).where(
|
|
82915
|
+
}).from(runs).where(and54(
|
|
82783
82916
|
eq64(runs.projectId, project.id),
|
|
82784
82917
|
eq64(runs.kind, RunKinds["site-audit"]),
|
|
82785
82918
|
notProbeRun()
|
|
82786
82919
|
)).orderBy(desc27(runs.createdAt), desc27(runs.id)).limit(limit).all();
|
|
82787
82920
|
const runIds = rows.map((row) => row.runId);
|
|
82788
|
-
const crawlRunIds = new Set(runIds.length === 0 ? [] : app.db.select({ runId: siteCrawlSnapshots.runId }).from(siteCrawlSnapshots).innerJoin(runs, eq64(siteCrawlSnapshots.runId, runs.id)).where(
|
|
82921
|
+
const crawlRunIds = new Set(runIds.length === 0 ? [] : app.db.select({ runId: siteCrawlSnapshots.runId }).from(siteCrawlSnapshots).innerJoin(runs, eq64(siteCrawlSnapshots.runId, runs.id)).where(and54(
|
|
82789
82922
|
eq64(siteCrawlSnapshots.projectId, project.id),
|
|
82790
82923
|
eq64(runs.projectId, project.id),
|
|
82791
82924
|
eq64(runs.kind, RunKinds["site-audit"]),
|
|
@@ -82804,18 +82937,18 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82804
82937
|
});
|
|
82805
82938
|
app.get("/projects/:name/technical-aeo/runs/:runId/progress", async (request) => {
|
|
82806
82939
|
const project = resolveProject(app.db, request.params.name);
|
|
82807
|
-
const run = app.db.select().from(runs).where(
|
|
82940
|
+
const run = app.db.select().from(runs).where(and54(
|
|
82808
82941
|
eq64(runs.id, request.params.runId),
|
|
82809
82942
|
eq64(runs.projectId, project.id),
|
|
82810
82943
|
eq64(runs.kind, RunKinds["site-audit"]),
|
|
82811
82944
|
notProbeRun()
|
|
82812
82945
|
)).get();
|
|
82813
82946
|
if (!run) throw notFound("Site audit run", request.params.runId);
|
|
82814
|
-
const attempt = app.db.select().from(siteCrawlAttempts).where(
|
|
82947
|
+
const attempt = app.db.select().from(siteCrawlAttempts).where(and54(
|
|
82815
82948
|
eq64(siteCrawlAttempts.projectId, project.id),
|
|
82816
82949
|
eq64(siteCrawlAttempts.runId, run.id)
|
|
82817
82950
|
)).orderBy(desc27(siteCrawlAttempts.attemptNumber), desc27(siteCrawlAttempts.updatedAt)).limit(1).get();
|
|
82818
|
-
const persistedLayout = attempt ? app.db.select().from(siteCrawlGraphLayouts).where(
|
|
82951
|
+
const persistedLayout = attempt ? app.db.select().from(siteCrawlGraphLayouts).where(and54(
|
|
82819
82952
|
eq64(siteCrawlGraphLayouts.projectId, project.id),
|
|
82820
82953
|
eq64(siteCrawlGraphLayouts.runId, run.id),
|
|
82821
82954
|
eq64(siteCrawlGraphLayouts.attemptId, attempt.id)
|
|
@@ -82851,14 +82984,14 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82851
82984
|
app.get("/projects/:name/technical-aeo/runs/:runId/page-health-preview", async (request) => app.db.transaction((tx) => {
|
|
82852
82985
|
const project = tx.select().from(projects).where(eq64(projects.name, request.params.name)).get();
|
|
82853
82986
|
if (!project) throw notFound("Project", request.params.name);
|
|
82854
|
-
const run = tx.select().from(runs).where(
|
|
82987
|
+
const run = tx.select().from(runs).where(and54(
|
|
82855
82988
|
eq64(runs.id, request.params.runId),
|
|
82856
82989
|
eq64(runs.projectId, project.id),
|
|
82857
82990
|
eq64(runs.kind, RunKinds["site-audit"]),
|
|
82858
82991
|
notProbeRun()
|
|
82859
82992
|
)).get();
|
|
82860
82993
|
if (!run) throw notFound("Site audit run", request.params.runId);
|
|
82861
|
-
const attempt = tx.select().from(siteCrawlAttempts).where(
|
|
82994
|
+
const attempt = tx.select().from(siteCrawlAttempts).where(and54(
|
|
82862
82995
|
eq64(siteCrawlAttempts.projectId, project.id),
|
|
82863
82996
|
eq64(siteCrawlAttempts.runId, run.id)
|
|
82864
82997
|
)).orderBy(desc27(siteCrawlAttempts.attemptNumber), desc27(siteCrawlAttempts.updatedAt)).limit(1).get();
|
|
@@ -82874,7 +83007,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82874
83007
|
if (!attempt) {
|
|
82875
83008
|
return { ...base, pagesAudited: 0, examples: [] };
|
|
82876
83009
|
}
|
|
82877
|
-
const auditedWhere =
|
|
83010
|
+
const auditedWhere = and54(
|
|
82878
83011
|
eq64(siteCrawlPages.projectId, project.id),
|
|
82879
83012
|
eq64(siteCrawlPages.runId, run.id),
|
|
82880
83013
|
eq64(siteCrawlPages.attemptId, attempt.id),
|
|
@@ -82889,7 +83022,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82889
83022
|
url: siteCrawlPages.url,
|
|
82890
83023
|
auditScore: siteCrawlPages.auditScore,
|
|
82891
83024
|
auditFields: siteCrawlPages.auditFields
|
|
82892
|
-
}).from(siteCrawlPages).where(
|
|
83025
|
+
}).from(siteCrawlPages).where(and54(
|
|
82893
83026
|
auditedWhere,
|
|
82894
83027
|
isNotNull5(siteCrawlPages.auditScore),
|
|
82895
83028
|
lt10(siteCrawlPages.auditScore, 70)
|
|
@@ -82925,10 +83058,10 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82925
83058
|
status: runs.status,
|
|
82926
83059
|
identityKey: siteCrawlRunRequests.identityKey,
|
|
82927
83060
|
effectiveOptions: siteCrawlRunRequests.effectiveOptions
|
|
82928
|
-
}).from(runs).leftJoin(siteCrawlRunRequests,
|
|
83061
|
+
}).from(runs).leftJoin(siteCrawlRunRequests, and54(
|
|
82929
83062
|
eq64(siteCrawlRunRequests.projectId, runs.projectId),
|
|
82930
83063
|
eq64(siteCrawlRunRequests.runId, runs.id)
|
|
82931
|
-
)).where(
|
|
83064
|
+
)).where(and54(
|
|
82932
83065
|
eq64(runs.projectId, project.id),
|
|
82933
83066
|
eq64(runs.kind, RunKinds["site-audit"]),
|
|
82934
83067
|
inArray24(runs.status, [RunStatuses.queued, RunStatuses.running])
|
|
@@ -82984,7 +83117,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
82984
83117
|
|
|
82985
83118
|
// ../api-routes/src/research.ts
|
|
82986
83119
|
import crypto49 from "crypto";
|
|
82987
|
-
import { and as
|
|
83120
|
+
import { and as and55, count as count3, desc as desc28, eq as eq65, gte as gte17, lt as lt11, sql as sql25 } from "drizzle-orm";
|
|
82988
83121
|
var sameLocation = (a, b) => a.label === b.label && a.city === b.city && a.region === b.region && a.country === b.country && a.timezone === b.timezone;
|
|
82989
83122
|
async function researchRoutes(app, opts) {
|
|
82990
83123
|
const viewerDailyRunLimit = opts.viewerDailyRunLimit ?? DEFAULT_VIEWER_RESEARCH_DAILY_RUN_LIMIT;
|
|
@@ -83012,7 +83145,7 @@ async function researchRoutes(app, opts) {
|
|
|
83012
83145
|
const location = input.location === void 0 ? project.defaultLocation ? project.locations.find((item2) => item2.label === project.defaultLocation) ?? null : null : input.location;
|
|
83013
83146
|
if (location && !project.locations.some((item2) => sameLocation(item2, location))) throw validationError("Research location must exactly match a configured project location.", { location });
|
|
83014
83147
|
const requestedModel2 = input.model ?? null;
|
|
83015
|
-
const resolvedModel = requestedModel2 ?? (project.providerModels[providerName] || adapter.defaultModel);
|
|
83148
|
+
const resolvedModel = requestedModel2 ?? (project.providerModels[providerName] || opts.getEffectiveProviderModels?.()[providerName] || adapter.defaultModel);
|
|
83016
83149
|
adapter.modelValidationPattern.lastIndex = 0;
|
|
83017
83150
|
if (!adapter.modelValidationPattern.test(resolvedModel)) throw validationError(`Invalid resolved model "${resolvedModel}" for provider "${providerName}".`, { provider: providerName, model: resolvedModel, hint: adapter.modelValidationHint });
|
|
83018
83151
|
if (new Set(input.queries.map((query) => query.toLocaleLowerCase())).size !== input.queries.length) throw validationError("Research queries must be unique within a batch.");
|
|
@@ -83022,7 +83155,7 @@ async function researchRoutes(app, opts) {
|
|
|
83022
83155
|
const initiatedBy = researchPrincipal(request);
|
|
83023
83156
|
const decision = app.db.transaction((tx) => {
|
|
83024
83157
|
if (input.idempotencyKey) {
|
|
83025
|
-
const existing = tx.select().from(researchRuns).where(
|
|
83158
|
+
const existing = tx.select().from(researchRuns).where(and55(eq65(researchRuns.projectId, project.id), eq65(researchRuns.idempotencyKey, input.idempotencyKey))).get();
|
|
83026
83159
|
if (existing) {
|
|
83027
83160
|
if (existing.requestHash !== requestHash2) throw alreadyExists("Research idempotency key", input.idempotencyKey);
|
|
83028
83161
|
return { reused: true, id: existing.id, shouldDispatch: existing.status === ResearchRunStatuses.queued };
|
|
@@ -83030,7 +83163,7 @@ async function researchRoutes(app, opts) {
|
|
|
83030
83163
|
}
|
|
83031
83164
|
if (initiatedBy?.kind === "user" && initiatedBy.role === UserRoles.viewer) {
|
|
83032
83165
|
const { start, end, date } = utcDayBounds(now);
|
|
83033
|
-
const used = tx.select({ value: count3() }).from(researchRuns).where(
|
|
83166
|
+
const used = tx.select({ value: count3() }).from(researchRuns).where(and55(
|
|
83034
83167
|
eq65(researchRuns.projectId, project.id),
|
|
83035
83168
|
gte17(researchRuns.createdAt, start),
|
|
83036
83169
|
lt11(researchRuns.createdAt, end),
|
|
@@ -83057,12 +83190,18 @@ async function researchRoutes(app, opts) {
|
|
|
83057
83190
|
const limit = Number.isInteger(requested) && requested > 0 ? Math.min(requested, 100) : 20;
|
|
83058
83191
|
const runs2 = app.db.select().from(researchRuns).where(eq65(researchRuns.projectId, project.id)).orderBy(desc28(researchRuns.createdAt)).limit(limit).all().map(serializeRun);
|
|
83059
83192
|
const configured = new Set(opts.configuredProviderNames ?? []);
|
|
83060
|
-
const
|
|
83061
|
-
|
|
83062
|
-
|
|
83063
|
-
|
|
83064
|
-
|
|
83065
|
-
|
|
83193
|
+
const effectiveModels2 = opts.getEffectiveProviderModels?.() ?? {};
|
|
83194
|
+
const providers = await Promise.all((opts.providerAdapters ?? []).filter((adapter) => adapter.mode === "api" && !isBrowserProvider(adapter.name) && configured.has(adapter.name)).map(async (adapter) => {
|
|
83195
|
+
const defaultModel = project.providerModels[adapter.name] || effectiveModels2[adapter.name] || adapter.defaultModel;
|
|
83196
|
+
const discovered = opts.getProviderModels ? await opts.getProviderModels(adapter.name) : [];
|
|
83197
|
+
const models = discovered.length ? discovered : adapter.knownModels;
|
|
83198
|
+
return {
|
|
83199
|
+
name: adapter.name,
|
|
83200
|
+
displayName: adapter.displayName,
|
|
83201
|
+
modelConfigurable: adapter.modelConfigurable,
|
|
83202
|
+
defaultModel,
|
|
83203
|
+
knownModels: [...new Map([{ id: defaultModel, displayName: defaultModel }, ...models].map((model) => [model.id, { id: model.id, displayName: model.displayName }])).values()]
|
|
83204
|
+
};
|
|
83066
83205
|
}));
|
|
83067
83206
|
return { runs: runs2, providers };
|
|
83068
83207
|
});
|
|
@@ -83072,7 +83211,7 @@ async function researchRoutes(app, opts) {
|
|
|
83072
83211
|
});
|
|
83073
83212
|
}
|
|
83074
83213
|
function getDetail(app, projectId, id) {
|
|
83075
|
-
const row = app.db.select().from(researchRuns).where(
|
|
83214
|
+
const row = app.db.select().from(researchRuns).where(and55(eq65(researchRuns.id, id), eq65(researchRuns.projectId, projectId))).get();
|
|
83076
83215
|
if (!row) throw notFound("Research run", id);
|
|
83077
83216
|
const queries2 = app.db.select().from(researchRunQueries).where(eq65(researchRunQueries.researchRunId, id)).orderBy(researchRunQueries.position).all().map(serializeQuery);
|
|
83078
83217
|
return { ...serializeRun(row), queries: queries2 };
|
|
@@ -83102,7 +83241,7 @@ function utcDayBounds(now) {
|
|
|
83102
83241
|
|
|
83103
83242
|
// ../api-routes/src/simple-measurement-definitions.ts
|
|
83104
83243
|
import crypto50 from "crypto";
|
|
83105
|
-
import { and as
|
|
83244
|
+
import { and as and56, eq as eq66 } from "drizzle-orm";
|
|
83106
83245
|
function captureSimpleMeasurementDefinition(db, input) {
|
|
83107
83246
|
return db.transaction((tx) => {
|
|
83108
83247
|
const run = tx.select({
|
|
@@ -83110,7 +83249,7 @@ function captureSimpleMeasurementDefinition(db, input) {
|
|
|
83110
83249
|
trigger: runs.trigger,
|
|
83111
83250
|
status: runs.status,
|
|
83112
83251
|
measurementPlanVersionId: runs.measurementPlanVersionId
|
|
83113
|
-
}).from(runs).where(
|
|
83252
|
+
}).from(runs).where(and56(eq66(runs.projectId, input.projectId), eq66(runs.id, input.runId))).get();
|
|
83114
83253
|
if (!run) throw notFound("Run", input.runId);
|
|
83115
83254
|
if (run.kind !== RunKinds["answer-visibility"] || run.trigger === RunTriggers.probe || run.measurementPlanVersionId !== null) {
|
|
83116
83255
|
return null;
|
|
@@ -83120,7 +83259,7 @@ function captureSimpleMeasurementDefinition(db, input) {
|
|
|
83120
83259
|
if (definition.queries.some((query) => query.queryClass !== (classifier?.classify(query.queryText) ?? null))) {
|
|
83121
83260
|
throw validationError("Query classes must match the captured identity and text.");
|
|
83122
83261
|
}
|
|
83123
|
-
const existing = tx.select().from(simpleMeasurementDefinitions).where(
|
|
83262
|
+
const existing = tx.select().from(simpleMeasurementDefinitions).where(and56(eq66(simpleMeasurementDefinitions.projectId, input.projectId), eq66(simpleMeasurementDefinitions.runId, input.runId))).get();
|
|
83124
83263
|
if (existing) {
|
|
83125
83264
|
const frozen = simpleMeasurementDefinitionSchema.parse(existing.definition);
|
|
83126
83265
|
const replayDefinition = {
|
|
@@ -83307,6 +83446,7 @@ async function apiRoutes(app, opts) {
|
|
|
83307
83446
|
briefPromptVersion: opts.briefPromptVersion
|
|
83308
83447
|
});
|
|
83309
83448
|
await api.register(settingsRoutes, {
|
|
83449
|
+
getProviderModels: opts.getProviderModels,
|
|
83310
83450
|
providerSummary: opts.providerSummary,
|
|
83311
83451
|
providerAdapters: opts.providerAdapters,
|
|
83312
83452
|
onProviderUpdate: opts.onProviderUpdate,
|
|
@@ -83429,6 +83569,8 @@ async function apiRoutes(app, opts) {
|
|
|
83429
83569
|
embedQueries: opts.embedQueries
|
|
83430
83570
|
});
|
|
83431
83571
|
await api.register(researchRoutes, {
|
|
83572
|
+
getProviderModels: opts.getProviderModels,
|
|
83573
|
+
getEffectiveProviderModels: opts.getEffectiveProviderModels,
|
|
83432
83574
|
providerAdapters: opts.providerAdapters,
|
|
83433
83575
|
configuredProviderNames: opts.providerSummary?.filter((provider) => provider.configured).map((provider) => provider.name),
|
|
83434
83576
|
onResearchRunRequested: opts.onResearchRunRequested,
|
|
@@ -83915,14 +84057,14 @@ var IntelligenceService = class {
|
|
|
83915
84057
|
* Returns the analysis result for the coordinator to inspect (e.g. for webhook dispatch).
|
|
83916
84058
|
*/
|
|
83917
84059
|
analyzeAndPersist(runId, projectId) {
|
|
83918
|
-
const currentRunRecord = this.db.select().from(runs).where(
|
|
84060
|
+
const currentRunRecord = this.db.select().from(runs).where(and57(eq67(runs.id, runId), ...analyzableRunPredicates(projectId))).get();
|
|
83919
84061
|
if (!currentRunRecord) {
|
|
83920
84062
|
log.info("intelligence.skip", { runId, reason: "run not eligible for analysis" });
|
|
83921
84063
|
return null;
|
|
83922
84064
|
}
|
|
83923
84065
|
const currentLocation = currentRunRecord.location ?? null;
|
|
83924
84066
|
const recentRuns = this.db.select().from(runs).where(
|
|
83925
|
-
|
|
84067
|
+
and57(
|
|
83926
84068
|
...analyzableRunPredicates(projectId),
|
|
83927
84069
|
currentLocation === null ? isNull12(runs.location) : eq67(runs.location, currentLocation),
|
|
83928
84070
|
// Never look forward. The window is this run's own past, so
|
|
@@ -84015,7 +84157,7 @@ var IntelligenceService = class {
|
|
|
84015
84157
|
}
|
|
84016
84158
|
const windowStart = runRow.startedAt ?? runRow.createdAt;
|
|
84017
84159
|
const windowEnd = runRow.finishedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
84018
|
-
const selected = this.db.select().from(gbpLocations).where(
|
|
84160
|
+
const selected = this.db.select().from(gbpLocations).where(and57(
|
|
84019
84161
|
eq67(gbpLocations.projectId, projectId),
|
|
84020
84162
|
eq67(gbpLocations.selected, true),
|
|
84021
84163
|
gte18(gbpLocations.syncedAt, windowStart),
|
|
@@ -84052,12 +84194,12 @@ var IntelligenceService = class {
|
|
|
84052
84194
|
}
|
|
84053
84195
|
/** Build the per-location signal bundle the GBP analyzer consumes. */
|
|
84054
84196
|
buildGbpLocationSignals(projectId, locationName, displayName, fallbackDate) {
|
|
84055
|
-
const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(
|
|
84056
|
-
const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(
|
|
84057
|
-
const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(
|
|
84058
|
-
const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(
|
|
84197
|
+
const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(and57(eq67(gbpDailyMetrics.projectId, projectId), eq67(gbpDailyMetrics.locationName, locationName))).all();
|
|
84198
|
+
const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(and57(eq67(gbpPlaceActions.projectId, projectId), eq67(gbpPlaceActions.locationName, locationName))).all();
|
|
84199
|
+
const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and57(eq67(gbpLodgingSnapshots.projectId, projectId), eq67(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc29(gbpLodgingSnapshots.syncedAt)).limit(1).get();
|
|
84200
|
+
const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(and57(eq67(gbpLocations.projectId, projectId), eq67(gbpLocations.locationName, locationName))).get();
|
|
84059
84201
|
const descriptionMissing = !(ownerRow?.description ?? "").trim();
|
|
84060
|
-
const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(
|
|
84202
|
+
const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and57(eq67(gbpPlaceDetails.projectId, projectId), eq67(gbpPlaceDetails.locationName, locationName))).orderBy(desc29(gbpPlaceDetails.syncedAt)).limit(1).get();
|
|
84061
84203
|
const placesAmenities = placeRow ? extractPlaceAmenities(placeRow.attributes) : [];
|
|
84062
84204
|
const summary2 = buildGbpSummary({
|
|
84063
84205
|
locationName,
|
|
@@ -84093,7 +84235,7 @@ var IntelligenceService = class {
|
|
|
84093
84235
|
/** Build the month-over-month keyword series for a location from the
|
|
84094
84236
|
* accumulating gbp_keyword_monthly table (latest complete month vs prior). */
|
|
84095
84237
|
buildGbpKeywordTrend(projectId, locationName) {
|
|
84096
|
-
const rows = this.db.select({ month: gbpKeywordMonthly.month, keyword: gbpKeywordMonthly.keyword, valueCount: gbpKeywordMonthly.valueCount }).from(gbpKeywordMonthly).where(
|
|
84238
|
+
const rows = this.db.select({ month: gbpKeywordMonthly.month, keyword: gbpKeywordMonthly.keyword, valueCount: gbpKeywordMonthly.valueCount }).from(gbpKeywordMonthly).where(and57(eq67(gbpKeywordMonthly.projectId, projectId), eq67(gbpKeywordMonthly.locationName, locationName))).all();
|
|
84097
84239
|
if (rows.length === 0) return { recentMonth: null, priorMonth: null, points: [] };
|
|
84098
84240
|
const months = [...new Set(rows.map((r) => r.month))].sort().reverse();
|
|
84099
84241
|
const recentMonth = months[0] ?? null;
|
|
@@ -84124,7 +84266,7 @@ var IntelligenceService = class {
|
|
|
84124
84266
|
*/
|
|
84125
84267
|
persistGbpInsights(runId, projectId, gbpInsights, coveredLocationNames) {
|
|
84126
84268
|
const covered = new Set(coveredLocationNames);
|
|
84127
|
-
const existing = this.db.select({ id: insights.id, dismissed: insights.dismissed }).from(insights).where(
|
|
84269
|
+
const existing = this.db.select({ id: insights.id, dismissed: insights.dismissed }).from(insights).where(and57(eq67(insights.projectId, projectId), eq67(insights.provider, GBP_INSIGHT_PROVIDER))).all();
|
|
84128
84270
|
const staleIds = [];
|
|
84129
84271
|
const dismissedSlots = /* @__PURE__ */ new Set();
|
|
84130
84272
|
for (const row of existing) {
|
|
@@ -84233,7 +84375,7 @@ var IntelligenceService = class {
|
|
|
84233
84375
|
}
|
|
84234
84376
|
sinceTimestamp = parsed;
|
|
84235
84377
|
}
|
|
84236
|
-
const allRuns = this.db.select().from(runs).where(
|
|
84378
|
+
const allRuns = this.db.select().from(runs).where(and57(...analyzableRunPredicates(project.id))).orderBy(asc12(runs.finishedAt)).all();
|
|
84237
84379
|
const measuredRunIds = this.runIdsWithSnapshots(allRuns.map((r) => r.id));
|
|
84238
84380
|
const measuredRuns = allRuns.filter((r) => measuredRunIds.has(r.id));
|
|
84239
84381
|
let startIdx = 0;
|
|
@@ -84396,7 +84538,7 @@ var IntelligenceService = class {
|
|
|
84396
84538
|
clicks: gscSearchData.clicks,
|
|
84397
84539
|
impressions: gscSearchData.impressions,
|
|
84398
84540
|
position: gscSearchData.position
|
|
84399
|
-
}).from(gscSearchData).where(
|
|
84541
|
+
}).from(gscSearchData).where(and57(
|
|
84400
84542
|
eq67(gscSearchData.projectId, projectId),
|
|
84401
84543
|
gte18(gscSearchData.date, window.startDate),
|
|
84402
84544
|
lte15(gscSearchData.date, window.endDate)
|
|
@@ -84457,7 +84599,7 @@ var IntelligenceService = class {
|
|
|
84457
84599
|
);
|
|
84458
84600
|
const ROWS_PER_GROUP_BUDGET = Math.max(2, locationCount);
|
|
84459
84601
|
const recentRunRows = this.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
|
|
84460
|
-
|
|
84602
|
+
and57(
|
|
84461
84603
|
eq67(runs.projectId, projectId),
|
|
84462
84604
|
eq67(runs.kind, RunKinds["answer-visibility"]),
|
|
84463
84605
|
or14(eq67(runs.status, "completed"), eq67(runs.status, "partial")),
|
|
@@ -84480,7 +84622,7 @@ var IntelligenceService = class {
|
|
|
84480
84622
|
const haveHistory = recentRunIds.length > 0;
|
|
84481
84623
|
const priorRegressionsByPair = /* @__PURE__ */ new Map();
|
|
84482
84624
|
if (haveHistory) {
|
|
84483
|
-
const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(
|
|
84625
|
+
const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and57(eq67(insights.type, "regression"), inArray25(insights.runId, recentRunIds))).all();
|
|
84484
84626
|
const regressionGroups = /* @__PURE__ */ new Map();
|
|
84485
84627
|
for (const row of priorRows) {
|
|
84486
84628
|
if (!row.runId) continue;
|
|
@@ -84670,6 +84812,7 @@ export {
|
|
|
84670
84812
|
queueRunIfProjectIdle,
|
|
84671
84813
|
resolveMeasurementSitemapTarget,
|
|
84672
84814
|
nextRunFromCron,
|
|
84815
|
+
nextRunFromSchedule,
|
|
84673
84816
|
resolveWebhookTarget,
|
|
84674
84817
|
deliverWebhook,
|
|
84675
84818
|
redactNotificationUrl,
|