@canonry/canonry 5.13.0 → 5.15.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-DWDOPf8c.js → AuditHistoryPanel-BZJn-wvp.js} +1 -1
- package/assets/assets/{BacklinksPage-DGxq-iU6.js → BacklinksPage-DsQAKO31.js} +1 -1
- package/assets/assets/{HistoryPage-DR91m-gT.js → HistoryPage-DWn459Gu.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-a8poltfM.js → MeasurementPropertyPage-D6pUcBiT.js} +1 -1
- package/assets/assets/{ProjectPage-CCCJE7rA.js → ProjectPage-D-lDBpPV.js} +1 -1
- package/assets/assets/{RunRow-Xe63DyPK.js → RunRow-BJxx50Ar.js} +1 -1
- package/assets/assets/{RunsPage-DK119ZZw.js → RunsPage-DvoNDx6z.js} +1 -1
- package/assets/assets/{SettingsPage-G461foD-.js → SettingsPage-DXbhM5Lv.js} +1 -1
- package/assets/assets/{SiteHealthSection-CJnHkGM2.js → SiteHealthSection-4mMfc6Rb.js} +3 -3
- package/assets/assets/{TrafficPage-AsWgc7Ot.js → TrafficPage-EYSxLxkQ.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-D10yBQoD.js → TrafficSourceDetailPage-DY4sV_BX.js} +1 -1
- package/assets/assets/{extract-error-message-PP4HD_Dp.js → extract-error-message-BMpWRqf9.js} +1 -1
- package/assets/assets/{index-CCIeAE4J.js → index-KCAlcuMN.js} +22 -22
- package/assets/assets/{react-sigma_core.esm.min-CkyyYkKU.js → react-sigma_core.esm.min-CHepSGqZ.js} +1 -1
- package/assets/assets/{v2-overview-adapter-DW-In1hp.js → v2-overview-adapter-CpM-FjB_.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-Q35D2R2P.js → chunk-3YAPVVFN.js} +173 -52
- package/dist/{chunk-IDZQ5H3J.js → chunk-CDQDPUY4.js} +2 -2
- package/dist/{chunk-6YLNO2T5.js → chunk-JO5HHEJV.js} +2 -2
- package/dist/{chunk-UWJAATGC.js → chunk-L36TC6LB.js} +90 -7
- package/dist/{chunk-TDHRUXN3.js → chunk-SJ7ZOFL5.js} +92 -31
- package/dist/{chunk-IPGBK7XR.js → chunk-ZGZSROSR.js} +1 -1
- package/dist/cli.js +7 -7
- package/dist/{demo-server-IZFTJI7E.js → demo-server-QLQUVMKJ.js} +3 -3
- package/dist/index.js +5 -5
- package/dist/{intelligence-service-PM7MC5VC.js → intelligence-service-EAUKUVVM.js} +2 -2
- package/dist/mcp.js +3 -3
- package/package.json +7 -7
|
@@ -404,6 +404,7 @@ import {
|
|
|
404
404
|
internalError,
|
|
405
405
|
intersectScopes,
|
|
406
406
|
isBrowserProvider,
|
|
407
|
+
isListingMarketplace,
|
|
407
408
|
isLocationRedirectStatus,
|
|
408
409
|
isReadOnlyKey,
|
|
409
410
|
isRetryableHttpError,
|
|
@@ -783,10 +784,10 @@ import {
|
|
|
783
784
|
wordpressSchemaDeployResultDtoSchema,
|
|
784
785
|
wordpressSchemaStatusResultDtoSchema,
|
|
785
786
|
wordpressStatusDtoSchema
|
|
786
|
-
} from "./chunk-
|
|
787
|
+
} from "./chunk-L36TC6LB.js";
|
|
787
788
|
|
|
788
789
|
// src/intelligence-service.ts
|
|
789
|
-
import { eq as
|
|
790
|
+
import { eq as eq71, desc as desc32, asc as asc12, and as and60, ne as ne11, or as or18, inArray as inArray27, gte as gte18, lte as lte15, isNull as isNull13, sql as sql28, exists } from "drizzle-orm";
|
|
790
791
|
|
|
791
792
|
// ../db/src/client.ts
|
|
792
793
|
import { mkdirSync } from "fs";
|
|
@@ -3296,6 +3297,7 @@ var adsCampaigns = sqliteTable("ads_campaigns", {
|
|
|
3296
3297
|
lifetimeSpendLimitMicros: integer("lifetime_spend_limit_micros"),
|
|
3297
3298
|
conversionEventSettingIds: text("conversion_event_setting_ids", { mode: "json" }).$type().notNull().default([]),
|
|
3298
3299
|
targeting: text("targeting", { mode: "json" }).$type(),
|
|
3300
|
+
landingPageQueryStringTemplate: text("landing_page_query_string_template"),
|
|
3299
3301
|
upstreamCreatedAt: integer("upstream_created_at"),
|
|
3300
3302
|
upstreamUpdatedAt: integer("upstream_updated_at"),
|
|
3301
3303
|
syncRunId: text("sync_run_id").references(() => runs.id, { onDelete: "set null" }),
|
|
@@ -3313,6 +3315,7 @@ var adsAdGroups = sqliteTable("ads_ad_groups", {
|
|
|
3313
3315
|
billingEventType: text("billing_event_type"),
|
|
3314
3316
|
maxBidMicros: integer("max_bid_micros"),
|
|
3315
3317
|
contextHints: text("context_hints", { mode: "json" }).$type().notNull().default([]),
|
|
3318
|
+
landingPageQueryStringTemplate: text("landing_page_query_string_template"),
|
|
3316
3319
|
upstreamCreatedAt: integer("upstream_created_at"),
|
|
3317
3320
|
upstreamUpdatedAt: integer("upstream_updated_at"),
|
|
3318
3321
|
syncRunId: text("sync_run_id").references(() => runs.id, { onDelete: "set null" }),
|
|
@@ -3329,6 +3332,7 @@ var adsAds = sqliteTable("ads_ads", {
|
|
|
3329
3332
|
status: text("status").notNull(),
|
|
3330
3333
|
creative: text("creative", { mode: "json" }).$type(),
|
|
3331
3334
|
reviewStatus: text("review_status"),
|
|
3335
|
+
landingPageQueryStringTemplate: text("landing_page_query_string_template"),
|
|
3332
3336
|
upstreamCreatedAt: integer("upstream_created_at"),
|
|
3333
3337
|
upstreamUpdatedAt: integer("upstream_updated_at"),
|
|
3334
3338
|
syncRunId: text("sync_run_id").references(() => runs.id, { onDelete: "set null" }),
|
|
@@ -7515,6 +7519,19 @@ var MIGRATION_VERSIONS = [
|
|
|
7515
7519
|
`CREATE INDEX IF NOT EXISTS idx_run_fills_run ON run_fills(run_id, created_at)`,
|
|
7516
7520
|
`CREATE INDEX IF NOT EXISTS idx_run_fills_project_status ON run_fills(project_id, status)`
|
|
7517
7521
|
]
|
|
7522
|
+
},
|
|
7523
|
+
{
|
|
7524
|
+
// Ad URL tracking parameters (`landing_page_configuration.
|
|
7525
|
+
// query_string_template` upstream): the provider appends them to every
|
|
7526
|
+
// click URL under the entity. Stored per level because campaign, ad group,
|
|
7527
|
+
// and ad each carry their own, and upstream combines them.
|
|
7528
|
+
version: 161,
|
|
7529
|
+
name: "ads-landing-page-tracking-template",
|
|
7530
|
+
statements: [
|
|
7531
|
+
`ALTER TABLE ads_campaigns ADD COLUMN landing_page_query_string_template TEXT`,
|
|
7532
|
+
`ALTER TABLE ads_ad_groups ADD COLUMN landing_page_query_string_template TEXT`,
|
|
7533
|
+
`ALTER TABLE ads_ads ADD COLUMN landing_page_query_string_template TEXT`
|
|
7534
|
+
]
|
|
7518
7535
|
}
|
|
7519
7536
|
];
|
|
7520
7537
|
function addRunsMeasurementPlanVersionForeignKey(tx) {
|
|
@@ -19691,12 +19708,12 @@ function upsertCompetitor(authoring, body) {
|
|
|
19691
19708
|
};
|
|
19692
19709
|
}
|
|
19693
19710
|
function removeCompetitor(authoring, body) {
|
|
19694
|
-
const { groupKey, competitorKey } = parseBody(measurementDraftRemoveCompetitorRequestSchema, body, "remove-competitor");
|
|
19711
|
+
const { groupKey, competitorKey: competitorKey2 } = parseBody(measurementDraftRemoveCompetitorRequestSchema, body, "remove-competitor");
|
|
19695
19712
|
requireGroup(authoring, groupKey);
|
|
19696
19713
|
return {
|
|
19697
19714
|
authoring: {
|
|
19698
19715
|
...authoring,
|
|
19699
|
-
groups: authoring.groups.map((group) => group.stableKey === groupKey ? { ...group, competitors: group.competitors.filter((competitor) => competitor.stableKey !==
|
|
19716
|
+
groups: authoring.groups.map((group) => group.stableKey === groupKey ? { ...group, competitors: group.competitors.filter((competitor) => competitor.stableKey !== competitorKey2) } : group)
|
|
19700
19717
|
},
|
|
19701
19718
|
warnings: []
|
|
19702
19719
|
};
|
|
@@ -40583,7 +40600,8 @@ var routeCatalog = [
|
|
|
40583
40600
|
uniqueItems: true,
|
|
40584
40601
|
items: stringSchema,
|
|
40585
40602
|
description: "Optional conversion events to optimize delivery toward. Independent of biddingType: a clicks campaign may omit these."
|
|
40586
|
-
}
|
|
40603
|
+
},
|
|
40604
|
+
landingPageQueryStringTemplate: { type: "string", minLength: 1, maxLength: 1e3, description: "Tracking parameters appended to click URLs under this entity, as a bare query string (utm_source=chatgpt&utm_medium=cpc). Supports the {campaign_id}, {ad_group_id}, {ad_id}, {ad_account_id} and {oppref} macros. Levels combine; on a duplicate key the destination URL wins, then ad, ad group, campaign." }
|
|
40587
40605
|
}
|
|
40588
40606
|
} } }
|
|
40589
40607
|
},
|
|
@@ -40615,7 +40633,8 @@ var routeCatalog = [
|
|
|
40615
40633
|
description: stringSchema,
|
|
40616
40634
|
contextHints: { type: "array", minItems: 1, maxItems: 100, items: stringSchema },
|
|
40617
40635
|
maxBidMicros: { type: "integer", minimum: 1, maximum: 1e8 },
|
|
40618
|
-
billingEventType: { type: "string", enum: Object.values(AdsAdGroupBillingEventTypes) }
|
|
40636
|
+
billingEventType: { type: "string", enum: Object.values(AdsAdGroupBillingEventTypes) },
|
|
40637
|
+
landingPageQueryStringTemplate: { type: "string", minLength: 1, maxLength: 1e3, description: "Tracking parameters appended to click URLs under this entity, as a bare query string (utm_source=chatgpt&utm_medium=cpc). Supports the {campaign_id}, {ad_group_id}, {ad_id}, {ad_account_id} and {oppref} macros. Levels combine; on a duplicate key the destination URL wins, then ad, ad group, campaign." }
|
|
40619
40638
|
}
|
|
40620
40639
|
} } }
|
|
40621
40640
|
},
|
|
@@ -40644,7 +40663,8 @@ var routeCatalog = [
|
|
|
40644
40663
|
operationKey: adsOperationKeySchema,
|
|
40645
40664
|
adGroupId: stringSchema,
|
|
40646
40665
|
name: { type: "string", minLength: 3, maxLength: 1e3 },
|
|
40647
|
-
creative: adsCreativeRequestSchema
|
|
40666
|
+
creative: adsCreativeRequestSchema,
|
|
40667
|
+
landingPageQueryStringTemplate: { type: "string", minLength: 1, maxLength: 1e3, description: "Tracking parameters appended to click URLs under this entity, as a bare query string (utm_source=chatgpt&utm_medium=cpc). Supports the {campaign_id}, {ad_group_id}, {ad_id}, {ad_account_id} and {oppref} macros. Levels combine; on a duplicate key the destination URL wins, then ad, ad group, campaign." }
|
|
40648
40668
|
}
|
|
40649
40669
|
} } }
|
|
40650
40670
|
},
|
|
@@ -40677,7 +40697,8 @@ var routeCatalog = [
|
|
|
40677
40697
|
startTime: { type: "integer", nullable: true },
|
|
40678
40698
|
endTime: { type: "integer", nullable: true },
|
|
40679
40699
|
lifetimeSpendLimitMicros: { type: "integer", minimum: 1e6 },
|
|
40680
|
-
locationIds: { type: "array", minItems: 1, maxItems: 100, items: stringSchema }
|
|
40700
|
+
locationIds: { type: "array", minItems: 1, maxItems: 100, items: stringSchema },
|
|
40701
|
+
landingPageQueryStringTemplate: { type: "string", minLength: 1, maxLength: 1e3, nullable: true, description: "Tracking parameters appended to click URLs under this entity, as a bare query string. Null clears them." }
|
|
40681
40702
|
}
|
|
40682
40703
|
} } }
|
|
40683
40704
|
},
|
|
@@ -40708,7 +40729,8 @@ var routeCatalog = [
|
|
|
40708
40729
|
name: { type: "string", minLength: 3, maxLength: 1e3 },
|
|
40709
40730
|
description: { type: "string", nullable: true },
|
|
40710
40731
|
contextHints: { type: "array", minItems: 1, maxItems: 100, items: stringSchema },
|
|
40711
|
-
maxBidMicros: { type: "integer", minimum: 1, maximum: 1e8 }
|
|
40732
|
+
maxBidMicros: { type: "integer", minimum: 1, maximum: 1e8 },
|
|
40733
|
+
landingPageQueryStringTemplate: { type: "string", minLength: 1, maxLength: 1e3, nullable: true, description: "Tracking parameters appended to click URLs under this entity, as a bare query string. Null clears them." }
|
|
40712
40734
|
}
|
|
40713
40735
|
} } }
|
|
40714
40736
|
},
|
|
@@ -40737,7 +40759,8 @@ var routeCatalog = [
|
|
|
40737
40759
|
operationKey: adsOperationKeySchema,
|
|
40738
40760
|
expectedUpdatedAt: integerSchema,
|
|
40739
40761
|
name: { type: "string", minLength: 3, maxLength: 1e3 },
|
|
40740
|
-
creative: adsCreativeRequestSchema
|
|
40762
|
+
creative: adsCreativeRequestSchema,
|
|
40763
|
+
landingPageQueryStringTemplate: { type: "string", minLength: 1, maxLength: 1e3, nullable: true, description: "Tracking parameters appended to click URLs under this entity, as a bare query string. Null clears them." }
|
|
40741
40764
|
}
|
|
40742
40765
|
} } }
|
|
40743
40766
|
},
|
|
@@ -52444,7 +52467,8 @@ function campaignCreateReconcileFields(input) {
|
|
|
52444
52467
|
lifetimeSpendLimitMicros: input.lifetimeSpendLimitMicros,
|
|
52445
52468
|
locationIds: normalizeStringSet(input.locationIds),
|
|
52446
52469
|
biddingType: input.biddingType,
|
|
52447
|
-
conversionEventSettingIds: normalizeStringSet(input.conversionEventSettingIds ?? [])
|
|
52470
|
+
conversionEventSettingIds: normalizeStringSet(input.conversionEventSettingIds ?? []),
|
|
52471
|
+
...input.landingPageQueryStringTemplate === void 0 ? {} : { landingPageQueryStringTemplate: input.landingPageQueryStringTemplate }
|
|
52448
52472
|
};
|
|
52449
52473
|
}
|
|
52450
52474
|
function adGroupCreateReconcileFields(input) {
|
|
@@ -52455,7 +52479,8 @@ function adGroupCreateReconcileFields(input) {
|
|
|
52455
52479
|
status: AdsEntityStatuses.paused,
|
|
52456
52480
|
contextHints: normalizeStringSet(input.contextHints),
|
|
52457
52481
|
maxBidMicros: input.maxBidMicros,
|
|
52458
|
-
billingEventType: input.billingEventType
|
|
52482
|
+
billingEventType: input.billingEventType,
|
|
52483
|
+
...input.landingPageQueryStringTemplate === void 0 ? {} : { landingPageQueryStringTemplate: input.landingPageQueryStringTemplate }
|
|
52459
52484
|
};
|
|
52460
52485
|
}
|
|
52461
52486
|
function adCreateReconcileFields(input) {
|
|
@@ -52463,7 +52488,8 @@ function adCreateReconcileFields(input) {
|
|
|
52463
52488
|
adGroupId: input.adGroupId,
|
|
52464
52489
|
name: normalizeString(input.name),
|
|
52465
52490
|
status: AdsEntityStatuses.paused,
|
|
52466
|
-
creativeFingerprint: creativeFingerprint(input.creative)
|
|
52491
|
+
creativeFingerprint: creativeFingerprint(input.creative),
|
|
52492
|
+
...input.landingPageQueryStringTemplate === void 0 ? {} : { landingPageQueryStringTemplate: input.landingPageQueryStringTemplate }
|
|
52467
52493
|
};
|
|
52468
52494
|
}
|
|
52469
52495
|
function updateReconcileFields(entityType, update) {
|
|
@@ -52471,6 +52497,10 @@ function updateReconcileFields(entityType, update) {
|
|
|
52471
52497
|
if (typeof update.name === "string") fields.name = normalizeString(update.name);
|
|
52472
52498
|
if (update.description === null) fields.description = null;
|
|
52473
52499
|
else if (typeof update.description === "string") fields.description = normalizeString(update.description);
|
|
52500
|
+
if (update.landingPageQueryStringTemplate === null) fields.landingPageQueryStringTemplate = null;
|
|
52501
|
+
else if (typeof update.landingPageQueryStringTemplate === "string") {
|
|
52502
|
+
fields.landingPageQueryStringTemplate = update.landingPageQueryStringTemplate;
|
|
52503
|
+
}
|
|
52474
52504
|
if (entityType === AdsEntityTypes.campaign) {
|
|
52475
52505
|
if (update.startTime === null || typeof update.startTime === "number") fields.startTime = update.startTime;
|
|
52476
52506
|
if (update.endTime === null || typeof update.endTime === "number") fields.endTime = update.endTime;
|
|
@@ -52512,6 +52542,10 @@ function entityReconcileFields(entity) {
|
|
|
52512
52542
|
} else if (Array.isArray(entity.conversionEventSettingIds)) {
|
|
52513
52543
|
fields.conversionEventSettingIds = normalizeStringSet(entity.conversionEventSettingIds);
|
|
52514
52544
|
}
|
|
52545
|
+
if (entity.landingPageQueryStringTemplate === null) fields.landingPageQueryStringTemplate = null;
|
|
52546
|
+
else if (typeof entity.landingPageQueryStringTemplate === "string") {
|
|
52547
|
+
fields.landingPageQueryStringTemplate = entity.landingPageQueryStringTemplate;
|
|
52548
|
+
}
|
|
52515
52549
|
if (typeof entity.campaignId === "string") fields.campaignId = entity.campaignId;
|
|
52516
52550
|
if (Array.isArray(entity.contextHints)) fields.contextHints = normalizeStringSet(entity.contextHints);
|
|
52517
52551
|
if (typeof entity.maxBidMicros === "number") fields.maxBidMicros = entity.maxBidMicros;
|
|
@@ -54055,6 +54089,7 @@ async function adsRoutes(app, opts) {
|
|
|
54055
54089
|
status: ad.status,
|
|
54056
54090
|
reviewStatus: ad.reviewStatus,
|
|
54057
54091
|
creative: creativeDto(ad.creative),
|
|
54092
|
+
landingPageQueryStringTemplate: ad.landingPageQueryStringTemplate,
|
|
54058
54093
|
upstreamUpdatedAt: ad.upstreamUpdatedAt,
|
|
54059
54094
|
syncedAt: ad.syncedAt
|
|
54060
54095
|
};
|
|
@@ -54074,6 +54109,7 @@ async function adsRoutes(app, opts) {
|
|
|
54074
54109
|
maxBidMicros: group.maxBidMicros,
|
|
54075
54110
|
contextHints: group.contextHints,
|
|
54076
54111
|
ads: adsByGroup.get(group.id) ?? [],
|
|
54112
|
+
landingPageQueryStringTemplate: group.landingPageQueryStringTemplate,
|
|
54077
54113
|
upstreamUpdatedAt: group.upstreamUpdatedAt,
|
|
54078
54114
|
syncedAt: group.syncedAt
|
|
54079
54115
|
};
|
|
@@ -54094,6 +54130,7 @@ async function adsRoutes(app, opts) {
|
|
|
54094
54130
|
lifetimeSpendLimitMicros: campaign.lifetimeSpendLimitMicros,
|
|
54095
54131
|
locationIds: locationIdsDto(campaign.targeting),
|
|
54096
54132
|
adGroups: groupsByCampaign.get(campaign.id) ?? [],
|
|
54133
|
+
landingPageQueryStringTemplate: campaign.landingPageQueryStringTemplate,
|
|
54097
54134
|
upstreamUpdatedAt: campaign.upstreamUpdatedAt,
|
|
54098
54135
|
syncedAt: campaign.syncedAt
|
|
54099
54136
|
}));
|
|
@@ -85596,9 +85633,88 @@ function utcDayBounds(now) {
|
|
|
85596
85633
|
return { start, end, date };
|
|
85597
85634
|
}
|
|
85598
85635
|
|
|
85636
|
+
// ../api-routes/src/plan-competitors.ts
|
|
85637
|
+
import { eq as eq69 } from "drizzle-orm";
|
|
85638
|
+
function competitorKey(value) {
|
|
85639
|
+
const host = (hostOf(value) ?? value).trim().toLowerCase().replace(/\.$/, "");
|
|
85640
|
+
return host.startsWith("www.") ? host.slice(4) : host;
|
|
85641
|
+
}
|
|
85642
|
+
function merge(into, domain, names) {
|
|
85643
|
+
const key = competitorKey(domain);
|
|
85644
|
+
if (!key) return;
|
|
85645
|
+
const set = into.get(key) ?? /* @__PURE__ */ new Set();
|
|
85646
|
+
for (const name of names) if (name.trim()) set.add(name.trim());
|
|
85647
|
+
into.set(key, set);
|
|
85648
|
+
}
|
|
85649
|
+
function toList(merged) {
|
|
85650
|
+
return [...merged].sort(([left], [right]) => left.localeCompare(right)).map(([domain, names]) => ({ domain, aliases: [...names] }));
|
|
85651
|
+
}
|
|
85652
|
+
function readScope(db, versionId) {
|
|
85653
|
+
const row = db.select({ canonicalJson: measurementPlanVersions.canonicalJson }).from(measurementPlanVersions).where(eq69(measurementPlanVersions.id, versionId)).get();
|
|
85654
|
+
if (!row) return null;
|
|
85655
|
+
let groups;
|
|
85656
|
+
let edges;
|
|
85657
|
+
try {
|
|
85658
|
+
const plan = parseStoredMeasurementPlanAnyVersion(row.canonicalJson);
|
|
85659
|
+
if (plan.schemaVersion === MEASUREMENT_PLAN_V2_SCHEMA_VERSION) {
|
|
85660
|
+
groups = plan.groups.map((group) => ({
|
|
85661
|
+
targetKeys: group.targetKeys,
|
|
85662
|
+
competitors: group.competitors.map((competitor) => ({ domain: competitor.domain, names: [competitor.label, ...competitor.aliases] }))
|
|
85663
|
+
}));
|
|
85664
|
+
edges = plan.usageEdges;
|
|
85665
|
+
} else {
|
|
85666
|
+
groups = plan.groups.map((group) => ({
|
|
85667
|
+
targetKeys: group.targetKeys,
|
|
85668
|
+
competitors: (group.competitors ?? []).map((domain) => ({ domain, names: [] }))
|
|
85669
|
+
}));
|
|
85670
|
+
edges = plan.usageEdges.flatMap((edge) => edge.kind === "target" ? [edge] : []);
|
|
85671
|
+
}
|
|
85672
|
+
} catch {
|
|
85673
|
+
return null;
|
|
85674
|
+
}
|
|
85675
|
+
const all = /* @__PURE__ */ new Map();
|
|
85676
|
+
const groupsByTarget = /* @__PURE__ */ new Map();
|
|
85677
|
+
groups.forEach((group, index2) => {
|
|
85678
|
+
for (const competitor of group.competitors) merge(all, competitor.domain, competitor.names);
|
|
85679
|
+
for (const target of group.targetKeys) groupsByTarget.set(target, [...groupsByTarget.get(target) ?? [], index2]);
|
|
85680
|
+
});
|
|
85681
|
+
const nodeGroups = /* @__PURE__ */ new Map();
|
|
85682
|
+
for (const edge of edges) {
|
|
85683
|
+
const set = nodeGroups.get(edge.executionNodeKey) ?? /* @__PURE__ */ new Set();
|
|
85684
|
+
for (const index2 of groupsByTarget.get(edge.targetKey) ?? []) set.add(index2);
|
|
85685
|
+
nodeGroups.set(edge.executionNodeKey, set);
|
|
85686
|
+
}
|
|
85687
|
+
const byNode = /* @__PURE__ */ new Map();
|
|
85688
|
+
for (const [node, indexes] of nodeGroups) {
|
|
85689
|
+
const merged = /* @__PURE__ */ new Map();
|
|
85690
|
+
for (const index2 of indexes) for (const competitor of groups[index2].competitors) merge(merged, competitor.domain, competitor.names);
|
|
85691
|
+
byNode.set(node, toList(merged));
|
|
85692
|
+
}
|
|
85693
|
+
return { all: toList(all), byNode };
|
|
85694
|
+
}
|
|
85695
|
+
function createRunCompetitorResolver(db, projectCompetitorDomains) {
|
|
85696
|
+
const scopes = /* @__PURE__ */ new Map();
|
|
85697
|
+
const listOnly = () => ({ domains: [...new Set(projectCompetitorDomains)], aliases: /* @__PURE__ */ new Map() });
|
|
85698
|
+
return (versionId, executionId) => {
|
|
85699
|
+
if (!versionId || !executionId) return listOnly();
|
|
85700
|
+
if (!scopes.has(versionId)) scopes.set(versionId, readScope(db, versionId));
|
|
85701
|
+
const pinned = scopes.get(versionId)?.byNode.get(executionId) ?? [];
|
|
85702
|
+
if (pinned.length === 0) return listOnly();
|
|
85703
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
85704
|
+
for (const domain of projectCompetitorDomains) if (!byKey.has(competitorKey(domain))) byKey.set(competitorKey(domain), domain);
|
|
85705
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
85706
|
+
for (const competitor of pinned) {
|
|
85707
|
+
const domain = byKey.get(competitor.domain) ?? competitor.domain;
|
|
85708
|
+
byKey.set(competitor.domain, domain);
|
|
85709
|
+
if (competitor.aliases.length) aliases.set(domain, competitor.aliases);
|
|
85710
|
+
}
|
|
85711
|
+
return { domains: [.../* @__PURE__ */ new Set([...projectCompetitorDomains, ...byKey.values()])], aliases };
|
|
85712
|
+
};
|
|
85713
|
+
}
|
|
85714
|
+
|
|
85599
85715
|
// ../api-routes/src/simple-measurement-definitions.ts
|
|
85600
85716
|
import crypto51 from "crypto";
|
|
85601
|
-
import { and as and59, eq as
|
|
85717
|
+
import { and as and59, eq as eq70 } from "drizzle-orm";
|
|
85602
85718
|
function captureSimpleMeasurementDefinition(db, input) {
|
|
85603
85719
|
return db.transaction((tx) => {
|
|
85604
85720
|
const run = tx.select({
|
|
@@ -85606,7 +85722,7 @@ function captureSimpleMeasurementDefinition(db, input) {
|
|
|
85606
85722
|
trigger: runs.trigger,
|
|
85607
85723
|
status: runs.status,
|
|
85608
85724
|
measurementPlanVersionId: runs.measurementPlanVersionId
|
|
85609
|
-
}).from(runs).where(and59(
|
|
85725
|
+
}).from(runs).where(and59(eq70(runs.projectId, input.projectId), eq70(runs.id, input.runId))).get();
|
|
85610
85726
|
if (!run) throw notFound("Run", input.runId);
|
|
85611
85727
|
if (run.kind !== RunKinds["answer-visibility"] || run.trigger === RunTriggers.probe || run.measurementPlanVersionId !== null) {
|
|
85612
85728
|
return null;
|
|
@@ -85616,7 +85732,7 @@ function captureSimpleMeasurementDefinition(db, input) {
|
|
|
85616
85732
|
if (definition.queries.some((query) => query.queryClass !== (classifier?.classify(query.queryText) ?? null))) {
|
|
85617
85733
|
throw validationError("Query classes must match the captured identity and text.");
|
|
85618
85734
|
}
|
|
85619
|
-
const existing = tx.select().from(simpleMeasurementDefinitions).where(and59(
|
|
85735
|
+
const existing = tx.select().from(simpleMeasurementDefinitions).where(and59(eq70(simpleMeasurementDefinitions.projectId, input.projectId), eq70(simpleMeasurementDefinitions.runId, input.runId))).get();
|
|
85620
85736
|
if (existing) {
|
|
85621
85737
|
const frozen = simpleMeasurementDefinitionSchema.parse(existing.definition);
|
|
85622
85738
|
const replayDefinition = {
|
|
@@ -85637,15 +85753,15 @@ function captureSimpleMeasurementDefinition(db, input) {
|
|
|
85637
85753
|
if (run.status !== RunStatuses.running) {
|
|
85638
85754
|
throw validationError("Only a running run can capture a new measurement definition.");
|
|
85639
85755
|
}
|
|
85640
|
-
if (tx.select({ id: querySnapshots.id }).from(querySnapshots).where(
|
|
85756
|
+
if (tx.select({ id: querySnapshots.id }).from(querySnapshots).where(eq70(querySnapshots.runId, input.runId)).limit(1).get()) {
|
|
85641
85757
|
throw validationError("This run already has stored answers. Its measurement definition cannot be inferred afterward.");
|
|
85642
85758
|
}
|
|
85643
|
-
const projectQueryIds = new Set(tx.select({ id: queries.id }).from(queries).where(
|
|
85759
|
+
const projectQueryIds = new Set(tx.select({ id: queries.id }).from(queries).where(eq70(queries.projectId, input.projectId)).all().map((query) => query.id));
|
|
85644
85760
|
if (definition.queries.some((query) => !projectQueryIds.has(query.queryId))) {
|
|
85645
85761
|
throw validationError("Every captured query must belong to the run project.");
|
|
85646
85762
|
}
|
|
85647
85763
|
if (definition.competitors !== void 0) {
|
|
85648
|
-
const liveCompetitorDomains = new Set(tx.select({ domain: competitors.domain }).from(competitors).where(
|
|
85764
|
+
const liveCompetitorDomains = new Set(tx.select({ domain: competitors.domain }).from(competitors).where(eq70(competitors.projectId, input.projectId)).all().map((competitor) => competitor.domain));
|
|
85649
85765
|
const capturedDomains = new Set(definition.competitors.map((competitor) => competitor.domain));
|
|
85650
85766
|
if (liveCompetitorDomains.size !== capturedDomains.size || [...liveCompetitorDomains].some((domain) => !capturedDomains.has(domain))) {
|
|
85651
85767
|
throw validationError("Captured competitors must exactly match the project competitors dispatched for this run.");
|
|
@@ -86462,7 +86578,7 @@ function determineCitationState(normalized, domains) {
|
|
|
86462
86578
|
}
|
|
86463
86579
|
return "not-cited";
|
|
86464
86580
|
}
|
|
86465
|
-
function computeCompetitorOverlap(normalized, competitorDomains) {
|
|
86581
|
+
function computeCompetitorOverlap(normalized, competitorDomains, competitorAliases = /* @__PURE__ */ new Map()) {
|
|
86466
86582
|
const overlapSet = /* @__PURE__ */ new Set();
|
|
86467
86583
|
for (const d of normalized.citedDomains) {
|
|
86468
86584
|
for (const cd of competitorDomains) {
|
|
@@ -86487,6 +86603,10 @@ function computeCompetitorOverlap(normalized, competitorDomains) {
|
|
|
86487
86603
|
if (brandKeyFromText(brand).length >= 4 && textContainsBrandAlias(normalized.answerText, brand)) {
|
|
86488
86604
|
overlapSet.add(cd);
|
|
86489
86605
|
}
|
|
86606
|
+
const named = competitorAliases.get(cd);
|
|
86607
|
+
if (named?.length && textContainsAnyBrandAlias(normalized.answerText, named)) {
|
|
86608
|
+
overlapSet.add(cd);
|
|
86609
|
+
}
|
|
86490
86610
|
}
|
|
86491
86611
|
}
|
|
86492
86612
|
return [...overlapSet];
|
|
@@ -86500,7 +86620,7 @@ function computeCitedCompetitorDomains(citedDomains, competitorDomains) {
|
|
|
86500
86620
|
}
|
|
86501
86621
|
return [...citedCompetitors];
|
|
86502
86622
|
}
|
|
86503
|
-
function extractRecommendedCompetitors(answerText, ownDomains, citedDomains, competitorDomains, ownBrandNames = []) {
|
|
86623
|
+
function extractRecommendedCompetitors(answerText, ownDomains, citedDomains, competitorDomains, ownBrandNames = [], competitorAliases = /* @__PURE__ */ new Map()) {
|
|
86504
86624
|
if (!answerText || answerText.length < 20) return [];
|
|
86505
86625
|
const ownBrandAliases = new Set(
|
|
86506
86626
|
ownDomains.flatMap((domain) => collectBrandAliasesFromDomain(domain))
|
|
@@ -86510,7 +86630,7 @@ function extractRecommendedCompetitors(answerText, ownDomains, citedDomains, com
|
|
|
86510
86630
|
}
|
|
86511
86631
|
const ownKeys = new Set([...ownBrandAliases].map(brandKeyFromText));
|
|
86512
86632
|
const knownCompetitorAliases = new Set(
|
|
86513
|
-
[...citedDomains, ...competitorDomains].flatMap((domain) => collectBrandAliasesFromDomain(domain)).filter((alias2) => !ownKeys.has(brandKeyFromText(alias2)))
|
|
86633
|
+
[...citedDomains.filter((domain) => !isListingMarketplace(domain)), ...competitorDomains].flatMap((domain) => collectBrandAliasesFromDomain(domain)).concat([...competitorAliases.values()].flat()).filter((alias2) => !ownKeys.has(brandKeyFromText(alias2)))
|
|
86514
86634
|
);
|
|
86515
86635
|
if (knownCompetitorAliases.size === 0) return [];
|
|
86516
86636
|
const candidatePatterns = [
|
|
@@ -86592,10 +86712,10 @@ var log = createLogger("IntelligenceService");
|
|
|
86592
86712
|
var runChronologyKey = sql28`coalesce(${runs.finishedAt}, ${runs.createdAt})`;
|
|
86593
86713
|
function analyzableRunPredicates(projectId) {
|
|
86594
86714
|
return [
|
|
86595
|
-
|
|
86715
|
+
eq71(runs.projectId, projectId),
|
|
86596
86716
|
// Only this kind writes query_snapshots.
|
|
86597
|
-
|
|
86598
|
-
or18(
|
|
86717
|
+
eq71(runs.kind, RunKinds["answer-visibility"]),
|
|
86718
|
+
or18(eq71(runs.status, RunStatuses.completed), eq71(runs.status, RunStatuses.partial)),
|
|
86599
86719
|
// Defensive: RunCoordinator already skips probes before analyzeAndPersist
|
|
86600
86720
|
// is called, but a future call site invoking it directly for a probe must
|
|
86601
86721
|
// still not pollute the intelligence window.
|
|
@@ -86640,7 +86760,7 @@ var IntelligenceService = class {
|
|
|
86640
86760
|
* Returns the analysis result for the coordinator to inspect (e.g. for webhook dispatch).
|
|
86641
86761
|
*/
|
|
86642
86762
|
analyzeAndPersist(runId, projectId) {
|
|
86643
|
-
const currentRunRecord = this.db.select().from(runs).where(and60(
|
|
86763
|
+
const currentRunRecord = this.db.select().from(runs).where(and60(eq71(runs.id, runId), ...analyzableRunPredicates(projectId))).get();
|
|
86644
86764
|
if (!currentRunRecord) {
|
|
86645
86765
|
log.info("intelligence.skip", { runId, reason: "run not eligible for analysis" });
|
|
86646
86766
|
return null;
|
|
@@ -86649,7 +86769,7 @@ var IntelligenceService = class {
|
|
|
86649
86769
|
const recentRuns = this.db.select().from(runs).where(
|
|
86650
86770
|
and60(
|
|
86651
86771
|
...analyzableRunPredicates(projectId),
|
|
86652
|
-
currentLocation === null ? isNull13(runs.location) :
|
|
86772
|
+
currentLocation === null ? isNull13(runs.location) : eq71(runs.location, currentLocation),
|
|
86653
86773
|
// Never look forward. The window is this run's own past, so
|
|
86654
86774
|
// re-analyzing a historical run compares it against its true
|
|
86655
86775
|
// predecessor rather than against sweeps that came after it.
|
|
@@ -86657,7 +86777,7 @@ var IntelligenceService = class {
|
|
|
86657
86777
|
// MEASUREMENT: only runs that actually wrote snapshots — see above.
|
|
86658
86778
|
// Index seek on idx_snapshots_run, short-circuited on the first row.
|
|
86659
86779
|
exists(
|
|
86660
|
-
this.db.select({ one: sql28`1` }).from(querySnapshots).where(
|
|
86780
|
+
this.db.select({ one: sql28`1` }).from(querySnapshots).where(eq71(querySnapshots.runId, runs.id))
|
|
86661
86781
|
)
|
|
86662
86782
|
)
|
|
86663
86783
|
).orderBy(desc32(runs.finishedAt), desc32(runs.createdAt)).limit(HISTORY_WINDOW_RUNS).all();
|
|
@@ -86732,7 +86852,7 @@ var IntelligenceService = class {
|
|
|
86732
86852
|
* Returns the persisted insights so the coordinator can count critical/high.
|
|
86733
86853
|
*/
|
|
86734
86854
|
analyzeAndPersistGbp(runId, projectId) {
|
|
86735
|
-
const runRow = this.db.select({ createdAt: runs.createdAt, startedAt: runs.startedAt, finishedAt: runs.finishedAt }).from(runs).where(
|
|
86855
|
+
const runRow = this.db.select({ createdAt: runs.createdAt, startedAt: runs.startedAt, finishedAt: runs.finishedAt }).from(runs).where(eq71(runs.id, runId)).get();
|
|
86736
86856
|
if (!runRow) {
|
|
86737
86857
|
log.info("gbp-intelligence.skip", { runId, reason: "run not found" });
|
|
86738
86858
|
this.persistGbpInsights(runId, projectId, [], []);
|
|
@@ -86741,8 +86861,8 @@ var IntelligenceService = class {
|
|
|
86741
86861
|
const windowStart = runRow.startedAt ?? runRow.createdAt;
|
|
86742
86862
|
const windowEnd = runRow.finishedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
86743
86863
|
const selected = this.db.select().from(gbpLocations).where(and60(
|
|
86744
|
-
|
|
86745
|
-
|
|
86864
|
+
eq71(gbpLocations.projectId, projectId),
|
|
86865
|
+
eq71(gbpLocations.selected, true),
|
|
86746
86866
|
gte18(gbpLocations.syncedAt, windowStart),
|
|
86747
86867
|
lte15(gbpLocations.syncedAt, windowEnd)
|
|
86748
86868
|
)).all();
|
|
@@ -86777,12 +86897,12 @@ var IntelligenceService = class {
|
|
|
86777
86897
|
}
|
|
86778
86898
|
/** Build the per-location signal bundle the GBP analyzer consumes. */
|
|
86779
86899
|
buildGbpLocationSignals(projectId, locationName, displayName, fallbackDate) {
|
|
86780
|
-
const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(and60(
|
|
86781
|
-
const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(and60(
|
|
86782
|
-
const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and60(
|
|
86783
|
-
const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(and60(
|
|
86900
|
+
const metricRows = this.db.select({ metric: gbpDailyMetrics.metric, date: gbpDailyMetrics.date, value: gbpDailyMetrics.value }).from(gbpDailyMetrics).where(and60(eq71(gbpDailyMetrics.projectId, projectId), eq71(gbpDailyMetrics.locationName, locationName))).all();
|
|
86901
|
+
const placeActionRows = this.db.select({ placeActionType: gbpPlaceActions.placeActionType, providerType: gbpPlaceActions.providerType }).from(gbpPlaceActions).where(and60(eq71(gbpPlaceActions.projectId, projectId), eq71(gbpPlaceActions.locationName, locationName))).all();
|
|
86902
|
+
const lodgingRow = this.db.select({ populatedGroupCount: gbpLodgingSnapshots.populatedGroupCount }).from(gbpLodgingSnapshots).where(and60(eq71(gbpLodgingSnapshots.projectId, projectId), eq71(gbpLodgingSnapshots.locationName, locationName))).orderBy(desc32(gbpLodgingSnapshots.syncedAt)).limit(1).get();
|
|
86903
|
+
const ownerRow = this.db.select({ description: gbpLocations.description }).from(gbpLocations).where(and60(eq71(gbpLocations.projectId, projectId), eq71(gbpLocations.locationName, locationName))).get();
|
|
86784
86904
|
const descriptionMissing = !(ownerRow?.description ?? "").trim();
|
|
86785
|
-
const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and60(
|
|
86905
|
+
const placeRow = this.db.select({ attributes: gbpPlaceDetails.attributes }).from(gbpPlaceDetails).where(and60(eq71(gbpPlaceDetails.projectId, projectId), eq71(gbpPlaceDetails.locationName, locationName))).orderBy(desc32(gbpPlaceDetails.syncedAt)).limit(1).get();
|
|
86786
86906
|
const placesAmenities = placeRow ? extractPlaceAmenities(placeRow.attributes) : [];
|
|
86787
86907
|
const summary3 = buildGbpSummary({
|
|
86788
86908
|
locationName,
|
|
@@ -86818,7 +86938,7 @@ var IntelligenceService = class {
|
|
|
86818
86938
|
/** Build the month-over-month keyword series for a location from the
|
|
86819
86939
|
* accumulating gbp_keyword_monthly table (latest complete month vs prior). */
|
|
86820
86940
|
buildGbpKeywordTrend(projectId, locationName) {
|
|
86821
|
-
const rows = this.db.select({ month: gbpKeywordMonthly.month, keyword: gbpKeywordMonthly.keyword, valueCount: gbpKeywordMonthly.valueCount }).from(gbpKeywordMonthly).where(and60(
|
|
86941
|
+
const rows = this.db.select({ month: gbpKeywordMonthly.month, keyword: gbpKeywordMonthly.keyword, valueCount: gbpKeywordMonthly.valueCount }).from(gbpKeywordMonthly).where(and60(eq71(gbpKeywordMonthly.projectId, projectId), eq71(gbpKeywordMonthly.locationName, locationName))).all();
|
|
86822
86942
|
if (rows.length === 0) return { recentMonth: null, priorMonth: null, points: [] };
|
|
86823
86943
|
const months = [...new Set(rows.map((r) => r.month))].sort().reverse();
|
|
86824
86944
|
const recentMonth = months[0] ?? null;
|
|
@@ -86849,7 +86969,7 @@ var IntelligenceService = class {
|
|
|
86849
86969
|
*/
|
|
86850
86970
|
persistGbpInsights(runId, projectId, gbpInsights, coveredLocationNames) {
|
|
86851
86971
|
const covered = new Set(coveredLocationNames);
|
|
86852
|
-
const existing = this.db.select({ id: insights.id, dismissed: insights.dismissed }).from(insights).where(and60(
|
|
86972
|
+
const existing = this.db.select({ id: insights.id, dismissed: insights.dismissed }).from(insights).where(and60(eq71(insights.projectId, projectId), eq71(insights.provider, GBP_INSIGHT_PROVIDER))).all();
|
|
86853
86973
|
const staleIds = [];
|
|
86854
86974
|
const dismissedSlots = /* @__PURE__ */ new Set();
|
|
86855
86975
|
for (const row of existing) {
|
|
@@ -86860,7 +86980,7 @@ var IntelligenceService = class {
|
|
|
86860
86980
|
}
|
|
86861
86981
|
this.db.transaction((tx) => {
|
|
86862
86982
|
for (const id of staleIds) {
|
|
86863
|
-
tx.delete(insights).where(
|
|
86983
|
+
tx.delete(insights).where(eq71(insights.id, id)).run();
|
|
86864
86984
|
}
|
|
86865
86985
|
for (const insight of gbpInsights) {
|
|
86866
86986
|
const parsed = parseGbpInsightId(insight.id);
|
|
@@ -86946,7 +87066,7 @@ var IntelligenceService = class {
|
|
|
86946
87066
|
* create per run + aggregate). DB is left untouched.
|
|
86947
87067
|
*/
|
|
86948
87068
|
backfill(projectName, opts, onProgress) {
|
|
86949
|
-
const project = this.db.select().from(projects).where(
|
|
87069
|
+
const project = this.db.select().from(projects).where(eq71(projects.name, projectName)).get();
|
|
86950
87070
|
if (!project) {
|
|
86951
87071
|
throw new Error(`Project "${projectName}" not found`);
|
|
86952
87072
|
}
|
|
@@ -87035,7 +87155,7 @@ var IntelligenceService = class {
|
|
|
87035
87155
|
return { processed, skipped: skipped3, totalInsights };
|
|
87036
87156
|
}
|
|
87037
87157
|
loadTrackedCompetitors(projectId) {
|
|
87038
|
-
return this.db.select({ domain: competitors.domain }).from(competitors).where(
|
|
87158
|
+
return this.db.select({ domain: competitors.domain }).from(competitors).where(eq71(competitors.projectId, projectId)).all().map((r) => r.domain);
|
|
87039
87159
|
}
|
|
87040
87160
|
/**
|
|
87041
87161
|
* Which of `runIds` actually wrote query snapshots. One grouped read, so
|
|
@@ -87066,15 +87186,15 @@ var IntelligenceService = class {
|
|
|
87066
87186
|
}
|
|
87067
87187
|
persistResult(result, runId, projectId) {
|
|
87068
87188
|
const previouslyDismissed = /* @__PURE__ */ new Set();
|
|
87069
|
-
const existingInsights = this.db.select({ query: insights.query, provider: insights.provider, type: insights.type, dismissed: insights.dismissed }).from(insights).where(
|
|
87189
|
+
const existingInsights = this.db.select({ query: insights.query, provider: insights.provider, type: insights.type, dismissed: insights.dismissed }).from(insights).where(eq71(insights.runId, runId)).all();
|
|
87070
87190
|
for (const row of existingInsights) {
|
|
87071
87191
|
if (row.dismissed) {
|
|
87072
87192
|
previouslyDismissed.add(`${row.query}:${row.provider}:${row.type}`);
|
|
87073
87193
|
}
|
|
87074
87194
|
}
|
|
87075
87195
|
this.db.transaction((tx) => {
|
|
87076
|
-
tx.delete(insights).where(
|
|
87077
|
-
tx.delete(healthSnapshots).where(
|
|
87196
|
+
tx.delete(insights).where(eq71(insights.runId, runId)).run();
|
|
87197
|
+
tx.delete(healthSnapshots).where(eq71(healthSnapshots.runId, runId)).run();
|
|
87078
87198
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
87079
87199
|
for (const insight of result.insights) {
|
|
87080
87200
|
const wasDismissed = previouslyDismissed.has(`${insight.query}:${insight.provider}:${insight.type}`);
|
|
@@ -87122,7 +87242,7 @@ var IntelligenceService = class {
|
|
|
87122
87242
|
impressions: gscSearchData.impressions,
|
|
87123
87243
|
position: gscSearchData.position
|
|
87124
87244
|
}).from(gscSearchData).where(and60(
|
|
87125
|
-
|
|
87245
|
+
eq71(gscSearchData.projectId, projectId),
|
|
87126
87246
|
gte18(gscSearchData.date, window.startDate),
|
|
87127
87247
|
lte15(gscSearchData.date, window.endDate)
|
|
87128
87248
|
)).all();
|
|
@@ -87175,7 +87295,7 @@ var IntelligenceService = class {
|
|
|
87175
87295
|
const key = row.query.toLowerCase();
|
|
87176
87296
|
gscImpressionsByQuery.set(key, (gscImpressionsByQuery.get(key) ?? 0) + row.impressions);
|
|
87177
87297
|
}
|
|
87178
|
-
const projectRow = this.db.select({ locations: projects.locations }).from(projects).where(
|
|
87298
|
+
const projectRow = this.db.select({ locations: projects.locations }).from(projects).where(eq71(projects.id, projectId)).get();
|
|
87179
87299
|
const locationCount = Math.max(
|
|
87180
87300
|
1,
|
|
87181
87301
|
(projectRow?.locations ?? []).length
|
|
@@ -87183,9 +87303,9 @@ var IntelligenceService = class {
|
|
|
87183
87303
|
const ROWS_PER_GROUP_BUDGET = Math.max(2, locationCount);
|
|
87184
87304
|
const recentRunRows = this.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
|
|
87185
87305
|
and60(
|
|
87186
|
-
|
|
87187
|
-
|
|
87188
|
-
or18(
|
|
87306
|
+
eq71(runs.projectId, projectId),
|
|
87307
|
+
eq71(runs.kind, RunKinds["answer-visibility"]),
|
|
87308
|
+
or18(eq71(runs.status, "completed"), eq71(runs.status, "partial")),
|
|
87189
87309
|
// Defensive — see top of file.
|
|
87190
87310
|
ne11(runs.trigger, RunTriggers.probe)
|
|
87191
87311
|
)
|
|
@@ -87205,7 +87325,7 @@ var IntelligenceService = class {
|
|
|
87205
87325
|
const haveHistory = recentRunIds.length > 0;
|
|
87206
87326
|
const priorRegressionsByPair = /* @__PURE__ */ new Map();
|
|
87207
87327
|
if (haveHistory) {
|
|
87208
|
-
const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and60(
|
|
87328
|
+
const priorRows = this.db.select({ query: insights.query, provider: insights.provider, runId: insights.runId }).from(insights).where(and60(eq71(insights.type, "regression"), inArray27(insights.runId, recentRunIds))).all();
|
|
87209
87329
|
const regressionGroups = /* @__PURE__ */ new Map();
|
|
87210
87330
|
for (const row of priorRows) {
|
|
87211
87331
|
if (!row.runId) continue;
|
|
@@ -87234,7 +87354,7 @@ var IntelligenceService = class {
|
|
|
87234
87354
|
});
|
|
87235
87355
|
}
|
|
87236
87356
|
buildRunData(runId, projectId, completedAt, location = null, trackedCompetitors = []) {
|
|
87237
|
-
const projectDomainRow = this.db.select({ canonicalDomain: projects.canonicalDomain, ownedDomains: projects.ownedDomains }).from(projects).where(
|
|
87357
|
+
const projectDomainRow = this.db.select({ canonicalDomain: projects.canonicalDomain, ownedDomains: projects.ownedDomains }).from(projects).where(eq71(projects.id, projectId)).get();
|
|
87238
87358
|
const projectDomains = projectDomainRow ? effectiveDomains({
|
|
87239
87359
|
canonicalDomain: projectDomainRow.canonicalDomain,
|
|
87240
87360
|
ownedDomains: projectDomainRow.ownedDomains
|
|
@@ -87252,7 +87372,7 @@ var IntelligenceService = class {
|
|
|
87252
87372
|
citedDomains: querySnapshots.citedDomains,
|
|
87253
87373
|
rawResponse: querySnapshots.rawResponse,
|
|
87254
87374
|
snapshotLocation: querySnapshots.location
|
|
87255
|
-
}).from(querySnapshots).leftJoin(queries,
|
|
87375
|
+
}).from(querySnapshots).leftJoin(queries, eq71(querySnapshots.queryId, queries.id)).where(eq71(querySnapshots.runId, runId)).all();
|
|
87256
87376
|
const snapshots = [];
|
|
87257
87377
|
let orphanCount = 0;
|
|
87258
87378
|
for (const r of rows) {
|
|
@@ -87473,6 +87593,7 @@ export {
|
|
|
87473
87593
|
runChecks,
|
|
87474
87594
|
executeDiscovery,
|
|
87475
87595
|
markSessionFailed,
|
|
87596
|
+
createRunCompetitorResolver,
|
|
87476
87597
|
captureSimpleMeasurementDefinition,
|
|
87477
87598
|
apiRoutes,
|
|
87478
87599
|
addLogListener,
|
|
@@ -5,12 +5,12 @@ import {
|
|
|
5
5
|
siteCrawlGraphNodes,
|
|
6
6
|
siteCrawlPages,
|
|
7
7
|
siteCrawlSnapshots
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-3YAPVVFN.js";
|
|
9
9
|
import {
|
|
10
10
|
SITE_CRAWL_GRAPH_MAX_EDGES,
|
|
11
11
|
SITE_CRAWL_GRAPH_MAX_NODES,
|
|
12
12
|
TEMPLATE_LINK_RATIO_THRESHOLD
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-L36TC6LB.js";
|
|
14
14
|
|
|
15
15
|
// src/site-crawl-graph-layout.ts
|
|
16
16
|
import crypto from "crypto";
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
installSkills,
|
|
5
5
|
loadConfigRaw,
|
|
6
6
|
saveConfigPatch
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ZGZSROSR.js";
|
|
8
8
|
import {
|
|
9
9
|
PACKAGE_VERSION
|
|
10
10
|
} from "./chunk-AOJU5LKX.js";
|
|
11
11
|
import {
|
|
12
12
|
SKILL_MANIFEST_FILENAME,
|
|
13
13
|
SkillsClients
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-L36TC6LB.js";
|
|
15
15
|
|
|
16
16
|
// src/skills-autosync.ts
|
|
17
17
|
import fs from "fs";
|