@canonry/canonry 7.63.1 → 7.64.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/agent-workspace/skills/aero/references/ai-traffic-tracking.md +13 -9
- package/assets/agent-workspace/skills/canonry/references/ai-traffic-tracking.md +13 -9
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +24 -3
- package/assets/assets/{AgentSetupPage-D6lCJ1G1.js → AgentSetupPage-C9VnIbMS.js} +1 -1
- package/assets/assets/{AuditHistoryPanel-DlgI3o-U.js → AuditHistoryPanel-DLa6Ca5t.js} +1 -1
- package/assets/assets/{BacklinksPage-ByiMqbSI.js → BacklinksPage-Dxnz-sUy.js} +1 -1
- package/assets/assets/{HistoryPage-DclVeuLO.js → HistoryPage-PU7UNO3T.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-DDHybtHa.js → MeasurementPropertyPage-Bo4xKbWQ.js} +1 -1
- package/assets/assets/{ProjectPage-vBu6oWFi.js → ProjectPage-DuW9zWT9.js} +1 -1
- package/assets/assets/{RunsPage-CYBJ6pXX.js → RunsPage-Cr0QSE4Q.js} +1 -1
- package/assets/assets/{SettingsPage-w0GmXir0.js → SettingsPage-K6tGAVHo.js} +1 -1
- package/assets/assets/{SiteHealthSection-DDTjGZ05.js → SiteHealthSection-DxhIqNDZ.js} +2 -2
- package/assets/assets/ToneBadge-Cvv6Tkk7.js +60 -0
- package/assets/assets/{TrafficPage-hUWYv-HT.js → TrafficPage-lNcR4TvT.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-CGHgPxs8.js → TrafficSourceDetailPage-D47VIFDK.js} +1 -1
- package/assets/assets/{account-context-qX-Es0RK.js → account-context-BL8j43iU.js} +1 -1
- package/assets/assets/{card-CzROANT5.js → card-BKud0olB.js} +1 -1
- package/assets/assets/{extract-error-message-BY1STLiX.js → extract-error-message-CvEgflI1.js} +1 -1
- package/assets/assets/{format-helpers-BNQR1HNK.js → format-helpers-Ce3RoH9T.js} +1 -1
- package/assets/assets/{index-LmB57HOs.js → index-C2t4yW4t.js} +4 -4
- package/assets/assets/{query-client-Gz37p16p.js → query-client-Bf5Rr6po.js} +1 -1
- package/assets/assets/{react-query-C6DtBAYQ.js → react-query-CsFtWT8r.js} +1 -1
- package/assets/assets/{react-sigma_core.esm.min-CgxuyPPF.js → react-sigma_core.esm.min-D-dyJflK.js} +1 -1
- package/assets/assets/{service-DyHZWnMe.js → service-C0U5Ude4.js} +1 -1
- package/assets/index.html +7 -7
- package/dist/{ads-FOUJNHP4.js → ads-EFXCND5Z.js} +3 -3
- package/dist/{agent-UVDVH7LK.js → agent-2MAONYLR.js} +7 -7
- package/dist/{agent-ask-UEYN2SQX.js → agent-ask-5555LQQL.js} +3 -3
- package/dist/{agent-conversations-F54376Q2.js → agent-conversations-LYWOS4X3.js} +3 -3
- package/dist/{agent-memory-SOHBTJ4U.js → agent-memory-HOYIIO66.js} +3 -3
- package/dist/{agent-providers-MMEK2H6V.js → agent-providers-EYXB2DMX.js} +3 -3
- package/dist/{agent-transcript-5IJ3VAEV.js → agent-transcript-BWDOJXPV.js} +3 -3
- package/dist/{analytics-LDWO5IW6.js → analytics-46VKY4SP.js} +3 -3
- package/dist/{apply-PSGFDJIC.js → apply-GII5J3QB.js} +3 -3
- package/dist/{backfill-2BVFKQ6J.js → backfill-WSIEPRES.js} +9 -9
- package/dist/{backlinks-X6DXIL2O.js → backlinks-GRHTLP5Z.js} +3 -3
- package/dist/{bing-3HMFUEOO.js → bing-5QDDHK57.js} +3 -3
- package/dist/{bootstrap-ZUSSLXCI.js → bootstrap-GWDFCGEQ.js} +10 -10
- package/dist/{cdp-FH627HJ6.js → cdp-YMIJN52Z.js} +7 -7
- package/dist/{chunk-SN5A767O.js → chunk-2BJDLTDI.js} +1 -1
- package/dist/{chunk-TKLE2Y6H.js → chunk-4PRXS5JH.js} +103 -4
- package/dist/{chunk-2LAL5W6J.js → chunk-6AYOWQJ3.js} +3 -3
- package/dist/{chunk-6ABOEN5D.js → chunk-6ZA23GRE.js} +8 -8
- package/dist/{chunk-PH7RTAWW.js → chunk-7LVZATRE.js} +1 -1
- package/dist/{chunk-V3QMOGZE.js → chunk-7STLCYWL.js} +5 -5
- package/dist/{chunk-AGSQWIE4.js → chunk-7U2SFOJN.js} +20 -20
- package/dist/{chunk-L2QPAUTQ.js → chunk-7V6DJCZO.js} +1 -1
- package/dist/{chunk-LBD7YXVD.js → chunk-AUIHVRJ3.js} +2 -2
- package/dist/{chunk-ZJTU73GW.js → chunk-BAQOH3LE.js} +3 -3
- package/dist/{chunk-QNFX7ZCT.js → chunk-BUED4RWE.js} +1 -1
- package/dist/{chunk-NOQCIXM6.js → chunk-CLMJSIZU.js} +1 -1
- package/dist/{chunk-UBP3AAKA.js → chunk-CNPYR2CQ.js} +1 -1
- package/dist/{chunk-SQYYAYH6.js → chunk-DKVY6HFW.js} +3 -3
- package/dist/{chunk-LEG7F3DN.js → chunk-DYDLK3YY.js} +2 -2
- package/dist/{chunk-CWMJQ2JV.js → chunk-I62VYS4B.js} +4 -4
- package/dist/{chunk-GRWZC3GQ.js → chunk-ITYUIHKO.js} +1 -1
- package/dist/{chunk-5VAC4KQ2.js → chunk-JP4Q5FEW.js} +3 -3
- package/dist/{chunk-32KNDPD3.js → chunk-K5S5HXAK.js} +348 -336
- package/dist/{chunk-UYPBR3SF.js → chunk-L6IQN2Y5.js} +2 -2
- package/dist/{chunk-ERJ54U2I.js → chunk-M6QGMJAQ.js} +1 -1
- package/dist/{chunk-OIHJJHJR.js → chunk-MXQB7AAP.js} +1 -1
- package/dist/{chunk-5GMYD7UZ.js → chunk-NFZXB5ZV.js} +5 -5
- package/dist/{chunk-22ABGRB7.js → chunk-TX4HBLFP.js} +206 -115
- package/dist/{chunk-SG2OPR7J.js → chunk-UQABYWAX.js} +1 -1
- package/dist/{chunk-67262NJL.js → chunk-V23ALG2D.js} +2 -2
- package/dist/{chunk-H22RCHYH.js → chunk-VLOWXBJS.js} +3 -3
- package/dist/{chunk-IDQZTPRG.js → chunk-WFOIIHAK.js} +2 -2
- package/dist/{chunk-IRRONWF7.js → chunk-WLCYVJGN.js} +4 -4
- package/dist/{chunk-EHTSCLEL.js → chunk-XR3R5PDK.js} +1 -1
- package/dist/{chunk-A57HYHJ3.js → chunk-Y3VMSYEG.js} +1 -1
- package/dist/{chunk-5YC6IU44.js → chunk-ZGLLSPBB.js} +2 -2
- package/dist/{chunk-JM6OFCLX.js → chunk-ZUH7GDQ4.js} +4 -4
- package/dist/{chunk-HNZQVIPS.js → chunk-ZYE7D2OC.js} +23 -1
- package/dist/{citations-BKWLP5S3.js → citations-AMOXXK5R.js} +3 -3
- package/dist/{cli-catalog-VRJS66GR.js → cli-catalog-K5EQZBOO.js} +3 -3
- package/dist/{cli-commands-ONFE63OB.js → cli-commands-CCGP2A2P.js} +7 -7
- package/dist/cli.js +13 -13
- package/dist/{competitor-VELMM2TJ.js → competitor-YQBDZE6A.js} +3 -3
- package/dist/{content-I525MITL.js → content-DFZ56U3J.js} +3 -3
- package/dist/{dashboard-BC4NKAO2.js → dashboard-LIPZS22H.js} +6 -6
- package/dist/{demo-ZRFZ5EBH.js → demo-XZJKCQRO.js} +1 -1
- package/dist/{demo-server-7R7NGWJA.js → demo-server-3BCUBH4H.js} +11 -11
- package/dist/{discover-E2CV5ZP7.js → discover-JDJ2O6D6.js} +3 -3
- package/dist/{discover-eval-ESRCWRHP.js → discover-eval-5GST6BOJ.js} +3 -3
- package/dist/{doctor-BQDVERII.js → doctor-2LJGHCIZ.js} +3 -3
- package/dist/{evidence-NUULK5XD.js → evidence-FQKL6ULX.js} +3 -3
- package/dist/{export-cmd-K324RTN4.js → export-cmd-KNGYT4JH.js} +3 -3
- package/dist/{ga-PQ36UFTK.js → ga-UH4RUHX2.js} +25 -3
- package/dist/{gbp-KTYA6KHR.js → gbp-IPMROSVV.js} +3 -3
- package/dist/{google-3D4E7TJX.js → google-QU5M737H.js} +4 -4
- package/dist/{google-marketing-4FRO4PRN.js → google-marketing-QCLVAP25.js} +1 -1
- package/dist/{health-cmd-CZJOZUAQ.js → health-cmd-7UFZ5MT6.js} +3 -3
- package/dist/{history-JNH34GAM.js → history-3H3CKHVR.js} +3 -3
- package/dist/index.d.ts +64 -5
- package/dist/index.js +24 -24
- package/dist/{init-TU4VSGVU.js → init-HNPTJIOS.js} +11 -11
- package/dist/{insights-STYJSZBB.js → insights-LEVVXDBW.js} +3 -3
- package/dist/intelligence-service-GQQNTMUX.js +15 -0
- package/dist/{journeys-POTSSBOM.js → journeys-JMQBUF2E.js} +3 -3
- package/dist/{keys-BPCSPX2O.js → keys-LF2UMTN6.js} +3 -3
- package/dist/{keyword-6SML434W.js → keyword-JSJYNWN2.js} +3 -3
- package/dist/{logs-WTKKH4UJ.js → logs-RWUB42V3.js} +3 -3
- package/dist/{mcp-HTAHMVRC.js → mcp-FWQXTWAR.js} +2 -2
- package/dist/mcp.js +9 -9
- package/dist/{measurement-plan-LJHKKRZ7.js → measurement-plan-4WXYE6CZ.js} +5 -5
- package/dist/{notify-EARS4LMG.js → notify-FBS43GY5.js} +3 -3
- package/dist/{organic-evidence-W7ZQQKPL.js → organic-evidence-TTXXAHFX.js} +3 -3
- package/dist/{overview-C7KQD4NR.js → overview-AB5JTMWR.js} +4 -4
- package/dist/{project-YU2FIL4B.js → project-GSQMF736.js} +7 -4
- package/dist/{query-SYFLWHFA.js → query-JITDUO3B.js} +3 -3
- package/dist/{research-UOUXMFBV.js → research-UU5W2XPU.js} +3 -3
- package/dist/{results-export-VYPG2Z6S.js → results-export-ZX62A645.js} +3 -3
- package/dist/{run-GZD3MQGS.js → run-HXNS5CB3.js} +4 -4
- package/dist/{schedule-PAA2NLGF.js → schedule-Q4XMBZAH.js} +3 -3
- package/dist/{search-6RWCUEEY.js → search-GC4RYLYD.js} +3 -3
- package/dist/{serve-VIEGFGSK.js → serve-ECMM256O.js} +25 -25
- package/dist/{session-JLH72BF5.js → session-JI4YODZS.js} +12 -12
- package/dist/{settings-TTA775EJ.js → settings-5GFLK4DY.js} +3 -3
- package/dist/{skills-GA35KKOV.js → skills-B7Z5S3IT.js} +2 -2
- package/dist/{snapshot-QVQVAMMN.js → snapshot-2JOQFYJE.js} +3 -3
- package/dist/{src-CTHVFVLF.js → src-2UNG3E4M.js} +2 -2
- package/dist/{status-E7B726S6.js → status-NKK5MYNE.js} +4 -4
- package/dist/{technical-aeo-SMPN3QDQ.js → technical-aeo-MQLGHVIX.js} +3 -3
- package/dist/{telemetry-CTBFPMWD.js → telemetry-J5F2H7OJ.js} +4 -4
- package/dist/{tools-YOV2KHF2.js → tools-CXANMI23.js} +11 -11
- package/dist/{traffic-XACOSYYM.js → traffic-BVKW6QDD.js} +5 -5
- package/dist/{users-WJC7SGRL.js → users-2EKLHWPH.js} +3 -3
- package/dist/{visibility-stats-H3ZNFV5M.js → visibility-stats-HVQ6VUEB.js} +3 -3
- package/dist/{wordpress-72YMWF7F.js → wordpress-EEYBM634.js} +3 -3
- package/package.json +1 -1
- package/assets/assets/ToneBadge-MKA1xeYc.js +0 -60
- package/dist/intelligence-service-MWTHUE7S.js +0 -15
|
@@ -9,14 +9,14 @@ import {
|
|
|
9
9
|
normalizeCloudflareWorkerEvent,
|
|
10
10
|
sessionizeJourneyRequests,
|
|
11
11
|
verifyRequestSignature
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-UQABYWAX.js";
|
|
13
13
|
import {
|
|
14
14
|
currentOutcomeAttribution,
|
|
15
15
|
getRequestContext,
|
|
16
16
|
registerRequestContext,
|
|
17
17
|
requestAuditIdentity,
|
|
18
18
|
sanitizeRequestContext
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-BUED4RWE.js";
|
|
20
20
|
import {
|
|
21
21
|
SentimentIdempotencyConflict,
|
|
22
22
|
SentimentRepository,
|
|
@@ -154,7 +154,7 @@ import {
|
|
|
154
154
|
userSessions,
|
|
155
155
|
users,
|
|
156
156
|
writeNegativeReviewMaxStars
|
|
157
|
-
} from "./chunk-
|
|
157
|
+
} from "./chunk-ZYE7D2OC.js";
|
|
158
158
|
import {
|
|
159
159
|
ADS_ACTIVATE_SCOPE,
|
|
160
160
|
ADS_ACTIVATION_ABSOLUTE_MAX_ENTITIES,
|
|
@@ -565,7 +565,9 @@ import {
|
|
|
565
565
|
conversionTrackingOptionsDtoSchema,
|
|
566
566
|
cosineSimilarity,
|
|
567
567
|
countAdsActivationManifestEntities,
|
|
568
|
+
countedLeadEventNames,
|
|
568
569
|
countsAsMention,
|
|
570
|
+
countsKeyEvents,
|
|
569
571
|
createApiKeyRequestSchema,
|
|
570
572
|
createAutoAliasAccumulator,
|
|
571
573
|
createSentimentEvaluationDefinition,
|
|
@@ -720,6 +722,7 @@ import {
|
|
|
720
722
|
hostMatchesAnyDomain,
|
|
721
723
|
hostMatchesDomain,
|
|
722
724
|
hostOf,
|
|
725
|
+
ignoredKeyEventNames,
|
|
723
726
|
inclusiveDayCount,
|
|
724
727
|
indexingRequestResponseDtoSchema,
|
|
725
728
|
insightActionGroupByType,
|
|
@@ -1163,7 +1166,7 @@ import {
|
|
|
1163
1166
|
wordpressSchemaDeployResultDtoSchema,
|
|
1164
1167
|
wordpressSchemaStatusResultDtoSchema,
|
|
1165
1168
|
wordpressStatusDtoSchema
|
|
1166
|
-
} from "./chunk-
|
|
1169
|
+
} from "./chunk-4PRXS5JH.js";
|
|
1167
1170
|
|
|
1168
1171
|
// ../api-routes/src/user-session.ts
|
|
1169
1172
|
import crypto2 from "crypto";
|
|
@@ -11732,7 +11735,9 @@ async function projectRoutes(app, opts) {
|
|
|
11732
11735
|
measurement: {
|
|
11733
11736
|
marketingHosts: patch.measurement.marketingHosts ?? existing.measurement.marketingHosts,
|
|
11734
11737
|
brandTerms: patch.measurement.brandTerms ?? existing.measurement.brandTerms,
|
|
11735
|
-
leadEventNames: patch.measurement.leadEventNames ?? existing.measurement.leadEventNames
|
|
11738
|
+
leadEventNames: patch.measurement.leadEventNames ?? existing.measurement.leadEventNames,
|
|
11739
|
+
// Omitted stays omitted, which means on.
|
|
11740
|
+
...(patch.measurement.countKeyEvents ?? existing.measurement.countKeyEvents) !== void 0 ? { countKeyEvents: patch.measurement.countKeyEvents ?? existing.measurement.countKeyEvents } : {}
|
|
11736
11741
|
}
|
|
11737
11742
|
} : {},
|
|
11738
11743
|
...patch.autoExtractBacklinks !== void 0 ? { autoExtractBacklinks: patch.autoExtractBacklinks } : {},
|
|
@@ -26627,6 +26632,7 @@ function readProjectConfigState(db, name, options = {}) {
|
|
|
26627
26632
|
"measurement.marketingHosts": project.measurement.marketingHosts,
|
|
26628
26633
|
"measurement.brandTerms": project.measurement.brandTerms,
|
|
26629
26634
|
"measurement.leadEventNames": project.measurement.leadEventNames,
|
|
26635
|
+
"measurement.countKeyEvents": countsKeyEvents(project.measurement),
|
|
26630
26636
|
locations: project.locations,
|
|
26631
26637
|
defaultLocation: project.defaultLocation,
|
|
26632
26638
|
autoExtractBacklinks: project.autoExtractBacklinks,
|
|
@@ -29830,7 +29836,7 @@ function literalPathPrefixCondition(path8, prefix) {
|
|
|
29830
29836
|
}
|
|
29831
29837
|
|
|
29832
29838
|
// ../api-routes/src/ga-measurement-analysis.ts
|
|
29833
|
-
import { and as and44, eq as eq52, gte as gte12, lte as lte11, or as or11, sql as sql18 } from "drizzle-orm";
|
|
29839
|
+
import { and as and44, eq as eq52, gte as gte12, inArray as inArray28, lte as lte11, or as or11, sql as sql18 } from "drizzle-orm";
|
|
29834
29840
|
var UNKNOWN_LANDING_PAGE = "(not set)";
|
|
29835
29841
|
function addDays(date, offset) {
|
|
29836
29842
|
const value = /* @__PURE__ */ new Date(`${date}T00:00:00.000Z`);
|
|
@@ -30131,8 +30137,16 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
30131
30137
|
};
|
|
30132
30138
|
const acquisitionScope = scopedConditions(gaAcquisitionDaily.hostName, gaAcquisitionDaily.landingPageNormalized, gaAcquisitionDaily.landingPage);
|
|
30133
30139
|
const leadLandingScope = scopedConditions(gaLeadEventsDaily.hostName, gaLeadEventsDaily.landingPageNormalized, gaLeadEventsDaily.landingPage);
|
|
30140
|
+
const state = db.select().from(gaMeasurementSyncStates).where(eq52(gaMeasurementSyncStates.projectId, project.id)).get();
|
|
30141
|
+
const configuredLeadEvents = [...project.measurement.leadEventNames];
|
|
30142
|
+
const keyEventsEnabled = countsKeyEvents(project.measurement);
|
|
30143
|
+
const keyEventNames = keyEventsEnabled ? state?.keyEventNames ?? null : null;
|
|
30144
|
+
const countedEventNames = countedLeadEventNames(configuredLeadEvents, keyEventNames ?? []);
|
|
30145
|
+
const measuredEventSet = new Set(state?.leadEventNames ?? configuredLeadEvents);
|
|
30146
|
+
const reportedEventNames = countedEventNames.filter((name) => measuredEventSet.has(name));
|
|
30147
|
+
const leadEventCondition = reportedEventNames.length > 0 ? inArray28(gaLeadEventsDaily.eventName, reportedEventNames) : null;
|
|
30134
30148
|
const acquisitionAnchor = db.select({ date: sql18`max(${gaAcquisitionDaily.date})` }).from(gaAcquisitionDaily).where(and44(eq52(gaAcquisitionDaily.projectId, project.id), ...acquisitionScope)).get()?.date ?? null;
|
|
30135
|
-
const leadAnchor = db.select({ date: sql18`max(${gaLeadEventsDaily.date})` }).from(gaLeadEventsDaily).where(and44(eq52(gaLeadEventsDaily.projectId, project.id), or11(
|
|
30149
|
+
const leadAnchor = leadEventCondition === null ? null : db.select({ date: sql18`max(${gaLeadEventsDaily.date})` }).from(gaLeadEventsDaily).where(and44(eq52(gaLeadEventsDaily.projectId, project.id), leadEventCondition, or11(
|
|
30136
30150
|
eq52(gaLeadEventsDaily.attributionScope, "channel"),
|
|
30137
30151
|
and44(eq52(gaLeadEventsDaily.attributionScope, "landing-page"), ...leadLandingScope)
|
|
30138
30152
|
))).get()?.date ?? null;
|
|
@@ -30140,7 +30154,7 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
30140
30154
|
const gaPeriods = gaAnchor ? buildPeriods(gaAnchor, days) : [];
|
|
30141
30155
|
const gaStartDate = gaPeriods[0]?.startDate;
|
|
30142
30156
|
const acquisitionRows = gaStartDate ? db.select().from(gaAcquisitionDaily).where(and44(eq52(gaAcquisitionDaily.projectId, project.id), gte12(gaAcquisitionDaily.date, gaStartDate), lte11(gaAcquisitionDaily.date, gaAnchor))).all() : [];
|
|
30143
|
-
const leadRows = gaStartDate ? db.select().from(gaLeadEventsDaily).where(and44(eq52(gaLeadEventsDaily.projectId, project.id), gte12(gaLeadEventsDaily.date, gaStartDate), lte11(gaLeadEventsDaily.date, gaAnchor))).all() : [];
|
|
30157
|
+
const leadRows = gaStartDate && leadEventCondition !== null ? db.select().from(gaLeadEventsDaily).where(and44(eq52(gaLeadEventsDaily.projectId, project.id), leadEventCondition, gte12(gaLeadEventsDaily.date, gaStartDate), lte11(gaLeadEventsDaily.date, gaAnchor))).all() : [];
|
|
30144
30158
|
const engagementAnchor = db.select({ date: sql18`max(${gaDailyTotals.date})` }).from(gaDailyTotals).where(eq52(gaDailyTotals.projectId, project.id)).get()?.date ?? null;
|
|
30145
30159
|
const engagementPeriodWindow = engagementAnchor ? buildPeriods(engagementAnchor, days) : [];
|
|
30146
30160
|
const engagementStartDate = engagementPeriodWindow[0]?.startDate;
|
|
@@ -30164,7 +30178,6 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
30164
30178
|
const propertyRows = gscStartDate ? db.select().from(gscDailyTotals).where(and44(eq52(gscDailyTotals.projectId, project.id), gte12(gscDailyTotals.date, gscStartDate), lte11(gscDailyTotals.date, gscAnchor))).all() : [];
|
|
30165
30179
|
const queryRows2 = gscStartDate ? db.select().from(gscQueryDailyTotals).where(and44(eq52(gscQueryDailyTotals.projectId, project.id), gte12(gscQueryDailyTotals.date, gscStartDate), lte11(gscQueryDailyTotals.date, gscAnchor))).all() : [];
|
|
30166
30180
|
const rawPageRows = gscStartDate ? db.select().from(gscSearchData).where(and44(eq52(gscSearchData.projectId, project.id), gte12(gscSearchData.date, gscStartDate), lte11(gscSearchData.date, gscAnchor))).all() : [];
|
|
30167
|
-
const state = db.select().from(gaMeasurementSyncStates).where(eq52(gaMeasurementSyncStates.projectId, project.id)).get();
|
|
30168
30181
|
const acquisition = acquisitionRows.filter((row) => {
|
|
30169
30182
|
const landingPage = normalizeLandingPage(row.landingPageNormalized ?? row.landingPage);
|
|
30170
30183
|
return hostIsIncluded(row.hostName) && pageIsIncluded(landingPage);
|
|
@@ -30211,6 +30224,19 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
30211
30224
|
(row) => row.channelGroup,
|
|
30212
30225
|
(row) => row.eventCount
|
|
30213
30226
|
);
|
|
30227
|
+
const leadEvents = aggregateByKey(
|
|
30228
|
+
leads,
|
|
30229
|
+
gaPeriods,
|
|
30230
|
+
(row) => row.eventName,
|
|
30231
|
+
(row) => row.eventCount
|
|
30232
|
+
);
|
|
30233
|
+
for (const eventName of reportedEventNames) {
|
|
30234
|
+
if (!leadEvents.has(eventName)) leadEvents.set(eventName, gaPeriods.map(() => 0));
|
|
30235
|
+
}
|
|
30236
|
+
const unmeasuredEventNames = countedEventNames.filter((name) => !measuredEventSet.has(name));
|
|
30237
|
+
const configuredEventSet = new Set(configuredLeadEvents);
|
|
30238
|
+
const keyEventSet = new Set(keyEventNames ?? []);
|
|
30239
|
+
const eventOrigin = (eventName) => configuredEventSet.has(eventName) && keyEventSet.has(eventName) ? "both" : keyEventSet.has(eventName) ? "key-event" : "configured";
|
|
30214
30240
|
const filtersNarrowSessions = parsedHostScope.data === "marketing" || pathPrefix !== null && pathPrefix !== "/";
|
|
30215
30241
|
const hasAiEngineLeadData = gaAnchor !== null && hasLeadTimeline;
|
|
30216
30242
|
const aiEngineRows = attributeAiEngineRows({
|
|
@@ -30338,7 +30364,28 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
30338
30364
|
channelGroup,
|
|
30339
30365
|
periods: eventPeriods(gaPeriods, values)
|
|
30340
30366
|
})),
|
|
30341
|
-
aiEngines: aiEngineLeads
|
|
30367
|
+
aiEngines: aiEngineLeads,
|
|
30368
|
+
countedEvents: {
|
|
30369
|
+
configured: configuredLeadEvents,
|
|
30370
|
+
keyEventsEnabled,
|
|
30371
|
+
keyEvents: keyEventNames,
|
|
30372
|
+
keyEventsError: keyEventsEnabled ? state?.keyEventsError ?? null : null,
|
|
30373
|
+
ignoredKeyEvents: ignoredKeyEventNames(configuredLeadEvents, keyEventNames ?? [])
|
|
30374
|
+
},
|
|
30375
|
+
events: [
|
|
30376
|
+
...gaAnchor && hasLeadTimeline ? rankEntries(leadEvents).map(([eventName, values]) => ({
|
|
30377
|
+
eventName,
|
|
30378
|
+
origin: eventOrigin(eventName),
|
|
30379
|
+
measured: true,
|
|
30380
|
+
periods: eventPeriods(gaPeriods, values)
|
|
30381
|
+
})) : [],
|
|
30382
|
+
...unmeasuredEventNames.map((eventName) => ({
|
|
30383
|
+
eventName,
|
|
30384
|
+
origin: eventOrigin(eventName),
|
|
30385
|
+
measured: false,
|
|
30386
|
+
periods: []
|
|
30387
|
+
}))
|
|
30388
|
+
]
|
|
30342
30389
|
},
|
|
30343
30390
|
engagement: {
|
|
30344
30391
|
status: engagementAnchor === null ? "unavailable" : "ready",
|
|
@@ -30921,7 +30968,7 @@ async function organicEvidenceRoutes(app) {
|
|
|
30921
30968
|
}
|
|
30922
30969
|
|
|
30923
30970
|
// ../api-routes/src/citations.ts
|
|
30924
|
-
import { and as and46, eq as eq54, inArray as
|
|
30971
|
+
import { and as and46, eq as eq54, inArray as inArray29 } from "drizzle-orm";
|
|
30925
30972
|
async function citationRoutes(app) {
|
|
30926
30973
|
app.get("/projects/:name/citations/visibility", async (request, reply) => {
|
|
30927
30974
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -30945,7 +30992,7 @@ async function citationRoutes(app) {
|
|
|
30945
30992
|
competitorOverlap: querySnapshots.competitorOverlap,
|
|
30946
30993
|
answerMentioned: querySnapshots.answerMentioned,
|
|
30947
30994
|
createdAt: querySnapshots.createdAt
|
|
30948
|
-
}).from(querySnapshots).where(
|
|
30995
|
+
}).from(querySnapshots).where(inArray29(querySnapshots.runId, projectRuns.map((r) => r.id))).all();
|
|
30949
30996
|
if (rawSnapshots.length === 0) {
|
|
30950
30997
|
return reply.send(emptyCitationVisibility("no-runs-yet"));
|
|
30951
30998
|
}
|
|
@@ -31082,7 +31129,7 @@ function computeCitationVisibility(input) {
|
|
|
31082
31129
|
}
|
|
31083
31130
|
|
|
31084
31131
|
// ../api-routes/src/visibility-stats.ts
|
|
31085
|
-
import { and as and47, desc as desc26, eq as eq55, inArray as
|
|
31132
|
+
import { and as and47, desc as desc26, eq as eq55, inArray as inArray30 } from "drizzle-orm";
|
|
31086
31133
|
|
|
31087
31134
|
// ../api-routes/src/visibility-compare.ts
|
|
31088
31135
|
var VISIBILITY_COMPARE_MIN_RUNS = 5;
|
|
@@ -31569,7 +31616,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
31569
31616
|
citationState: querySnapshots.citationState,
|
|
31570
31617
|
answerMentioned: querySnapshots.answerMentioned,
|
|
31571
31618
|
createdAt: querySnapshots.createdAt
|
|
31572
|
-
}).from(querySnapshots).where(
|
|
31619
|
+
}).from(querySnapshots).where(inArray30(querySnapshots.runId, runIds)).all() : [];
|
|
31573
31620
|
const stats = computeVisibilityStats({ queries: projectQueries, snapshots, groupBy });
|
|
31574
31621
|
const queryAttribution = buildQueryAttribution(projectQueries);
|
|
31575
31622
|
let shareOfVoice;
|
|
@@ -31580,7 +31627,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
31580
31627
|
queryText: querySnapshots.queryText,
|
|
31581
31628
|
answerMentioned: querySnapshots.answerMentioned,
|
|
31582
31629
|
answerText: querySnapshots.answerText
|
|
31583
|
-
}).from(querySnapshots).where(
|
|
31630
|
+
}).from(querySnapshots).where(inArray30(querySnapshots.runId, runIds)).all() : [];
|
|
31584
31631
|
const attributedSovSnapshots = sovSnapshots.filter((s) => resolveCurrentQuery(queryAttribution, s) !== void 0);
|
|
31585
31632
|
const advanced = activeMeasurementPlan(app.db, project.id)?.plan.schemaVersion === 2;
|
|
31586
31633
|
const queryClass = advanced || projectQueryClassifier(project) ? requestedQueryClass : "all";
|
|
@@ -31678,7 +31725,7 @@ function readVisibilityCompare(db, projectName, query) {
|
|
|
31678
31725
|
answerText: querySnapshots.answerText,
|
|
31679
31726
|
citedDomains: querySnapshots.citedDomains,
|
|
31680
31727
|
location: querySnapshots.location
|
|
31681
|
-
}).from(querySnapshots).where(
|
|
31728
|
+
}).from(querySnapshots).where(inArray30(querySnapshots.runId, runIds)).all() : [];
|
|
31682
31729
|
return {
|
|
31683
31730
|
runCount: runIds.length,
|
|
31684
31731
|
snapshots: snapshots.filter((snapshot) => (providerKey2 === void 0 || normalizeIdentityText(snapshot.provider) === providerKey2) && (locationKey2 === void 0 || (locationKey2 === "none" ? snapshot.location === null : snapshot.location !== null && normalizeIdentityText(snapshot.location) === locationKey2)))
|
|
@@ -31797,7 +31844,7 @@ function readVisibilityContinuity(db, projectName, months) {
|
|
|
31797
31844
|
const trackedQueries = db.select({ id: queries.id, query: queries.query }).from(queries).where(eq55(queries.projectId, project.id)).all();
|
|
31798
31845
|
const loadProjectMonth = (bounds) => {
|
|
31799
31846
|
const runIds = legacyCompareRunIds(db, project.id, bounds);
|
|
31800
|
-
const rows = runIds.length > 0 && trackedQueries.length > 0 ? db.select({ queryId: querySnapshots.queryId, queryText: querySnapshots.queryText, provider: querySnapshots.provider, model: querySnapshots.model }).from(querySnapshots).where(
|
|
31847
|
+
const rows = runIds.length > 0 && trackedQueries.length > 0 ? db.select({ queryId: querySnapshots.queryId, queryText: querySnapshots.queryText, provider: querySnapshots.provider, model: querySnapshots.model }).from(querySnapshots).where(inArray30(querySnapshots.runId, runIds)).all() : [];
|
|
31801
31848
|
return { runCount: runIds.length, snapshots: rows.map(bare) };
|
|
31802
31849
|
};
|
|
31803
31850
|
const frames = [{ frame: "project", continuity: gate(trackedQueries, loadProjectMonth(fromBounds), loadProjectMonth(toBounds)) }];
|
|
@@ -32057,7 +32104,7 @@ async function resultsExportRoutes(app) {
|
|
|
32057
32104
|
}
|
|
32058
32105
|
|
|
32059
32106
|
// ../api-routes/src/composites.ts
|
|
32060
|
-
import { eq as eq57, and as and49, desc as desc27, sql as sql20, like as like5, or as or13, inArray as
|
|
32107
|
+
import { eq as eq57, and as and49, desc as desc27, sql as sql20, like as like5, or as or13, inArray as inArray31 } from "drizzle-orm";
|
|
32061
32108
|
var TOP_INSIGHT_LIMIT = 5;
|
|
32062
32109
|
var SEARCH_HIT_HARD_LIMIT = 50;
|
|
32063
32110
|
var SEARCH_SNIPPET_RADIUS = 80;
|
|
@@ -32358,7 +32405,7 @@ function loadSnapshotsByRunIds(app, runIds, queryIdByText) {
|
|
|
32358
32405
|
rawResponse: querySnapshots.rawResponse,
|
|
32359
32406
|
competitorOverlap: querySnapshots.competitorOverlap,
|
|
32360
32407
|
citedDomains: querySnapshots.citedDomains
|
|
32361
|
-
}).from(querySnapshots).where(
|
|
32408
|
+
}).from(querySnapshots).where(inArray31(querySnapshots.runId, [...runIds])).all();
|
|
32362
32409
|
for (const row of rows) {
|
|
32363
32410
|
const queryText = row.queryText?.trim() || null;
|
|
32364
32411
|
let queryId;
|
|
@@ -32798,7 +32845,7 @@ import crypto29 from "crypto";
|
|
|
32798
32845
|
import { and as and51, desc as desc29, eq as eq59 } from "drizzle-orm";
|
|
32799
32846
|
|
|
32800
32847
|
// ../api-routes/src/content-data.ts
|
|
32801
|
-
import { and as and50, eq as eq58, desc as desc28, gte as gte15, inArray as
|
|
32848
|
+
import { and as and50, eq as eq58, desc as desc28, gte as gte15, inArray as inArray32, lte as lte14 } from "drizzle-orm";
|
|
32802
32849
|
var RECENT_RUNS_WINDOW = 5;
|
|
32803
32850
|
function loadOrchestratorInput(db, project, locationFilter = void 0, gscWindowDays = DEFAULT_CONTENT_GSC_WINDOW_DAYS) {
|
|
32804
32851
|
const projectId = project.id;
|
|
@@ -32938,7 +32985,7 @@ function listRecentAnswerVisibilityRunIds(db, projectId, limit, locationFilter)
|
|
|
32938
32985
|
// Queued/running/failed/cancelled runs may have partial or no
|
|
32939
32986
|
// snapshots; including them risks pointing latestRunId at a run with
|
|
32940
32987
|
// no usable evidence.
|
|
32941
|
-
|
|
32988
|
+
inArray32(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
32942
32989
|
// Probe runs are operator/agent test runs; they must not poison the
|
|
32943
32990
|
// recent-runs window the content engine uses to recommend actions.
|
|
32944
32991
|
notProbeRun()
|
|
@@ -33006,7 +33053,7 @@ function buildCandidateQueries(opts) {
|
|
|
33006
33053
|
const queryRows2 = opts.db.select({ id: queries.id, text: queries.query }).from(queries).where(eq58(queries.projectId, opts.projectId)).all();
|
|
33007
33054
|
const queryIdByText = new Map(queryRows2.map((r) => [r.text, r.id]));
|
|
33008
33055
|
const candidateQueryIds = opts.candidateQueryStrings.map((q) => queryIdByText.get(q)).filter((id) => Boolean(id));
|
|
33009
|
-
const snapshotRows = filterTrackedSnapshots(opts.db.select().from(querySnapshots).where(
|
|
33056
|
+
const snapshotRows = filterTrackedSnapshots(opts.db.select().from(querySnapshots).where(inArray32(querySnapshots.runId, opts.recentRunIds)).all()).filter((r) => candidateQueryIds.includes(r.queryId));
|
|
33010
33057
|
const snapshotsByQuery = /* @__PURE__ */ new Map();
|
|
33011
33058
|
for (const row of snapshotRows) {
|
|
33012
33059
|
const list = snapshotsByQuery.get(row.queryId) ?? [];
|
|
@@ -45064,7 +45111,7 @@ async function gbpLocalPostsRoutes(app, options) {
|
|
|
45064
45111
|
}
|
|
45065
45112
|
|
|
45066
45113
|
// ../api-routes/src/google.ts
|
|
45067
|
-
import { eq as eq66, and as and54, desc as desc31, sql as sql21, inArray as
|
|
45114
|
+
import { eq as eq66, and as and54, desc as desc31, sql as sql21, inArray as inArray33 } from "drizzle-orm";
|
|
45068
45115
|
|
|
45069
45116
|
// ../api-routes/src/gsc-period-comparison.ts
|
|
45070
45117
|
var DAY_MS2 = 864e5;
|
|
@@ -45937,39 +45984,7 @@ async function listProperties(accessToken) {
|
|
|
45937
45984
|
headers: { "Authorization": `Bearer ${accessToken}` },
|
|
45938
45985
|
signal: AbortSignal.timeout(GA4_REQUEST_TIMEOUT_MS)
|
|
45939
45986
|
});
|
|
45940
|
-
if (!res.ok)
|
|
45941
|
-
const raw = await res.text().catch(() => "");
|
|
45942
|
-
let detail = "";
|
|
45943
|
-
let quotaReason = false;
|
|
45944
|
-
try {
|
|
45945
|
-
const parsed = JSON.parse(raw);
|
|
45946
|
-
if (parsed.error?.status === "SERVICE_DISABLED") {
|
|
45947
|
-
detail = " The Google Analytics Admin API is not enabled for this GCP project. Enable it at: https://console.developers.google.com/apis/api/analyticsadmin.googleapis.com/overview";
|
|
45948
|
-
} else if (parsed.error?.message) {
|
|
45949
|
-
detail = ` ${parsed.error.message}`;
|
|
45950
|
-
}
|
|
45951
|
-
quotaReason = (parsed.error?.errors ?? []).some(
|
|
45952
|
-
(e) => e.reason === "rateLimitExceeded" || e.reason === "quotaExceeded" || e.reason === "userRateLimitExceeded"
|
|
45953
|
-
) || parsed.error?.status === "RESOURCE_EXHAUSTED";
|
|
45954
|
-
} catch {
|
|
45955
|
-
if (raw.length < 200) detail = ` ${raw}`;
|
|
45956
|
-
}
|
|
45957
|
-
const sanitized = detail.replace(new RegExp(escapeRegExp(accessToken), "g"), "***");
|
|
45958
|
-
const retryAfterSeconds2 = res.status === 429 || res.status >= 500 || res.status === 403 && quotaReason ? parseRetryAfter(res.headers.get("retry-after")) : void 0;
|
|
45959
|
-
ga4Log("error", "admin.account-summaries-failed", {
|
|
45960
|
-
httpStatus: res.status,
|
|
45961
|
-
retryAfterSeconds: retryAfterSeconds2,
|
|
45962
|
-
quotaReason
|
|
45963
|
-
});
|
|
45964
|
-
throw new GA4ApiError(
|
|
45965
|
-
`Failed to list GA4 properties.${sanitized}`,
|
|
45966
|
-
// A quota 403 is surfaced as 429 so every downstream consumer — the
|
|
45967
|
-
// retry predicate and the route's error mapper — reads it as rate
|
|
45968
|
-
// limiting rather than as a permission denial.
|
|
45969
|
-
res.status === 403 && quotaReason ? 429 : res.status,
|
|
45970
|
-
retryAfterSeconds2
|
|
45971
|
-
);
|
|
45972
|
-
}
|
|
45987
|
+
if (!res.ok) throw await adminApiError(res, accessToken, "admin.account-summaries-failed", "Failed to list GA4 properties.");
|
|
45973
45988
|
return await res.json();
|
|
45974
45989
|
}, "GA4 accountSummaries"));
|
|
45975
45990
|
for (const account of body.accountSummaries ?? []) {
|
|
@@ -45987,6 +46002,53 @@ async function listProperties(accessToken) {
|
|
|
45987
46002
|
} while (pageToken);
|
|
45988
46003
|
return properties;
|
|
45989
46004
|
}
|
|
46005
|
+
async function adminApiError(res, accessToken, logAction, message) {
|
|
46006
|
+
const raw = await res.text().catch(() => "");
|
|
46007
|
+
let detail = "";
|
|
46008
|
+
let quotaReason = false;
|
|
46009
|
+
try {
|
|
46010
|
+
const parsed = JSON.parse(raw);
|
|
46011
|
+
if (parsed.error?.status === "SERVICE_DISABLED") {
|
|
46012
|
+
detail = " The Google Analytics Admin API is not enabled for this GCP project. Enable it at: https://console.developers.google.com/apis/api/analyticsadmin.googleapis.com/overview";
|
|
46013
|
+
} else if (parsed.error?.message) {
|
|
46014
|
+
detail = ` ${parsed.error.message}`;
|
|
46015
|
+
}
|
|
46016
|
+
quotaReason = (parsed.error?.errors ?? []).some(
|
|
46017
|
+
(e) => e.reason === "rateLimitExceeded" || e.reason === "quotaExceeded" || e.reason === "userRateLimitExceeded"
|
|
46018
|
+
) || parsed.error?.status === "RESOURCE_EXHAUSTED";
|
|
46019
|
+
} catch {
|
|
46020
|
+
if (raw.length < 200) detail = ` ${raw}`;
|
|
46021
|
+
}
|
|
46022
|
+
const sanitized = detail.replace(new RegExp(escapeRegExp(accessToken), "g"), "***");
|
|
46023
|
+
const retryAfterSeconds2 = res.status === 429 || res.status >= 500 || res.status === 403 && quotaReason ? parseRetryAfter(res.headers.get("retry-after")) : void 0;
|
|
46024
|
+
ga4Log("error", logAction, { httpStatus: res.status, retryAfterSeconds: retryAfterSeconds2, quotaReason });
|
|
46025
|
+
return new GA4ApiError(`${message}${sanitized}`, res.status === 403 && quotaReason ? 429 : res.status, retryAfterSeconds2);
|
|
46026
|
+
}
|
|
46027
|
+
async function fetchKeyEventNames(accessToken, propertyId) {
|
|
46028
|
+
validateAccessToken2(accessToken);
|
|
46029
|
+
validatePropertyId(propertyId);
|
|
46030
|
+
const names = /* @__PURE__ */ new Set();
|
|
46031
|
+
let pageToken;
|
|
46032
|
+
do {
|
|
46033
|
+
const url = new URL(`${GA4_ADMIN_API_BASE}/properties/${propertyId}/keyEvents`);
|
|
46034
|
+
url.searchParams.set("pageSize", "200");
|
|
46035
|
+
if (pageToken) url.searchParams.set("pageToken", pageToken);
|
|
46036
|
+
const body = await withGa4Limit(() => withGa4Retry(async () => {
|
|
46037
|
+
const res = await fetchWithContext(url, {
|
|
46038
|
+
headers: { "Authorization": `Bearer ${accessToken}` },
|
|
46039
|
+
signal: AbortSignal.timeout(GA4_REQUEST_TIMEOUT_MS)
|
|
46040
|
+
});
|
|
46041
|
+
if (!res.ok) throw await adminApiError(res, accessToken, "admin.key-events-failed", "Failed to list GA4 key events.");
|
|
46042
|
+
return await res.json();
|
|
46043
|
+
}, "GA4 keyEvents"));
|
|
46044
|
+
for (const keyEvent of body.keyEvents ?? []) {
|
|
46045
|
+
const name = keyEvent.eventName?.trim();
|
|
46046
|
+
if (name) names.add(name);
|
|
46047
|
+
}
|
|
46048
|
+
pageToken = body.nextPageToken;
|
|
46049
|
+
} while (pageToken);
|
|
46050
|
+
return [...names].sort();
|
|
46051
|
+
}
|
|
45990
46052
|
async function fetchAggregateSummary(accessToken, propertyId, days) {
|
|
45991
46053
|
validateAccessToken2(accessToken);
|
|
45992
46054
|
validatePropertyId(propertyId);
|
|
@@ -48304,10 +48366,10 @@ async function googleRoutes(app, opts) {
|
|
|
48304
48366
|
locationProfiles: []
|
|
48305
48367
|
});
|
|
48306
48368
|
}
|
|
48307
|
-
const metricRows = app.db.select().from(gbpDailyMetrics).where(and54(eq66(gbpDailyMetrics.projectId, project.id),
|
|
48308
|
-
const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and54(eq66(gbpKeywordImpressions.projectId, project.id),
|
|
48309
|
-
const placeActionRows = app.db.select().from(gbpPlaceActions).where(and54(eq66(gbpPlaceActions.projectId, project.id),
|
|
48310
|
-
const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and54(eq66(gbpLodgingSnapshots.projectId, project.id),
|
|
48369
|
+
const metricRows = app.db.select().from(gbpDailyMetrics).where(and54(eq66(gbpDailyMetrics.projectId, project.id), inArray33(gbpDailyMetrics.locationName, locationNames))).all();
|
|
48370
|
+
const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and54(eq66(gbpKeywordImpressions.projectId, project.id), inArray33(gbpKeywordImpressions.locationName, locationNames))).all();
|
|
48371
|
+
const placeActionRows = app.db.select().from(gbpPlaceActions).where(and54(eq66(gbpPlaceActions.projectId, project.id), inArray33(gbpPlaceActions.locationName, locationNames))).all();
|
|
48372
|
+
const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and54(eq66(gbpLodgingSnapshots.projectId, project.id), inArray33(gbpLodgingSnapshots.locationName, locationNames))).orderBy(desc31(gbpLodgingSnapshots.syncedAt)).all();
|
|
48311
48373
|
const latestLodgingByLocation = /* @__PURE__ */ new Map();
|
|
48312
48374
|
for (const row of lodgingRows) {
|
|
48313
48375
|
if (!latestLodgingByLocation.has(row.locationName)) {
|
|
@@ -48321,7 +48383,7 @@ async function googleRoutes(app, opts) {
|
|
|
48321
48383
|
regularHours: gbpLocations.regularHours,
|
|
48322
48384
|
primaryPhone: gbpLocations.primaryPhone,
|
|
48323
48385
|
openStatus: gbpLocations.openStatus
|
|
48324
|
-
}).from(gbpLocations).where(and54(eq66(gbpLocations.projectId, project.id),
|
|
48386
|
+
}).from(gbpLocations).where(and54(eq66(gbpLocations.projectId, project.id), inArray33(gbpLocations.locationName, locationNames))).all();
|
|
48325
48387
|
return buildGbpSummary({
|
|
48326
48388
|
locationName,
|
|
48327
48389
|
locationCount: locationNames.length,
|
|
@@ -49991,7 +50053,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
49991
50053
|
|
|
49992
50054
|
// ../api-routes/src/ads.ts
|
|
49993
50055
|
import crypto42 from "crypto";
|
|
49994
|
-
import { eq as eq69, and as and57, asc as asc15, desc as desc33, gt as gt6, gte as gte16, lt as lt10, lte as lte16, ne as ne13, inArray as
|
|
50056
|
+
import { eq as eq69, and as and57, asc as asc15, desc as desc33, gt as gt6, gte as gte16, lt as lt10, lte as lte16, ne as ne13, inArray as inArray34, or as or16, isNull as isNull12, isNotNull as isNotNull7, sql as sql24 } from "drizzle-orm";
|
|
49995
50057
|
|
|
49996
50058
|
// ../api-routes/src/ads-activation.ts
|
|
49997
50059
|
import crypto40 from "crypto";
|
|
@@ -53089,7 +53151,7 @@ function semanticallyMatchesMaterializedEntity(app, input) {
|
|
|
53089
53151
|
eq69(adsOperations.projectId, input.projectId),
|
|
53090
53152
|
eq69(adsOperations.entityType, input.entityType),
|
|
53091
53153
|
eq69(adsOperations.entityId, input.entityId),
|
|
53092
|
-
|
|
53154
|
+
inArray34(adsOperations.kind, [createKind, updateKind])
|
|
53093
53155
|
)).orderBy(asc15(adsOperations.createdAt), asc15(adsOperations.id)).all();
|
|
53094
53156
|
if (rows.some((row) => row.state === AdsOperationStates.pending || row.state === AdsOperationStates.reconciling || row.state === AdsOperationStates.unknown || row.kind === updateKind && row.state === AdsOperationStates.succeeded)) {
|
|
53095
53157
|
return false;
|
|
@@ -53537,7 +53599,7 @@ function quarantineExhaustedReconciliation(app, row, now, policy, context) {
|
|
|
53537
53599
|
eq69(adsOperations.id, row.id),
|
|
53538
53600
|
eq69(adsOperations.projectId, row.projectId),
|
|
53539
53601
|
gte16(adsOperations.reconcileAttempts, policy.maxAttempts),
|
|
53540
|
-
|
|
53602
|
+
inArray34(adsOperations.state, [
|
|
53541
53603
|
AdsOperationStates.pending,
|
|
53542
53604
|
AdsOperationStates.unknown,
|
|
53543
53605
|
AdsOperationStates.reconciling
|
|
@@ -53781,7 +53843,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
53781
53843
|
eq69(adsOperations.reconcileStrategy, AdsReconcileStrategies.create_fingerprint),
|
|
53782
53844
|
or16(
|
|
53783
53845
|
isNotNull7(adsOperations.entityId),
|
|
53784
|
-
|
|
53846
|
+
inArray34(adsOperations.state, [
|
|
53785
53847
|
AdsOperationStates.pending,
|
|
53786
53848
|
AdsOperationStates.reconciling
|
|
53787
53849
|
])
|
|
@@ -53832,7 +53894,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
53832
53894
|
const eligibleProjectIds = [...credentialsByProjectId.keys()];
|
|
53833
53895
|
if (eligibleProjectIds.length === 0) return;
|
|
53834
53896
|
const rows = app.db.select().from(adsOperations).where(and57(
|
|
53835
|
-
|
|
53897
|
+
inArray34(adsOperations.projectId, eligibleProjectIds),
|
|
53836
53898
|
staleReconcileWhere
|
|
53837
53899
|
)).orderBy(asc15(adsOperations.updatedAt)).limit(config.batchSize).all();
|
|
53838
53900
|
for (const row of rows) {
|
|
@@ -54158,7 +54220,7 @@ async function adsRoutes(app, opts) {
|
|
|
54158
54220
|
const cursor = parsed.data.cursor ? decodeAdsOperationCursor(parsed.data.cursor, project.id, parsed.data.state) : void 0;
|
|
54159
54221
|
const rows = app.db.select().from(adsOperations).where(and57(
|
|
54160
54222
|
eq69(adsOperations.projectId, project.id),
|
|
54161
|
-
|
|
54223
|
+
inArray34(adsOperations.state, parsed.data.state),
|
|
54162
54224
|
cursor ? or16(
|
|
54163
54225
|
gt6(adsOperations.createdAt, cursor.createdAt),
|
|
54164
54226
|
and57(
|
|
@@ -54592,7 +54654,7 @@ async function adsRoutes(app, opts) {
|
|
|
54592
54654
|
const inFlight2 = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and57(
|
|
54593
54655
|
eq69(runs.projectId, project.id),
|
|
54594
54656
|
eq69(runs.kind, RunKinds["ads-sync"]),
|
|
54595
|
-
|
|
54657
|
+
inArray34(runs.status, [RunStatuses.queued, RunStatuses.running])
|
|
54596
54658
|
)).get();
|
|
54597
54659
|
if (inFlight2) {
|
|
54598
54660
|
const existing = { runId: inFlight2.id, status: inFlight2.status };
|
|
@@ -56623,6 +56685,7 @@ function persistLeadMeasurement(db, input) {
|
|
|
56623
56685
|
leadError: null,
|
|
56624
56686
|
leadSyncedAt: input.syncedAt,
|
|
56625
56687
|
leadAttributionScope: input.report.attributionScope,
|
|
56688
|
+
leadEventNames: input.eventNames,
|
|
56626
56689
|
updatedAt: input.syncedAt
|
|
56627
56690
|
}).onConflictDoUpdate({
|
|
56628
56691
|
target: gaMeasurementSyncStates.projectId,
|
|
@@ -56631,6 +56694,7 @@ function persistLeadMeasurement(db, input) {
|
|
|
56631
56694
|
leadError: null,
|
|
56632
56695
|
leadSyncedAt: input.syncedAt,
|
|
56633
56696
|
leadAttributionScope: input.report.attributionScope,
|
|
56697
|
+
leadEventNames: input.eventNames,
|
|
56634
56698
|
updatedAt: input.syncedAt
|
|
56635
56699
|
}
|
|
56636
56700
|
}).run();
|
|
@@ -56639,12 +56703,23 @@ function persistLeadMeasurement(db, input) {
|
|
|
56639
56703
|
function resetLeadMeasurement(db, projectId, updatedAt) {
|
|
56640
56704
|
db.transaction((tx) => {
|
|
56641
56705
|
tx.delete(gaLeadEventsDaily).where(eq73(gaLeadEventsDaily.projectId, projectId)).run();
|
|
56642
|
-
tx.insert(gaMeasurementSyncStates).values({ projectId, leadStatus: "never-synced", leadError: null, leadSyncedAt: null, leadAttributionScope: null, updatedAt }).onConflictDoUpdate({
|
|
56706
|
+
tx.insert(gaMeasurementSyncStates).values({ projectId, leadStatus: "never-synced", leadError: null, leadSyncedAt: null, leadAttributionScope: null, leadEventNames: null, updatedAt }).onConflictDoUpdate({
|
|
56643
56707
|
target: gaMeasurementSyncStates.projectId,
|
|
56644
|
-
set: { leadStatus: "never-synced", leadError: null, leadSyncedAt: null, leadAttributionScope: null, updatedAt }
|
|
56708
|
+
set: { leadStatus: "never-synced", leadError: null, leadSyncedAt: null, leadAttributionScope: null, leadEventNames: null, updatedAt }
|
|
56645
56709
|
}).run();
|
|
56646
56710
|
});
|
|
56647
56711
|
}
|
|
56712
|
+
function persistKeyEventRead(db, projectId, read, updatedAt) {
|
|
56713
|
+
if (read.status === "disabled") return;
|
|
56714
|
+
const set = read.status === "read" ? { keyEventNames: read.names, keyEventsError: null, updatedAt } : { keyEventsError: read.error ?? "Key event read failed", updatedAt };
|
|
56715
|
+
db.insert(gaMeasurementSyncStates).values({ projectId, ...set }).onConflictDoUpdate({
|
|
56716
|
+
target: gaMeasurementSyncStates.projectId,
|
|
56717
|
+
set
|
|
56718
|
+
}).run();
|
|
56719
|
+
}
|
|
56720
|
+
function sameEventNames(left, right) {
|
|
56721
|
+
return left.length === right.length && left.every((name, index) => name === right[index]);
|
|
56722
|
+
}
|
|
56648
56723
|
function persistMeasurementError(db, projectId, component, message, updatedAt) {
|
|
56649
56724
|
if (component === "acquisition") {
|
|
56650
56725
|
db.insert(gaMeasurementSyncStates).values({
|
|
@@ -56994,8 +57069,9 @@ async function ga4Routes(app, opts) {
|
|
|
56994
57069
|
const syncSearchLanding = !only || only === "search-landing";
|
|
56995
57070
|
const measurementState = app.db.select().from(gaMeasurementSyncStates).where(eq73(gaMeasurementSyncStates.projectId, project.id)).get();
|
|
56996
57071
|
const acquisitionDays = measurementState?.acquisitionSyncedAt != null ? days : GA4_MAX_SYNC_DAYS;
|
|
56997
|
-
|
|
56998
|
-
|
|
57072
|
+
let leadDays = GA4_MAX_SYNC_DAYS;
|
|
57073
|
+
let leadEventNames = [];
|
|
57074
|
+
let keyEventRead = { status: "disabled", names: [] };
|
|
56999
57075
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
57000
57076
|
const runId = crypto47.randomUUID();
|
|
57001
57077
|
app.db.insert(runs).values({
|
|
@@ -57013,6 +57089,18 @@ async function ga4Routes(app, opts) {
|
|
|
57013
57089
|
try {
|
|
57014
57090
|
const { accessToken, propertyId } = await resolveGa4AccessToken(opts, project.name, project.canonicalDomain);
|
|
57015
57091
|
credentialsResolved = true;
|
|
57092
|
+
if (countsKeyEvents(project.measurement)) {
|
|
57093
|
+
try {
|
|
57094
|
+
keyEventRead = { status: "read", names: await fetchKeyEventNames(accessToken, propertyId) };
|
|
57095
|
+
} catch (error) {
|
|
57096
|
+
keyEventRead = { status: "error", names: measurementState?.keyEventNames ?? [], error: describeError(error) };
|
|
57097
|
+
}
|
|
57098
|
+
persistKeyEventRead(app.db, project.id, keyEventRead, (/* @__PURE__ */ new Date()).toISOString());
|
|
57099
|
+
}
|
|
57100
|
+
leadEventNames = countedLeadEventNames(project.measurement.leadEventNames, keyEventRead.names);
|
|
57101
|
+
const previousLeadEvents = measurementState?.leadEventNames ?? null;
|
|
57102
|
+
const leadEventsChanged = previousLeadEvents === null || !sameEventNames(previousLeadEvents, leadEventNames);
|
|
57103
|
+
leadDays = measurementState?.leadSyncedAt != null && !leadEventsChanged ? days : GA4_MAX_SYNC_DAYS;
|
|
57016
57104
|
let rows = [];
|
|
57017
57105
|
let aiReferrals = [];
|
|
57018
57106
|
let socialReferrals = [];
|
|
@@ -57276,13 +57364,16 @@ async function ga4Routes(app, opts) {
|
|
|
57276
57364
|
projectId: project.id,
|
|
57277
57365
|
runId,
|
|
57278
57366
|
syncedAt: measurementNow,
|
|
57279
|
-
report: leadsSettled.value
|
|
57367
|
+
report: leadsSettled.value,
|
|
57368
|
+
eventNames: leadEventNames
|
|
57280
57369
|
});
|
|
57281
57370
|
return {
|
|
57282
57371
|
status: "ready",
|
|
57283
57372
|
days: leadDays,
|
|
57284
57373
|
rowCount: leadsSettled.value.rows.length,
|
|
57285
|
-
attributionScope: leadsSettled.value.attributionScope
|
|
57374
|
+
attributionScope: leadsSettled.value.attributionScope,
|
|
57375
|
+
eventNames: leadEventNames,
|
|
57376
|
+
keyEvents: keyEventRead
|
|
57286
57377
|
};
|
|
57287
57378
|
} catch (error) {
|
|
57288
57379
|
return recordMeasurementFailure("leads", error);
|
|
@@ -60441,7 +60532,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
60441
60532
|
import crypto52 from "crypto";
|
|
60442
60533
|
import { isIP } from "net";
|
|
60443
60534
|
import { isDeepStrictEqual } from "util";
|
|
60444
|
-
import { and as and69, desc as desc39, eq as eq80, gt as gt7, gte as gte19, inArray as
|
|
60535
|
+
import { and as and69, desc as desc39, eq as eq80, gt as gt7, gte as gte19, inArray as inArray35, lt as lt13, lte as lte20, sql as sql30 } from "drizzle-orm";
|
|
60445
60536
|
|
|
60446
60537
|
// ../api-routes/src/traffic-limits.ts
|
|
60447
60538
|
var VERCEL_MAX_SYNC_WINDOW_MS = 24 * 60 * 6e4;
|
|
@@ -65390,7 +65481,7 @@ async function trafficRoutes(app, opts) {
|
|
|
65390
65481
|
const listed = useContentList ? contentPaths : infraPaths;
|
|
65391
65482
|
const IN_LIST_CAP = 2e4;
|
|
65392
65483
|
const listFitsInSql = listed.length <= IN_LIST_CAP;
|
|
65393
|
-
const contentExpr = listed.length === 0 ? useContentList ? sql30`0` : sql30`${crawlerEventsHourly.hits}` : useContentList ? sql30`CASE WHEN ${
|
|
65484
|
+
const contentExpr = listed.length === 0 ? useContentList ? sql30`0` : sql30`${crawlerEventsHourly.hits}` : useContentList ? sql30`CASE WHEN ${inArray35(crawlerEventsHourly.pathNormalized, listed)} THEN ${crawlerEventsHourly.hits} ELSE 0 END` : sql30`CASE WHEN ${inArray35(crawlerEventsHourly.pathNormalized, listed)} THEN 0 ELSE ${crawlerEventsHourly.hits} END`;
|
|
65394
65485
|
if (listFitsInSql) {
|
|
65395
65486
|
const crawlerSeries = app.db.select({
|
|
65396
65487
|
bucket: crawlerSeriesBucket,
|
|
@@ -65779,7 +65870,7 @@ var reportSweepsCheck = {
|
|
|
65779
65870
|
};
|
|
65780
65871
|
|
|
65781
65872
|
// ../api-routes/src/doctor/checks/report-models.ts
|
|
65782
|
-
import { and as and71, eq as eq82, gte as gte21, inArray as
|
|
65873
|
+
import { and as and71, eq as eq82, gte as gte21, inArray as inArray36, lte as lte22 } from "drizzle-orm";
|
|
65783
65874
|
var reportModelsCheck = {
|
|
65784
65875
|
id: "report.models",
|
|
65785
65876
|
category: CheckCategories.providers,
|
|
@@ -65794,7 +65885,7 @@ var reportModelsCheck = {
|
|
|
65794
65885
|
const months = reportMonths.flatMap((month) => {
|
|
65795
65886
|
const bounds = calendarMonthBounds(month);
|
|
65796
65887
|
const previous = new Date(Date.parse(bounds.since) - 1).toISOString().slice(0, 7);
|
|
65797
|
-
const observations = ctx.db.select({ provider: querySnapshots.provider, model: querySnapshots.model, at: runs.createdAt }).from(querySnapshots).innerJoin(runs, eq82(runs.id, querySnapshots.runId)).where(and71(eq82(runs.projectId, ctx.project.id), eq82(runs.kind, RunKinds["answer-visibility"]),
|
|
65888
|
+
const observations = ctx.db.select({ provider: querySnapshots.provider, model: querySnapshots.model, at: runs.createdAt }).from(querySnapshots).innerJoin(runs, eq82(runs.id, querySnapshots.runId)).where(and71(eq82(runs.projectId, ctx.project.id), eq82(runs.kind, RunKinds["answer-visibility"]), inArray36(runs.status, [RunStatuses.completed, RunStatuses.partial]), notProbeRun(), gte21(runs.createdAt, bounds.since), lte22(runs.createdAt, bounds.until))).all();
|
|
65798
65889
|
return readVisibilityContinuity(ctx.db, ctx.project.name, { from: previous, to: month }).map(({ frame, continuity: continuity2 }) => ({
|
|
65799
65890
|
month,
|
|
65800
65891
|
previousMonth: previous,
|
|
@@ -66371,7 +66462,7 @@ var BACKLINKS_CHECKS = [
|
|
|
66371
66462
|
];
|
|
66372
66463
|
|
|
66373
66464
|
// ../api-routes/src/doctor/checks/bing-auth.ts
|
|
66374
|
-
import { and as and73, desc as desc40, eq as eq85, inArray as
|
|
66465
|
+
import { and as and73, desc as desc40, eq as eq85, inArray as inArray37 } from "drizzle-orm";
|
|
66375
66466
|
var BING_CONNECTION_ENTITY = "bing_connection";
|
|
66376
66467
|
var BING_CONNECTED_ACTION = "bing.connected";
|
|
66377
66468
|
var BING_DISCONNECTED_ACTION = "bing.disconnected";
|
|
@@ -66382,7 +66473,7 @@ function lostBingConnection(ctx, project) {
|
|
|
66382
66473
|
const lastChange = ctx.db.select({ action: auditLog.action }).from(auditLog).where(and73(
|
|
66383
66474
|
eq85(auditLog.entityType, BING_CONNECTION_ENTITY),
|
|
66384
66475
|
eq85(auditLog.entityId, project.canonicalDomain),
|
|
66385
|
-
|
|
66476
|
+
inArray37(auditLog.action, [BING_CONNECTED_ACTION, BING_DISCONNECTED_ACTION])
|
|
66386
66477
|
)).orderBy(desc40(auditLog.createdAt)).limit(1).get();
|
|
66387
66478
|
return lastChange?.action !== BING_DISCONNECTED_ACTION;
|
|
66388
66479
|
}
|
|
@@ -66928,7 +67019,7 @@ var ga4ConnectionCheck = {
|
|
|
66928
67019
|
var GA_AUTH_CHECKS = [ga4ConnectionCheck];
|
|
66929
67020
|
|
|
66930
67021
|
// ../api-routes/src/doctor/checks/data-freshness.ts
|
|
66931
|
-
import { and as and74, desc as desc41, eq as eq88, inArray as
|
|
67022
|
+
import { and as and74, desc as desc41, eq as eq88, inArray as inArray38 } from "drizzle-orm";
|
|
66932
67023
|
var GA_DATA_AGING_DAYS = 3;
|
|
66933
67024
|
var GA_DATA_STALE_DAYS = 5;
|
|
66934
67025
|
var GSC_DATA_AGING_DAYS = 5;
|
|
@@ -66957,7 +67048,7 @@ function skipped(code, summary3) {
|
|
|
66957
67048
|
return { status: CheckStatuses.skipped, code, summary: summary3, remediation: null };
|
|
66958
67049
|
}
|
|
66959
67050
|
function lastSyncAgeDays(ctx, kinds) {
|
|
66960
|
-
const row = ctx.db.select({ createdAt: runs.createdAt }).from(runs).where(and74(eq88(runs.projectId, ctx.project.id),
|
|
67051
|
+
const row = ctx.db.select({ createdAt: runs.createdAt }).from(runs).where(and74(eq88(runs.projectId, ctx.project.id), inArray38(runs.kind, kinds), eq88(runs.status, "completed"))).orderBy(desc41(runs.createdAt)).limit(1).get();
|
|
66961
67052
|
if (!row?.createdAt) return null;
|
|
66962
67053
|
const age = Math.floor((Date.now() - Date.parse(row.createdAt)) / DAY_MS4);
|
|
66963
67054
|
return Number.isFinite(age) ? age : null;
|
|
@@ -67452,7 +67543,7 @@ async function probeApiHost(host, options = {}) {
|
|
|
67452
67543
|
}
|
|
67453
67544
|
|
|
67454
67545
|
// ../api-routes/src/doctor/checks/integration-sync.ts
|
|
67455
|
-
import { and as and75, count as count7, desc as desc42, eq as eq89, gte as gte22, gt as gt8, inArray as
|
|
67546
|
+
import { and as and75, count as count7, desc as desc42, eq as eq89, gte as gte22, gt as gt8, inArray as inArray39, isNull as isNull14, notInArray as notInArray3, or as or19 } from "drizzle-orm";
|
|
67456
67547
|
var SYNC_FAILURE_WINDOW = 3;
|
|
67457
67548
|
var SUMMARY_ERROR_LIMIT = 300;
|
|
67458
67549
|
var FINISHED_STATUSES = [RunStatuses.completed, RunStatuses.partial, RunStatuses.failed];
|
|
@@ -67545,8 +67636,8 @@ function readSyncRunState(db, projectId, kind, options = {}) {
|
|
|
67545
67636
|
...options.nothingToSyncErrors?.length ? [or19(isNull14(runs.error), notInArray3(runs.error, [...options.nothingToSyncErrors]))] : []
|
|
67546
67637
|
);
|
|
67547
67638
|
const graded = options.since ? and75(scope, gte22(runs.createdAt, options.since)) : scope;
|
|
67548
|
-
const recent = db.select({ id: runs.id, status: runs.status, trigger: runs.trigger, error: runs.error, createdAt: runs.createdAt }).from(runs).where(and75(graded,
|
|
67549
|
-
const lastSuccess = db.select({ createdAt: runs.createdAt, finishedAt: runs.finishedAt }).from(runs).where(and75(graded,
|
|
67639
|
+
const recent = db.select({ id: runs.id, status: runs.status, trigger: runs.trigger, error: runs.error, createdAt: runs.createdAt }).from(runs).where(and75(graded, inArray39(runs.status, FINISHED_STATUSES))).orderBy(desc42(runs.createdAt)).limit(SYNC_FAILURE_WINDOW).all();
|
|
67640
|
+
const lastSuccess = db.select({ createdAt: runs.createdAt, finishedAt: runs.finishedAt }).from(runs).where(and75(graded, inArray39(runs.status, SUCCESS_STATUSES))).orderBy(desc42(runs.createdAt)).limit(1).get();
|
|
67550
67641
|
const failureCount = db.select({ count: count7() }).from(runs).where(and75(lastSuccess ? and75(graded, gt8(runs.createdAt, lastSuccess.createdAt)) : graded, eq89(runs.status, RunStatuses.failed))).get();
|
|
67551
67642
|
const failuresSinceSuccess = Number(failureCount?.count ?? 0);
|
|
67552
67643
|
const latest = recent[0];
|
|
@@ -68107,7 +68198,7 @@ var PLACES_CHECK_BY_ID = Object.fromEntries(
|
|
|
68107
68198
|
);
|
|
68108
68199
|
|
|
68109
68200
|
// ../api-routes/src/doctor/checks/gbp-reviews.ts
|
|
68110
|
-
import { and as and77, desc as desc43, eq as eq93, gte as gte23, inArray as
|
|
68201
|
+
import { and as and77, desc as desc43, eq as eq93, gte as gte23, inArray as inArray40, sql as sql31 } from "drizzle-orm";
|
|
68111
68202
|
var REVIEW_EVENTS = /* @__PURE__ */ new Set(["review.negative", "review.rating-dropped"]);
|
|
68112
68203
|
var V4_ACCESS_REMEDIATION = "Business Profile reviews use the legacy My Business API (mybusiness.googleapis.com), which Google enables per Cloud project only on request; the API Library and `gcloud services enable` cannot turn it on. Open the enable link in the API access approval email as the approved account, or reply to the access-request thread asking Google to enable mybusiness.googleapis.com for your project number, then run `canonry gbp sync`.";
|
|
68113
68204
|
var reviewsAccessCheck = {
|
|
@@ -68230,7 +68321,7 @@ var reviewDeliveryCheck = {
|
|
|
68230
68321
|
payload: reviewWebhookDeliveries.payload
|
|
68231
68322
|
}).from(reviewWebhookDeliveries).where(and77(
|
|
68232
68323
|
eq93(reviewWebhookDeliveries.projectId, ctx.project.id),
|
|
68233
|
-
|
|
68324
|
+
inArray40(reviewWebhookDeliveries.state, [ReviewDeliveryStates.Uncertain, ReviewDeliveryStates.Failed]),
|
|
68234
68325
|
gte23(lastTouched, since)
|
|
68235
68326
|
)).orderBy(desc43(lastTouched)).all();
|
|
68236
68327
|
if (rows.length === 0) {
|
|
@@ -68815,7 +68906,7 @@ var RUNTIME_STATE_CHECKS = [
|
|
|
68815
68906
|
];
|
|
68816
68907
|
|
|
68817
68908
|
// ../api-routes/src/doctor/checks/traffic-source.ts
|
|
68818
|
-
import { and as and78, desc as desc44, eq as eq94, gte as gte24, inArray as
|
|
68909
|
+
import { and as and78, desc as desc44, eq as eq94, gte as gte24, inArray as inArray41, isNotNull as isNotNull9, ne as ne16, sql as sql32 } from "drizzle-orm";
|
|
68819
68910
|
var RECENT_DATA_WARN_DAYS = 7;
|
|
68820
68911
|
var RECENT_DATA_FAIL_DAYS = 30;
|
|
68821
68912
|
function isCloudflareDirectPush(source) {
|
|
@@ -68995,7 +69086,7 @@ var recentDataCheck = {
|
|
|
68995
69086
|
ctx.db.select({ total: sql32`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
68996
69087
|
and78(
|
|
68997
69088
|
eq94(crawlerEventsHourly.projectId, ctx.project.id),
|
|
68998
|
-
|
|
69089
|
+
inArray41(crawlerEventsHourly.sourceId, activeSourceIds),
|
|
68999
69090
|
gte24(crawlerEventsHourly.tsHour, warnCutoff)
|
|
69000
69091
|
)
|
|
69001
69092
|
).get()?.total ?? 0
|
|
@@ -69004,7 +69095,7 @@ var recentDataCheck = {
|
|
|
69004
69095
|
ctx.db.select({ total: sql32`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
69005
69096
|
and78(
|
|
69006
69097
|
eq94(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
69007
|
-
|
|
69098
|
+
inArray41(aiReferralEventsHourly.sourceId, activeSourceIds),
|
|
69008
69099
|
gte24(aiReferralEventsHourly.tsHour, warnCutoff)
|
|
69009
69100
|
)
|
|
69010
69101
|
).get()?.total ?? 0
|
|
@@ -69013,7 +69104,7 @@ var recentDataCheck = {
|
|
|
69013
69104
|
ctx.db.select({ total: sql32`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
69014
69105
|
and78(
|
|
69015
69106
|
eq94(aiUserFetchEventsHourly.projectId, ctx.project.id),
|
|
69016
|
-
|
|
69107
|
+
inArray41(aiUserFetchEventsHourly.sourceId, activeSourceIds),
|
|
69017
69108
|
gte24(aiUserFetchEventsHourly.tsHour, warnCutoff)
|
|
69018
69109
|
)
|
|
69019
69110
|
).get()?.total ?? 0
|
|
@@ -69039,7 +69130,7 @@ var recentDataCheck = {
|
|
|
69039
69130
|
ctx.db.select({ total: sql32`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
69040
69131
|
and78(
|
|
69041
69132
|
eq94(crawlerEventsHourly.projectId, ctx.project.id),
|
|
69042
|
-
|
|
69133
|
+
inArray41(crawlerEventsHourly.sourceId, activeSourceIds),
|
|
69043
69134
|
gte24(crawlerEventsHourly.tsHour, failCutoff)
|
|
69044
69135
|
)
|
|
69045
69136
|
).get()?.total ?? 0
|
|
@@ -69048,7 +69139,7 @@ var recentDataCheck = {
|
|
|
69048
69139
|
ctx.db.select({ total: sql32`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
69049
69140
|
and78(
|
|
69050
69141
|
eq94(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
69051
|
-
|
|
69142
|
+
inArray41(aiReferralEventsHourly.sourceId, activeSourceIds),
|
|
69052
69143
|
gte24(aiReferralEventsHourly.tsHour, failCutoff)
|
|
69053
69144
|
)
|
|
69054
69145
|
).get()?.total ?? 0
|
|
@@ -69057,7 +69148,7 @@ var recentDataCheck = {
|
|
|
69057
69148
|
ctx.db.select({ total: sql32`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
69058
69149
|
and78(
|
|
69059
69150
|
eq94(aiUserFetchEventsHourly.projectId, ctx.project.id),
|
|
69060
|
-
|
|
69151
|
+
inArray41(aiUserFetchEventsHourly.sourceId, activeSourceIds),
|
|
69061
69152
|
gte24(aiUserFetchEventsHourly.tsHour, failCutoff)
|
|
69062
69153
|
)
|
|
69063
69154
|
).get()?.total ?? 0
|
|
@@ -70313,7 +70404,7 @@ async function statusRoutes(app, opts) {
|
|
|
70313
70404
|
|
|
70314
70405
|
// ../api-routes/src/discovery/routes.ts
|
|
70315
70406
|
import crypto54 from "crypto";
|
|
70316
|
-
import { and as and80, desc as desc46, eq as eq96, gte as gte25, inArray as
|
|
70407
|
+
import { and as and80, desc as desc46, eq as eq96, gte as gte25, inArray as inArray42, isNull as isNull16, or as or20 } from "drizzle-orm";
|
|
70317
70408
|
var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
|
|
70318
70409
|
async function discoveryRoutes(app, opts) {
|
|
70319
70410
|
app.post("/projects/:name/discover/run", async (request, reply) => {
|
|
@@ -70368,7 +70459,7 @@ async function discoveryRoutes(app, opts) {
|
|
|
70368
70459
|
// must never reuse another set's session. Null (= Gemini-only
|
|
70369
70460
|
// default, including explicit ['gemini']) matches legacy rows.
|
|
70370
70461
|
seedProviders == null ? isNull16(discoverySessions.seedProviders) : eq96(discoverySessions.seedProviders, seedProviders),
|
|
70371
|
-
|
|
70462
|
+
inArray42(discoverySessions.status, [
|
|
70372
70463
|
DiscoverySessionStatuses.queued,
|
|
70373
70464
|
DiscoverySessionStatuses.seeding,
|
|
70374
70465
|
DiscoverySessionStatuses.probing
|
|
@@ -71076,7 +71167,7 @@ function dedupeStrings(input) {
|
|
|
71076
71167
|
|
|
71077
71168
|
// ../api-routes/src/technical-aeo.ts
|
|
71078
71169
|
import crypto56 from "crypto";
|
|
71079
|
-
import { and as and82, asc as asc21, count as count8, desc as desc47, eq as eq99, gte as gte26, inArray as
|
|
71170
|
+
import { and as and82, asc as asc21, count as count8, desc as desc47, eq as eq99, gte as gte26, inArray as inArray43, isNotNull as isNotNull10, isNull as isNull17, lt as lt14, or as or21, sql as sql34 } from "drizzle-orm";
|
|
71080
71171
|
import { alias } from "drizzle-orm/sqlite-core";
|
|
71081
71172
|
|
|
71082
71173
|
// ../api-routes/src/technical-aeo-issues.ts
|
|
@@ -71712,7 +71803,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
71712
71803
|
eq99(siteCrawlSnapshots.projectId, projectId),
|
|
71713
71804
|
eq99(runs.projectId, projectId),
|
|
71714
71805
|
eq99(runs.kind, RunKinds["site-audit"]),
|
|
71715
|
-
|
|
71806
|
+
inArray43(runs.status, SURFACEABLE_STATUSES),
|
|
71716
71807
|
notProbeRun()
|
|
71717
71808
|
];
|
|
71718
71809
|
const availableScanDatesFor = (projectId, requestedDate) => {
|
|
@@ -71782,7 +71873,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
71782
71873
|
eq99(siteAuditSnapshots.projectId, projectId),
|
|
71783
71874
|
eq99(runs.projectId, projectId),
|
|
71784
71875
|
eq99(runs.kind, RunKinds["site-audit"]),
|
|
71785
|
-
|
|
71876
|
+
inArray43(runs.status, SURFACEABLE_STATUSES),
|
|
71786
71877
|
notProbeRun(),
|
|
71787
71878
|
...recordedBefore ? [lt14(siteAuditSnapshots.createdAt, recordedBefore)] : []
|
|
71788
71879
|
];
|
|
@@ -71925,7 +72016,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
71925
72016
|
eq99(runs.id, runId),
|
|
71926
72017
|
eq99(runs.projectId, projectId),
|
|
71927
72018
|
eq99(runs.kind, RunKinds["site-audit"]),
|
|
71928
|
-
|
|
72019
|
+
inArray43(runs.status, SURFACEABLE_STATUSES),
|
|
71929
72020
|
notProbeRun()
|
|
71930
72021
|
)).limit(1).get());
|
|
71931
72022
|
const assertKnownAuditRun = (projectId, runId) => {
|
|
@@ -71935,7 +72026,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
71935
72026
|
eq99(siteAuditSnapshots.projectId, projectId),
|
|
71936
72027
|
eq99(runs.projectId, projectId),
|
|
71937
72028
|
eq99(runs.kind, RunKinds["site-audit"]),
|
|
71938
|
-
|
|
72029
|
+
inArray43(runs.status, SURFACEABLE_STATUSES),
|
|
71939
72030
|
notProbeRun()
|
|
71940
72031
|
)).limit(1).get());
|
|
71941
72032
|
const emptyCrawlSummary = (projectName, legacyAuditAvailable) => ({
|
|
@@ -72066,7 +72157,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72066
72157
|
eq99(siteAuditSnapshots.projectId, project.id),
|
|
72067
72158
|
eq99(runs.projectId, project.id),
|
|
72068
72159
|
eq99(runs.kind, RunKinds["site-audit"]),
|
|
72069
|
-
|
|
72160
|
+
inArray43(runs.status, SURFACEABLE_STATUSES),
|
|
72070
72161
|
notProbeRun()
|
|
72071
72162
|
)).orderBy(desc47(siteAuditSnapshots.createdAt)).limit(limit).all();
|
|
72072
72163
|
return { project: project.name, points: rows.reverse() };
|
|
@@ -72381,8 +72472,8 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72381
72472
|
eq99(siteCrawlEdges.internal, true),
|
|
72382
72473
|
isNotNull10(siteCrawlEdges.targetNodeKey),
|
|
72383
72474
|
or21(
|
|
72384
|
-
|
|
72385
|
-
|
|
72475
|
+
inArray43(siteCrawlEdges.sourceNodeKey, frontier),
|
|
72476
|
+
inArray43(siteCrawlEdges.targetNodeKey, frontier)
|
|
72386
72477
|
)
|
|
72387
72478
|
)).orderBy(asc21(siteCrawlEdges.edgeKey)).limit(maxEdges + maxNodes + 1).all();
|
|
72388
72479
|
if (candidates.length > maxEdges + maxNodes) queryTruncated = true;
|
|
@@ -72419,7 +72510,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72419
72510
|
eq99(siteCrawlPages.projectId, scope.projectId),
|
|
72420
72511
|
eq99(siteCrawlPages.runId, scope.runId),
|
|
72421
72512
|
eq99(siteCrawlPages.attemptId, scope.attemptId),
|
|
72422
|
-
|
|
72513
|
+
inArray43(siteCrawlPages.nodeKey, nodeKeys)
|
|
72423
72514
|
)).all();
|
|
72424
72515
|
const persistedNodeKeys = new Set(pageRows.map((row) => row.nodeKey));
|
|
72425
72516
|
const outermostNodeKeys = pageRows.filter((row) => distances.get(row.nodeKey) === hops).map((row) => row.nodeKey);
|
|
@@ -72429,8 +72520,8 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72429
72520
|
eq99(siteCrawlEdges.attemptId, scope.attemptId),
|
|
72430
72521
|
eq99(siteCrawlEdges.internal, true),
|
|
72431
72522
|
isNotNull10(siteCrawlEdges.targetNodeKey),
|
|
72432
|
-
|
|
72433
|
-
|
|
72523
|
+
inArray43(siteCrawlEdges.sourceNodeKey, outermostNodeKeys),
|
|
72524
|
+
inArray43(siteCrawlEdges.targetNodeKey, outermostNodeKeys)
|
|
72434
72525
|
)).limit(1).get();
|
|
72435
72526
|
if (omittedOutermostEdge && !seenEdgeKeys.has(omittedOutermostEdge.edgeKey)) {
|
|
72436
72527
|
omittedEdgeKeys.add(omittedOutermostEdge.edgeKey);
|
|
@@ -72531,7 +72622,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72531
72622
|
eq99(siteCrawlEdges.followable, true),
|
|
72532
72623
|
eq99(siteCrawlEdges.relation, "anchor"),
|
|
72533
72624
|
isNotNull10(siteCrawlEdges.targetNodeKey),
|
|
72534
|
-
|
|
72625
|
+
inArray43(siteCrawlEdges.sourceNodeKey, frontier)
|
|
72535
72626
|
)).orderBy(asc21(siteCrawlEdges.edgeKey)).limit(SITE_HEALTH_PATH_MAX_VISITED_NODES + 1).all();
|
|
72536
72627
|
if (candidates.length > SITE_HEALTH_PATH_MAX_VISITED_NODES) truncated = true;
|
|
72537
72628
|
const candidateTargetKeys = [...new Set(candidates.map((edge) => edge.targetNodeKey).filter((nodeKey) => nodeKey != null))];
|
|
@@ -72539,7 +72630,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72539
72630
|
eq99(siteCrawlPages.projectId, scope.projectId),
|
|
72540
72631
|
eq99(siteCrawlPages.runId, scope.runId),
|
|
72541
72632
|
eq99(siteCrawlPages.attemptId, scope.attemptId),
|
|
72542
|
-
|
|
72633
|
+
inArray43(siteCrawlPages.nodeKey, candidateTargetKeys)
|
|
72543
72634
|
)).all().map((row) => row.nodeKey));
|
|
72544
72635
|
const next = /* @__PURE__ */ new Set();
|
|
72545
72636
|
for (const edge of candidates.slice(0, SITE_HEALTH_PATH_MAX_VISITED_NODES)) {
|
|
@@ -72584,7 +72675,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72584
72675
|
eq99(siteCrawlPages.projectId, scope.projectId),
|
|
72585
72676
|
eq99(siteCrawlPages.runId, scope.runId),
|
|
72586
72677
|
eq99(siteCrawlPages.attemptId, scope.attemptId),
|
|
72587
|
-
|
|
72678
|
+
inArray43(siteCrawlPages.nodeKey, pathKeys)
|
|
72588
72679
|
)).all();
|
|
72589
72680
|
const pageByKey = new Map(pathRows.map((row) => [row.nodeKey, row]));
|
|
72590
72681
|
const pathDetection = templateDetectionOf(snapshot.templateDetection);
|
|
@@ -72875,14 +72966,14 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72875
72966
|
eq99(siteCrawlPages.projectId, scope.projectId),
|
|
72876
72967
|
eq99(siteCrawlPages.runId, scope.runId),
|
|
72877
72968
|
eq99(siteCrawlPages.attemptId, scope.attemptId),
|
|
72878
|
-
|
|
72969
|
+
inArray43(siteCrawlPages.nodeKey, pageKeys)
|
|
72879
72970
|
)).all();
|
|
72880
72971
|
const edgeRowsFor = (scope) => linkKeys.length === 0 ? [] : app.db.select().from(siteCrawlEdges).where(and82(
|
|
72881
72972
|
eq99(siteCrawlEdges.projectId, scope.projectId),
|
|
72882
72973
|
eq99(siteCrawlEdges.runId, scope.runId),
|
|
72883
72974
|
eq99(siteCrawlEdges.attemptId, scope.attemptId),
|
|
72884
72975
|
eq99(siteCrawlEdges.internal, true),
|
|
72885
|
-
|
|
72976
|
+
inArray43(siteCrawlEdges.edgeKey, linkKeys)
|
|
72886
72977
|
)).all();
|
|
72887
72978
|
const beforePages = new Map(pageRowsFor(beforeScope).map((row) => [row.nodeKey, mapCrawlPage(row)]));
|
|
72888
72979
|
const afterPages = new Map(pageRowsFor(afterScope).map((row) => [row.nodeKey, mapCrawlPage(row)]));
|
|
@@ -73408,9 +73499,9 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
73408
73499
|
eq99(siteCrawlSnapshots.projectId, project.id),
|
|
73409
73500
|
eq99(runs.projectId, project.id),
|
|
73410
73501
|
eq99(runs.kind, RunKinds["site-audit"]),
|
|
73411
|
-
|
|
73502
|
+
inArray43(runs.status, SURFACEABLE_STATUSES),
|
|
73412
73503
|
notProbeRun(),
|
|
73413
|
-
|
|
73504
|
+
inArray43(siteCrawlSnapshots.runId, runIds)
|
|
73414
73505
|
)).all().map((row) => row.runId));
|
|
73415
73506
|
return {
|
|
73416
73507
|
project: project.name,
|
|
@@ -73551,7 +73642,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
73551
73642
|
)).where(and82(
|
|
73552
73643
|
eq99(runs.projectId, project.id),
|
|
73553
73644
|
eq99(runs.kind, RunKinds["site-audit"]),
|
|
73554
|
-
|
|
73645
|
+
inArray43(runs.status, [RunStatuses.queued, RunStatuses.running])
|
|
73555
73646
|
)).get();
|
|
73556
73647
|
if (existing) {
|
|
73557
73648
|
if (existing.identityKey === identityKey) {
|