@canonry/canonry 7.63.0 → 7.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/agent-workspace/skills/aero/references/ai-traffic-tracking.md +12 -9
- package/assets/agent-workspace/skills/canonry/references/ai-traffic-tracking.md +12 -9
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +20 -3
- package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +10 -0
- package/assets/assets/{AgentSetupPage-D6lCJ1G1.js → AgentSetupPage-C1e8ca-F.js} +1 -1
- package/assets/assets/{AuditHistoryPanel-DlgI3o-U.js → AuditHistoryPanel-w8m0gCI_.js} +1 -1
- package/assets/assets/{BacklinksPage-ByiMqbSI.js → BacklinksPage-5KLau65-.js} +1 -1
- package/assets/assets/{HistoryPage-DclVeuLO.js → HistoryPage-BDT8bwji.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-DDHybtHa.js → MeasurementPropertyPage-BXeUhCMT.js} +1 -1
- package/assets/assets/{ProjectPage-vBu6oWFi.js → ProjectPage-DpkuLS-J.js} +1 -1
- package/assets/assets/{RunsPage-CYBJ6pXX.js → RunsPage-sX82BCc6.js} +1 -1
- package/assets/assets/{SettingsPage-w0GmXir0.js → SettingsPage-Ckpdf_CN.js} +1 -1
- package/assets/assets/{SiteHealthSection-DDTjGZ05.js → SiteHealthSection-BXzwqMPd.js} +2 -2
- package/assets/assets/{ToneBadge-MKA1xeYc.js → ToneBadge-DX3v0ZMs.js} +1 -1
- package/assets/assets/{TrafficPage-hUWYv-HT.js → TrafficPage-DXFWGVO1.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-CGHgPxs8.js → TrafficSourceDetailPage-C5fkng5v.js} +1 -1
- package/assets/assets/{account-context-qX-Es0RK.js → account-context-CeU5Z9QZ.js} +1 -1
- package/assets/assets/{card-CzROANT5.js → card-BBGm0dhg.js} +1 -1
- package/assets/assets/{extract-error-message-BY1STLiX.js → extract-error-message-CfVZrmn7.js} +1 -1
- package/assets/assets/{format-helpers-BNQR1HNK.js → format-helpers-D7251Obw.js} +1 -1
- package/assets/assets/{index-LmB57HOs.js → index-DkJdIncY.js} +4 -4
- package/assets/assets/{query-client-Gz37p16p.js → query-client-D0E1gVp6.js} +1 -1
- package/assets/assets/{react-query-C6DtBAYQ.js → react-query-D23hl-0E.js} +1 -1
- package/assets/assets/{react-sigma_core.esm.min-CgxuyPPF.js → react-sigma_core.esm.min-00xBdRUm.js} +1 -1
- package/assets/assets/{service-DyHZWnMe.js → service-DgWa71E6.js} +1 -1
- package/assets/index.html +7 -7
- package/dist/{ads-FOUJNHP4.js → ads-KYINOV7M.js} +3 -3
- package/dist/{agent-UVDVH7LK.js → agent-KUYZWQDM.js} +7 -7
- package/dist/{agent-ask-UEYN2SQX.js → agent-ask-MMQJ676U.js} +3 -3
- package/dist/{agent-conversations-F54376Q2.js → agent-conversations-HHBEVWSA.js} +3 -3
- package/dist/{agent-memory-SOHBTJ4U.js → agent-memory-4GVGUXS5.js} +3 -3
- package/dist/{agent-providers-MMEK2H6V.js → agent-providers-NZHQGXOD.js} +3 -3
- package/dist/{agent-transcript-5IJ3VAEV.js → agent-transcript-DX6OH72V.js} +3 -3
- package/dist/{analytics-LDWO5IW6.js → analytics-ZB3WSJJ7.js} +3 -3
- package/dist/{apply-PSGFDJIC.js → apply-KINEQ47G.js} +3 -3
- package/dist/{backfill-HZU3BBOH.js → backfill-6BNBH7ZO.js} +9 -9
- package/dist/{backlinks-X6DXIL2O.js → backlinks-H3HTXZDY.js} +3 -3
- package/dist/{bing-3HMFUEOO.js → bing-F4LWNUZV.js} +3 -3
- package/dist/{bootstrap-ZUSSLXCI.js → bootstrap-KBV763E2.js} +10 -10
- package/dist/{cdp-FH627HJ6.js → cdp-LN3ZPTDI.js} +7 -7
- package/dist/{chunk-HNZQVIPS.js → chunk-3I3TZNDR.js} +23 -1
- package/dist/{chunk-DBA374EM.js → chunk-3VHU332P.js} +24 -20
- package/dist/{chunk-A57HYHJ3.js → chunk-4MLRY4FJ.js} +1 -1
- package/dist/{chunk-PH7RTAWW.js → chunk-52VCSAX7.js} +1 -1
- package/dist/{chunk-5VAC4KQ2.js → chunk-7TJGQHY6.js} +3 -3
- package/dist/{chunk-LEG7F3DN.js → chunk-B23LQ2IZ.js} +2 -2
- package/dist/{chunk-5YC6IU44.js → chunk-C5ZK4IHK.js} +2 -2
- package/dist/{chunk-SN5A767O.js → chunk-CXZGOSWD.js} +1 -1
- package/dist/{chunk-2LAL5W6J.js → chunk-D7IDW3TO.js} +3 -3
- package/dist/{chunk-ZJTU73GW.js → chunk-DBP7MBK7.js} +3 -3
- package/dist/{chunk-GRWZC3GQ.js → chunk-DYCCEDZF.js} +1 -1
- package/dist/{chunk-CWMJQ2JV.js → chunk-E2K4HLIX.js} +4 -4
- package/dist/{chunk-UYPBR3SF.js → chunk-EGWLPPTB.js} +2 -2
- package/dist/{chunk-ERJ54U2I.js → chunk-GDQBZMDZ.js} +1 -1
- package/dist/{chunk-OIHJJHJR.js → chunk-GQILYY3G.js} +1 -1
- package/dist/{chunk-L2QPAUTQ.js → chunk-H7WFBL5L.js} +1 -1
- package/dist/{chunk-SG2OPR7J.js → chunk-HOPQMZOC.js} +1 -1
- package/dist/{chunk-WYTRXYUR.js → chunk-IGITZQRK.js} +5 -5
- package/dist/{chunk-TDWNONBU.js → chunk-IZ74LHLX.js} +5 -5
- package/dist/{chunk-NOQCIXM6.js → chunk-JUQBI2Y2.js} +1 -1
- package/dist/{chunk-QPTSZDHE.js → chunk-KH7443NX.js} +4 -4
- package/dist/{chunk-Q4U2GJME.js → chunk-L6QDD6F5.js} +316 -158
- package/dist/{chunk-EHTSCLEL.js → chunk-LJZ7GIGO.js} +1 -1
- package/dist/{chunk-UBP3AAKA.js → chunk-LVT6WRLB.js} +1 -1
- package/dist/{chunk-I5QSS3CY.js → chunk-NSGCU5X6.js} +348 -336
- package/dist/{chunk-QNFX7ZCT.js → chunk-S67ZCRDF.js} +1 -1
- package/dist/{chunk-H22RCHYH.js → chunk-SQXSMO35.js} +3 -3
- package/dist/{chunk-67262NJL.js → chunk-STI6DRNG.js} +2 -2
- package/dist/{chunk-LBD7YXVD.js → chunk-T42EHWAR.js} +2 -2
- package/dist/{chunk-IDQZTPRG.js → chunk-TWUBHLRB.js} +2 -2
- package/dist/{chunk-SQYYAYH6.js → chunk-U2QS52HS.js} +3 -3
- package/dist/{chunk-W5TIRS4U.js → chunk-V4SAX4MI.js} +4 -4
- package/dist/{chunk-TKLE2Y6H.js → chunk-VCMF4TX5.js} +63 -3
- package/dist/{chunk-XWDCLX55.js → chunk-WJHOTZV3.js} +8 -8
- package/dist/{citations-BKWLP5S3.js → citations-OBRSEU4U.js} +3 -3
- package/dist/{cli-catalog-VRJS66GR.js → cli-catalog-2PSBZUIA.js} +3 -3
- package/dist/{cli-commands-6LZ5OIIP.js → cli-commands-44OZDNWA.js} +7 -7
- package/dist/cli.js +13 -13
- package/dist/{competitor-VELMM2TJ.js → competitor-6CMPUGOO.js} +3 -3
- package/dist/{content-I525MITL.js → content-ZTWFVZEH.js} +3 -3
- package/dist/{dashboard-XJJ6NZ2L.js → dashboard-6M7TS53W.js} +6 -6
- package/dist/{demo-X7LQ24GS.js → demo-6NSR6BVC.js} +1 -1
- package/dist/{demo-server-MBPBTJXG.js → demo-server-3YD53OJ6.js} +11 -11
- package/dist/{discover-E2CV5ZP7.js → discover-2SD6PX63.js} +3 -3
- package/dist/{discover-eval-ESRCWRHP.js → discover-eval-N34ZXEGG.js} +3 -3
- package/dist/{doctor-BQDVERII.js → doctor-BKLHIVSH.js} +3 -3
- package/dist/{evidence-NUULK5XD.js → evidence-DFBKZAYQ.js} +3 -3
- package/dist/{export-cmd-K324RTN4.js → export-cmd-U43VCFQA.js} +3 -3
- package/dist/{ga-PQ36UFTK.js → ga-6SHEXO27.js} +22 -3
- package/dist/{gbp-KTYA6KHR.js → gbp-TMU3ASMH.js} +3 -3
- package/dist/{google-3D4E7TJX.js → google-RTDYVX35.js} +4 -4
- package/dist/{google-marketing-4FRO4PRN.js → google-marketing-VR7CZD3V.js} +1 -1
- package/dist/{health-cmd-CZJOZUAQ.js → health-cmd-R4CR5JSV.js} +3 -3
- package/dist/{history-JNH34GAM.js → history-76HXCNM7.js} +3 -3
- package/dist/index.d.ts +59 -0
- package/dist/index.js +24 -24
- package/dist/{init-JRGRHLYU.js → init-J6BADMB7.js} +11 -11
- package/dist/{insights-STYJSZBB.js → insights-JQ7ZUTEB.js} +3 -3
- package/dist/intelligence-service-XTCLJSAP.js +15 -0
- package/dist/{journeys-POTSSBOM.js → journeys-GPOCEKPM.js} +3 -3
- package/dist/{keys-BPCSPX2O.js → keys-CEPK4BP5.js} +3 -3
- package/dist/{keyword-6SML434W.js → keyword-6NCXMIFC.js} +3 -3
- package/dist/{logs-WTKKH4UJ.js → logs-IIGC4WKI.js} +3 -3
- package/dist/{mcp-HTAHMVRC.js → mcp-RC2LU65U.js} +2 -2
- package/dist/mcp.js +9 -9
- package/dist/{measurement-plan-LJHKKRZ7.js → measurement-plan-BH3ZXRLG.js} +5 -5
- package/dist/{notify-EARS4LMG.js → notify-JVL7ZQWC.js} +3 -3
- package/dist/{organic-evidence-W7ZQQKPL.js → organic-evidence-FU2254CJ.js} +3 -3
- package/dist/{overview-C7KQD4NR.js → overview-CQOJKYB3.js} +4 -4
- package/dist/{project-YU2FIL4B.js → project-CHBBMK7T.js} +7 -4
- package/dist/{query-SYFLWHFA.js → query-FIUQXVX4.js} +3 -3
- package/dist/{research-UOUXMFBV.js → research-N3CSBKTG.js} +3 -3
- package/dist/{results-export-VYPG2Z6S.js → results-export-5RCAVBD4.js} +3 -3
- package/dist/{run-GZD3MQGS.js → run-6GQF3LBR.js} +4 -4
- package/dist/{schedule-PAA2NLGF.js → schedule-Z36TCNV2.js} +3 -3
- package/dist/{search-6RWCUEEY.js → search-ON4HP22R.js} +3 -3
- package/dist/{serve-FTAFEEJD.js → serve-GWGRQVKA.js} +25 -25
- package/dist/{session-E4V5MRUE.js → session-XHMABUUK.js} +12 -12
- package/dist/{settings-TTA775EJ.js → settings-LVZDNSTS.js} +3 -3
- package/dist/{skills-GA35KKOV.js → skills-3DOCO57E.js} +2 -2
- package/dist/{snapshot-QVQVAMMN.js → snapshot-JVUWV4MQ.js} +3 -3
- package/dist/{src-CTHVFVLF.js → src-QCQT7JBJ.js} +2 -2
- package/dist/{status-E7B726S6.js → status-BAAI3UGB.js} +4 -4
- package/dist/{technical-aeo-SMPN3QDQ.js → technical-aeo-RF3KVZNQ.js} +3 -3
- package/dist/{telemetry-CTBFPMWD.js → telemetry-67H5UO2X.js} +4 -4
- package/dist/{tools-XKGEC56T.js → tools-65JSRP7T.js} +11 -11
- package/dist/{traffic-XACOSYYM.js → traffic-OZMUJLQG.js} +5 -5
- package/dist/{users-WJC7SGRL.js → users-5Q6PLQTL.js} +3 -3
- package/dist/{visibility-stats-H3ZNFV5M.js → visibility-stats-L35IYACG.js} +3 -3
- package/dist/{wordpress-72YMWF7F.js → wordpress-I64CCIJA.js} +3 -3
- package/package.json +1 -1
- package/dist/intelligence-service-7LCTJQDL.js +0 -15
|
@@ -9,14 +9,14 @@ import {
|
|
|
9
9
|
normalizeCloudflareWorkerEvent,
|
|
10
10
|
sessionizeJourneyRequests,
|
|
11
11
|
verifyRequestSignature
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-HOPQMZOC.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-S67ZCRDF.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-3I3TZNDR.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,
|
|
@@ -1163,7 +1165,7 @@ import {
|
|
|
1163
1165
|
wordpressSchemaDeployResultDtoSchema,
|
|
1164
1166
|
wordpressSchemaStatusResultDtoSchema,
|
|
1165
1167
|
wordpressStatusDtoSchema
|
|
1166
|
-
} from "./chunk-
|
|
1168
|
+
} from "./chunk-VCMF4TX5.js";
|
|
1167
1169
|
|
|
1168
1170
|
// ../api-routes/src/user-session.ts
|
|
1169
1171
|
import crypto2 from "crypto";
|
|
@@ -11732,7 +11734,9 @@ async function projectRoutes(app, opts) {
|
|
|
11732
11734
|
measurement: {
|
|
11733
11735
|
marketingHosts: patch.measurement.marketingHosts ?? existing.measurement.marketingHosts,
|
|
11734
11736
|
brandTerms: patch.measurement.brandTerms ?? existing.measurement.brandTerms,
|
|
11735
|
-
leadEventNames: patch.measurement.leadEventNames ?? existing.measurement.leadEventNames
|
|
11737
|
+
leadEventNames: patch.measurement.leadEventNames ?? existing.measurement.leadEventNames,
|
|
11738
|
+
// Omitted stays omitted, which means on.
|
|
11739
|
+
...(patch.measurement.countKeyEvents ?? existing.measurement.countKeyEvents) !== void 0 ? { countKeyEvents: patch.measurement.countKeyEvents ?? existing.measurement.countKeyEvents } : {}
|
|
11736
11740
|
}
|
|
11737
11741
|
} : {},
|
|
11738
11742
|
...patch.autoExtractBacklinks !== void 0 ? { autoExtractBacklinks: patch.autoExtractBacklinks } : {},
|
|
@@ -26627,6 +26631,7 @@ function readProjectConfigState(db, name, options = {}) {
|
|
|
26627
26631
|
"measurement.marketingHosts": project.measurement.marketingHosts,
|
|
26628
26632
|
"measurement.brandTerms": project.measurement.brandTerms,
|
|
26629
26633
|
"measurement.leadEventNames": project.measurement.leadEventNames,
|
|
26634
|
+
"measurement.countKeyEvents": countsKeyEvents(project.measurement),
|
|
26630
26635
|
locations: project.locations,
|
|
26631
26636
|
defaultLocation: project.defaultLocation,
|
|
26632
26637
|
autoExtractBacklinks: project.autoExtractBacklinks,
|
|
@@ -29830,7 +29835,7 @@ function literalPathPrefixCondition(path8, prefix) {
|
|
|
29830
29835
|
}
|
|
29831
29836
|
|
|
29832
29837
|
// ../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";
|
|
29838
|
+
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
29839
|
var UNKNOWN_LANDING_PAGE = "(not set)";
|
|
29835
29840
|
function addDays(date, offset) {
|
|
29836
29841
|
const value = /* @__PURE__ */ new Date(`${date}T00:00:00.000Z`);
|
|
@@ -30131,8 +30136,16 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
30131
30136
|
};
|
|
30132
30137
|
const acquisitionScope = scopedConditions(gaAcquisitionDaily.hostName, gaAcquisitionDaily.landingPageNormalized, gaAcquisitionDaily.landingPage);
|
|
30133
30138
|
const leadLandingScope = scopedConditions(gaLeadEventsDaily.hostName, gaLeadEventsDaily.landingPageNormalized, gaLeadEventsDaily.landingPage);
|
|
30139
|
+
const state = db.select().from(gaMeasurementSyncStates).where(eq52(gaMeasurementSyncStates.projectId, project.id)).get();
|
|
30140
|
+
const configuredLeadEvents = [...project.measurement.leadEventNames];
|
|
30141
|
+
const keyEventsEnabled = countsKeyEvents(project.measurement);
|
|
30142
|
+
const keyEventNames = keyEventsEnabled ? state?.keyEventNames ?? null : null;
|
|
30143
|
+
const countedEventNames = countedLeadEventNames(configuredLeadEvents, keyEventNames ?? []);
|
|
30144
|
+
const measuredEventSet = new Set(state?.leadEventNames ?? configuredLeadEvents);
|
|
30145
|
+
const reportedEventNames = countedEventNames.filter((name) => measuredEventSet.has(name));
|
|
30146
|
+
const leadEventCondition = reportedEventNames.length > 0 ? inArray28(gaLeadEventsDaily.eventName, reportedEventNames) : null;
|
|
30134
30147
|
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(
|
|
30148
|
+
const leadAnchor = leadEventCondition === null ? null : db.select({ date: sql18`max(${gaLeadEventsDaily.date})` }).from(gaLeadEventsDaily).where(and44(eq52(gaLeadEventsDaily.projectId, project.id), leadEventCondition, or11(
|
|
30136
30149
|
eq52(gaLeadEventsDaily.attributionScope, "channel"),
|
|
30137
30150
|
and44(eq52(gaLeadEventsDaily.attributionScope, "landing-page"), ...leadLandingScope)
|
|
30138
30151
|
))).get()?.date ?? null;
|
|
@@ -30140,7 +30153,7 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
30140
30153
|
const gaPeriods = gaAnchor ? buildPeriods(gaAnchor, days) : [];
|
|
30141
30154
|
const gaStartDate = gaPeriods[0]?.startDate;
|
|
30142
30155
|
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() : [];
|
|
30156
|
+
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
30157
|
const engagementAnchor = db.select({ date: sql18`max(${gaDailyTotals.date})` }).from(gaDailyTotals).where(eq52(gaDailyTotals.projectId, project.id)).get()?.date ?? null;
|
|
30145
30158
|
const engagementPeriodWindow = engagementAnchor ? buildPeriods(engagementAnchor, days) : [];
|
|
30146
30159
|
const engagementStartDate = engagementPeriodWindow[0]?.startDate;
|
|
@@ -30164,7 +30177,6 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
30164
30177
|
const propertyRows = gscStartDate ? db.select().from(gscDailyTotals).where(and44(eq52(gscDailyTotals.projectId, project.id), gte12(gscDailyTotals.date, gscStartDate), lte11(gscDailyTotals.date, gscAnchor))).all() : [];
|
|
30165
30178
|
const queryRows2 = gscStartDate ? db.select().from(gscQueryDailyTotals).where(and44(eq52(gscQueryDailyTotals.projectId, project.id), gte12(gscQueryDailyTotals.date, gscStartDate), lte11(gscQueryDailyTotals.date, gscAnchor))).all() : [];
|
|
30166
30179
|
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
30180
|
const acquisition = acquisitionRows.filter((row) => {
|
|
30169
30181
|
const landingPage = normalizeLandingPage(row.landingPageNormalized ?? row.landingPage);
|
|
30170
30182
|
return hostIsIncluded(row.hostName) && pageIsIncluded(landingPage);
|
|
@@ -30211,6 +30223,19 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
30211
30223
|
(row) => row.channelGroup,
|
|
30212
30224
|
(row) => row.eventCount
|
|
30213
30225
|
);
|
|
30226
|
+
const leadEvents = aggregateByKey(
|
|
30227
|
+
leads,
|
|
30228
|
+
gaPeriods,
|
|
30229
|
+
(row) => row.eventName,
|
|
30230
|
+
(row) => row.eventCount
|
|
30231
|
+
);
|
|
30232
|
+
for (const eventName of reportedEventNames) {
|
|
30233
|
+
if (!leadEvents.has(eventName)) leadEvents.set(eventName, gaPeriods.map(() => 0));
|
|
30234
|
+
}
|
|
30235
|
+
const unmeasuredEventNames = countedEventNames.filter((name) => !measuredEventSet.has(name));
|
|
30236
|
+
const configuredEventSet = new Set(configuredLeadEvents);
|
|
30237
|
+
const keyEventSet = new Set(keyEventNames ?? []);
|
|
30238
|
+
const eventOrigin = (eventName) => configuredEventSet.has(eventName) && keyEventSet.has(eventName) ? "both" : keyEventSet.has(eventName) ? "key-event" : "configured";
|
|
30214
30239
|
const filtersNarrowSessions = parsedHostScope.data === "marketing" || pathPrefix !== null && pathPrefix !== "/";
|
|
30215
30240
|
const hasAiEngineLeadData = gaAnchor !== null && hasLeadTimeline;
|
|
30216
30241
|
const aiEngineRows = attributeAiEngineRows({
|
|
@@ -30338,7 +30363,27 @@ function buildGaMeasurementAnalysis(db, projectName, options = {}) {
|
|
|
30338
30363
|
channelGroup,
|
|
30339
30364
|
periods: eventPeriods(gaPeriods, values)
|
|
30340
30365
|
})),
|
|
30341
|
-
aiEngines: aiEngineLeads
|
|
30366
|
+
aiEngines: aiEngineLeads,
|
|
30367
|
+
countedEvents: {
|
|
30368
|
+
configured: configuredLeadEvents,
|
|
30369
|
+
keyEventsEnabled,
|
|
30370
|
+
keyEvents: keyEventNames,
|
|
30371
|
+
keyEventsError: keyEventsEnabled ? state?.keyEventsError ?? null : null
|
|
30372
|
+
},
|
|
30373
|
+
events: [
|
|
30374
|
+
...gaAnchor && hasLeadTimeline ? rankEntries(leadEvents).map(([eventName, values]) => ({
|
|
30375
|
+
eventName,
|
|
30376
|
+
origin: eventOrigin(eventName),
|
|
30377
|
+
measured: true,
|
|
30378
|
+
periods: eventPeriods(gaPeriods, values)
|
|
30379
|
+
})) : [],
|
|
30380
|
+
...unmeasuredEventNames.map((eventName) => ({
|
|
30381
|
+
eventName,
|
|
30382
|
+
origin: eventOrigin(eventName),
|
|
30383
|
+
measured: false,
|
|
30384
|
+
periods: []
|
|
30385
|
+
}))
|
|
30386
|
+
]
|
|
30342
30387
|
},
|
|
30343
30388
|
engagement: {
|
|
30344
30389
|
status: engagementAnchor === null ? "unavailable" : "ready",
|
|
@@ -30921,7 +30966,7 @@ async function organicEvidenceRoutes(app) {
|
|
|
30921
30966
|
}
|
|
30922
30967
|
|
|
30923
30968
|
// ../api-routes/src/citations.ts
|
|
30924
|
-
import { and as and46, eq as eq54, inArray as
|
|
30969
|
+
import { and as and46, eq as eq54, inArray as inArray29 } from "drizzle-orm";
|
|
30925
30970
|
async function citationRoutes(app) {
|
|
30926
30971
|
app.get("/projects/:name/citations/visibility", async (request, reply) => {
|
|
30927
30972
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -30945,7 +30990,7 @@ async function citationRoutes(app) {
|
|
|
30945
30990
|
competitorOverlap: querySnapshots.competitorOverlap,
|
|
30946
30991
|
answerMentioned: querySnapshots.answerMentioned,
|
|
30947
30992
|
createdAt: querySnapshots.createdAt
|
|
30948
|
-
}).from(querySnapshots).where(
|
|
30993
|
+
}).from(querySnapshots).where(inArray29(querySnapshots.runId, projectRuns.map((r) => r.id))).all();
|
|
30949
30994
|
if (rawSnapshots.length === 0) {
|
|
30950
30995
|
return reply.send(emptyCitationVisibility("no-runs-yet"));
|
|
30951
30996
|
}
|
|
@@ -31082,7 +31127,7 @@ function computeCitationVisibility(input) {
|
|
|
31082
31127
|
}
|
|
31083
31128
|
|
|
31084
31129
|
// ../api-routes/src/visibility-stats.ts
|
|
31085
|
-
import { and as and47, desc as desc26, eq as eq55, inArray as
|
|
31130
|
+
import { and as and47, desc as desc26, eq as eq55, inArray as inArray30 } from "drizzle-orm";
|
|
31086
31131
|
|
|
31087
31132
|
// ../api-routes/src/visibility-compare.ts
|
|
31088
31133
|
var VISIBILITY_COMPARE_MIN_RUNS = 5;
|
|
@@ -31569,7 +31614,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
31569
31614
|
citationState: querySnapshots.citationState,
|
|
31570
31615
|
answerMentioned: querySnapshots.answerMentioned,
|
|
31571
31616
|
createdAt: querySnapshots.createdAt
|
|
31572
|
-
}).from(querySnapshots).where(
|
|
31617
|
+
}).from(querySnapshots).where(inArray30(querySnapshots.runId, runIds)).all() : [];
|
|
31573
31618
|
const stats = computeVisibilityStats({ queries: projectQueries, snapshots, groupBy });
|
|
31574
31619
|
const queryAttribution = buildQueryAttribution(projectQueries);
|
|
31575
31620
|
let shareOfVoice;
|
|
@@ -31580,7 +31625,7 @@ async function visibilityStatsRoutes(app) {
|
|
|
31580
31625
|
queryText: querySnapshots.queryText,
|
|
31581
31626
|
answerMentioned: querySnapshots.answerMentioned,
|
|
31582
31627
|
answerText: querySnapshots.answerText
|
|
31583
|
-
}).from(querySnapshots).where(
|
|
31628
|
+
}).from(querySnapshots).where(inArray30(querySnapshots.runId, runIds)).all() : [];
|
|
31584
31629
|
const attributedSovSnapshots = sovSnapshots.filter((s) => resolveCurrentQuery(queryAttribution, s) !== void 0);
|
|
31585
31630
|
const advanced = activeMeasurementPlan(app.db, project.id)?.plan.schemaVersion === 2;
|
|
31586
31631
|
const queryClass = advanced || projectQueryClassifier(project) ? requestedQueryClass : "all";
|
|
@@ -31678,7 +31723,7 @@ function readVisibilityCompare(db, projectName, query) {
|
|
|
31678
31723
|
answerText: querySnapshots.answerText,
|
|
31679
31724
|
citedDomains: querySnapshots.citedDomains,
|
|
31680
31725
|
location: querySnapshots.location
|
|
31681
|
-
}).from(querySnapshots).where(
|
|
31726
|
+
}).from(querySnapshots).where(inArray30(querySnapshots.runId, runIds)).all() : [];
|
|
31682
31727
|
return {
|
|
31683
31728
|
runCount: runIds.length,
|
|
31684
31729
|
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 +31842,7 @@ function readVisibilityContinuity(db, projectName, months) {
|
|
|
31797
31842
|
const trackedQueries = db.select({ id: queries.id, query: queries.query }).from(queries).where(eq55(queries.projectId, project.id)).all();
|
|
31798
31843
|
const loadProjectMonth = (bounds) => {
|
|
31799
31844
|
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(
|
|
31845
|
+
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
31846
|
return { runCount: runIds.length, snapshots: rows.map(bare) };
|
|
31802
31847
|
};
|
|
31803
31848
|
const frames = [{ frame: "project", continuity: gate(trackedQueries, loadProjectMonth(fromBounds), loadProjectMonth(toBounds)) }];
|
|
@@ -32057,7 +32102,7 @@ async function resultsExportRoutes(app) {
|
|
|
32057
32102
|
}
|
|
32058
32103
|
|
|
32059
32104
|
// ../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
|
|
32105
|
+
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
32106
|
var TOP_INSIGHT_LIMIT = 5;
|
|
32062
32107
|
var SEARCH_HIT_HARD_LIMIT = 50;
|
|
32063
32108
|
var SEARCH_SNIPPET_RADIUS = 80;
|
|
@@ -32358,7 +32403,7 @@ function loadSnapshotsByRunIds(app, runIds, queryIdByText) {
|
|
|
32358
32403
|
rawResponse: querySnapshots.rawResponse,
|
|
32359
32404
|
competitorOverlap: querySnapshots.competitorOverlap,
|
|
32360
32405
|
citedDomains: querySnapshots.citedDomains
|
|
32361
|
-
}).from(querySnapshots).where(
|
|
32406
|
+
}).from(querySnapshots).where(inArray31(querySnapshots.runId, [...runIds])).all();
|
|
32362
32407
|
for (const row of rows) {
|
|
32363
32408
|
const queryText = row.queryText?.trim() || null;
|
|
32364
32409
|
let queryId;
|
|
@@ -32798,7 +32843,7 @@ import crypto29 from "crypto";
|
|
|
32798
32843
|
import { and as and51, desc as desc29, eq as eq59 } from "drizzle-orm";
|
|
32799
32844
|
|
|
32800
32845
|
// ../api-routes/src/content-data.ts
|
|
32801
|
-
import { and as and50, eq as eq58, desc as desc28, gte as gte15, inArray as
|
|
32846
|
+
import { and as and50, eq as eq58, desc as desc28, gte as gte15, inArray as inArray32, lte as lte14 } from "drizzle-orm";
|
|
32802
32847
|
var RECENT_RUNS_WINDOW = 5;
|
|
32803
32848
|
function loadOrchestratorInput(db, project, locationFilter = void 0, gscWindowDays = DEFAULT_CONTENT_GSC_WINDOW_DAYS) {
|
|
32804
32849
|
const projectId = project.id;
|
|
@@ -32938,7 +32983,7 @@ function listRecentAnswerVisibilityRunIds(db, projectId, limit, locationFilter)
|
|
|
32938
32983
|
// Queued/running/failed/cancelled runs may have partial or no
|
|
32939
32984
|
// snapshots; including them risks pointing latestRunId at a run with
|
|
32940
32985
|
// no usable evidence.
|
|
32941
|
-
|
|
32986
|
+
inArray32(runs.status, [RunStatuses.completed, RunStatuses.partial]),
|
|
32942
32987
|
// Probe runs are operator/agent test runs; they must not poison the
|
|
32943
32988
|
// recent-runs window the content engine uses to recommend actions.
|
|
32944
32989
|
notProbeRun()
|
|
@@ -33006,7 +33051,7 @@ function buildCandidateQueries(opts) {
|
|
|
33006
33051
|
const queryRows2 = opts.db.select({ id: queries.id, text: queries.query }).from(queries).where(eq58(queries.projectId, opts.projectId)).all();
|
|
33007
33052
|
const queryIdByText = new Map(queryRows2.map((r) => [r.text, r.id]));
|
|
33008
33053
|
const candidateQueryIds = opts.candidateQueryStrings.map((q) => queryIdByText.get(q)).filter((id) => Boolean(id));
|
|
33009
|
-
const snapshotRows = filterTrackedSnapshots(opts.db.select().from(querySnapshots).where(
|
|
33054
|
+
const snapshotRows = filterTrackedSnapshots(opts.db.select().from(querySnapshots).where(inArray32(querySnapshots.runId, opts.recentRunIds)).all()).filter((r) => candidateQueryIds.includes(r.queryId));
|
|
33010
33055
|
const snapshotsByQuery = /* @__PURE__ */ new Map();
|
|
33011
33056
|
for (const row of snapshotRows) {
|
|
33012
33057
|
const list = snapshotsByQuery.get(row.queryId) ?? [];
|
|
@@ -45064,7 +45109,7 @@ async function gbpLocalPostsRoutes(app, options) {
|
|
|
45064
45109
|
}
|
|
45065
45110
|
|
|
45066
45111
|
// ../api-routes/src/google.ts
|
|
45067
|
-
import { eq as eq66, and as and54, desc as desc31, sql as sql21, inArray as
|
|
45112
|
+
import { eq as eq66, and as and54, desc as desc31, sql as sql21, inArray as inArray33 } from "drizzle-orm";
|
|
45068
45113
|
|
|
45069
45114
|
// ../api-routes/src/gsc-period-comparison.ts
|
|
45070
45115
|
var DAY_MS2 = 864e5;
|
|
@@ -45937,39 +45982,7 @@ async function listProperties(accessToken) {
|
|
|
45937
45982
|
headers: { "Authorization": `Bearer ${accessToken}` },
|
|
45938
45983
|
signal: AbortSignal.timeout(GA4_REQUEST_TIMEOUT_MS)
|
|
45939
45984
|
});
|
|
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
|
-
}
|
|
45985
|
+
if (!res.ok) throw await adminApiError(res, accessToken, "admin.account-summaries-failed", "Failed to list GA4 properties.");
|
|
45973
45986
|
return await res.json();
|
|
45974
45987
|
}, "GA4 accountSummaries"));
|
|
45975
45988
|
for (const account of body.accountSummaries ?? []) {
|
|
@@ -45987,6 +46000,53 @@ async function listProperties(accessToken) {
|
|
|
45987
46000
|
} while (pageToken);
|
|
45988
46001
|
return properties;
|
|
45989
46002
|
}
|
|
46003
|
+
async function adminApiError(res, accessToken, logAction, message) {
|
|
46004
|
+
const raw = await res.text().catch(() => "");
|
|
46005
|
+
let detail = "";
|
|
46006
|
+
let quotaReason = false;
|
|
46007
|
+
try {
|
|
46008
|
+
const parsed = JSON.parse(raw);
|
|
46009
|
+
if (parsed.error?.status === "SERVICE_DISABLED") {
|
|
46010
|
+
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";
|
|
46011
|
+
} else if (parsed.error?.message) {
|
|
46012
|
+
detail = ` ${parsed.error.message}`;
|
|
46013
|
+
}
|
|
46014
|
+
quotaReason = (parsed.error?.errors ?? []).some(
|
|
46015
|
+
(e) => e.reason === "rateLimitExceeded" || e.reason === "quotaExceeded" || e.reason === "userRateLimitExceeded"
|
|
46016
|
+
) || parsed.error?.status === "RESOURCE_EXHAUSTED";
|
|
46017
|
+
} catch {
|
|
46018
|
+
if (raw.length < 200) detail = ` ${raw}`;
|
|
46019
|
+
}
|
|
46020
|
+
const sanitized = detail.replace(new RegExp(escapeRegExp(accessToken), "g"), "***");
|
|
46021
|
+
const retryAfterSeconds2 = res.status === 429 || res.status >= 500 || res.status === 403 && quotaReason ? parseRetryAfter(res.headers.get("retry-after")) : void 0;
|
|
46022
|
+
ga4Log("error", logAction, { httpStatus: res.status, retryAfterSeconds: retryAfterSeconds2, quotaReason });
|
|
46023
|
+
return new GA4ApiError(`${message}${sanitized}`, res.status === 403 && quotaReason ? 429 : res.status, retryAfterSeconds2);
|
|
46024
|
+
}
|
|
46025
|
+
async function fetchKeyEventNames(accessToken, propertyId) {
|
|
46026
|
+
validateAccessToken2(accessToken);
|
|
46027
|
+
validatePropertyId(propertyId);
|
|
46028
|
+
const names = /* @__PURE__ */ new Set();
|
|
46029
|
+
let pageToken;
|
|
46030
|
+
do {
|
|
46031
|
+
const url = new URL(`${GA4_ADMIN_API_BASE}/properties/${propertyId}/keyEvents`);
|
|
46032
|
+
url.searchParams.set("pageSize", "200");
|
|
46033
|
+
if (pageToken) url.searchParams.set("pageToken", pageToken);
|
|
46034
|
+
const body = await withGa4Limit(() => withGa4Retry(async () => {
|
|
46035
|
+
const res = await fetchWithContext(url, {
|
|
46036
|
+
headers: { "Authorization": `Bearer ${accessToken}` },
|
|
46037
|
+
signal: AbortSignal.timeout(GA4_REQUEST_TIMEOUT_MS)
|
|
46038
|
+
});
|
|
46039
|
+
if (!res.ok) throw await adminApiError(res, accessToken, "admin.key-events-failed", "Failed to list GA4 key events.");
|
|
46040
|
+
return await res.json();
|
|
46041
|
+
}, "GA4 keyEvents"));
|
|
46042
|
+
for (const keyEvent of body.keyEvents ?? []) {
|
|
46043
|
+
const name = keyEvent.eventName?.trim();
|
|
46044
|
+
if (name) names.add(name);
|
|
46045
|
+
}
|
|
46046
|
+
pageToken = body.nextPageToken;
|
|
46047
|
+
} while (pageToken);
|
|
46048
|
+
return [...names].sort();
|
|
46049
|
+
}
|
|
45990
46050
|
async function fetchAggregateSummary(accessToken, propertyId, days) {
|
|
45991
46051
|
validateAccessToken2(accessToken);
|
|
45992
46052
|
validatePropertyId(propertyId);
|
|
@@ -48304,10 +48364,10 @@ async function googleRoutes(app, opts) {
|
|
|
48304
48364
|
locationProfiles: []
|
|
48305
48365
|
});
|
|
48306
48366
|
}
|
|
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),
|
|
48367
|
+
const metricRows = app.db.select().from(gbpDailyMetrics).where(and54(eq66(gbpDailyMetrics.projectId, project.id), inArray33(gbpDailyMetrics.locationName, locationNames))).all();
|
|
48368
|
+
const keywordRows = app.db.select().from(gbpKeywordImpressions).where(and54(eq66(gbpKeywordImpressions.projectId, project.id), inArray33(gbpKeywordImpressions.locationName, locationNames))).all();
|
|
48369
|
+
const placeActionRows = app.db.select().from(gbpPlaceActions).where(and54(eq66(gbpPlaceActions.projectId, project.id), inArray33(gbpPlaceActions.locationName, locationNames))).all();
|
|
48370
|
+
const lodgingRows = app.db.select().from(gbpLodgingSnapshots).where(and54(eq66(gbpLodgingSnapshots.projectId, project.id), inArray33(gbpLodgingSnapshots.locationName, locationNames))).orderBy(desc31(gbpLodgingSnapshots.syncedAt)).all();
|
|
48311
48371
|
const latestLodgingByLocation = /* @__PURE__ */ new Map();
|
|
48312
48372
|
for (const row of lodgingRows) {
|
|
48313
48373
|
if (!latestLodgingByLocation.has(row.locationName)) {
|
|
@@ -48321,7 +48381,7 @@ async function googleRoutes(app, opts) {
|
|
|
48321
48381
|
regularHours: gbpLocations.regularHours,
|
|
48322
48382
|
primaryPhone: gbpLocations.primaryPhone,
|
|
48323
48383
|
openStatus: gbpLocations.openStatus
|
|
48324
|
-
}).from(gbpLocations).where(and54(eq66(gbpLocations.projectId, project.id),
|
|
48384
|
+
}).from(gbpLocations).where(and54(eq66(gbpLocations.projectId, project.id), inArray33(gbpLocations.locationName, locationNames))).all();
|
|
48325
48385
|
return buildGbpSummary({
|
|
48326
48386
|
locationName,
|
|
48327
48387
|
locationCount: locationNames.length,
|
|
@@ -49991,7 +50051,7 @@ async function googleMarketingRoutes(app, opts) {
|
|
|
49991
50051
|
|
|
49992
50052
|
// ../api-routes/src/ads.ts
|
|
49993
50053
|
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
|
|
50054
|
+
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
50055
|
|
|
49996
50056
|
// ../api-routes/src/ads-activation.ts
|
|
49997
50057
|
import crypto40 from "crypto";
|
|
@@ -53089,7 +53149,7 @@ function semanticallyMatchesMaterializedEntity(app, input) {
|
|
|
53089
53149
|
eq69(adsOperations.projectId, input.projectId),
|
|
53090
53150
|
eq69(adsOperations.entityType, input.entityType),
|
|
53091
53151
|
eq69(adsOperations.entityId, input.entityId),
|
|
53092
|
-
|
|
53152
|
+
inArray34(adsOperations.kind, [createKind, updateKind])
|
|
53093
53153
|
)).orderBy(asc15(adsOperations.createdAt), asc15(adsOperations.id)).all();
|
|
53094
53154
|
if (rows.some((row) => row.state === AdsOperationStates.pending || row.state === AdsOperationStates.reconciling || row.state === AdsOperationStates.unknown || row.kind === updateKind && row.state === AdsOperationStates.succeeded)) {
|
|
53095
53155
|
return false;
|
|
@@ -53537,7 +53597,7 @@ function quarantineExhaustedReconciliation(app, row, now, policy, context) {
|
|
|
53537
53597
|
eq69(adsOperations.id, row.id),
|
|
53538
53598
|
eq69(adsOperations.projectId, row.projectId),
|
|
53539
53599
|
gte16(adsOperations.reconcileAttempts, policy.maxAttempts),
|
|
53540
|
-
|
|
53600
|
+
inArray34(adsOperations.state, [
|
|
53541
53601
|
AdsOperationStates.pending,
|
|
53542
53602
|
AdsOperationStates.unknown,
|
|
53543
53603
|
AdsOperationStates.reconciling
|
|
@@ -53781,7 +53841,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
53781
53841
|
eq69(adsOperations.reconcileStrategy, AdsReconcileStrategies.create_fingerprint),
|
|
53782
53842
|
or16(
|
|
53783
53843
|
isNotNull7(adsOperations.entityId),
|
|
53784
|
-
|
|
53844
|
+
inArray34(adsOperations.state, [
|
|
53785
53845
|
AdsOperationStates.pending,
|
|
53786
53846
|
AdsOperationStates.reconciling
|
|
53787
53847
|
])
|
|
@@ -53832,7 +53892,7 @@ async function sweepAdsOperationsOnce(app, opts, config) {
|
|
|
53832
53892
|
const eligibleProjectIds = [...credentialsByProjectId.keys()];
|
|
53833
53893
|
if (eligibleProjectIds.length === 0) return;
|
|
53834
53894
|
const rows = app.db.select().from(adsOperations).where(and57(
|
|
53835
|
-
|
|
53895
|
+
inArray34(adsOperations.projectId, eligibleProjectIds),
|
|
53836
53896
|
staleReconcileWhere
|
|
53837
53897
|
)).orderBy(asc15(adsOperations.updatedAt)).limit(config.batchSize).all();
|
|
53838
53898
|
for (const row of rows) {
|
|
@@ -54158,7 +54218,7 @@ async function adsRoutes(app, opts) {
|
|
|
54158
54218
|
const cursor = parsed.data.cursor ? decodeAdsOperationCursor(parsed.data.cursor, project.id, parsed.data.state) : void 0;
|
|
54159
54219
|
const rows = app.db.select().from(adsOperations).where(and57(
|
|
54160
54220
|
eq69(adsOperations.projectId, project.id),
|
|
54161
|
-
|
|
54221
|
+
inArray34(adsOperations.state, parsed.data.state),
|
|
54162
54222
|
cursor ? or16(
|
|
54163
54223
|
gt6(adsOperations.createdAt, cursor.createdAt),
|
|
54164
54224
|
and57(
|
|
@@ -54592,7 +54652,7 @@ async function adsRoutes(app, opts) {
|
|
|
54592
54652
|
const inFlight2 = app.db.select({ id: runs.id, status: runs.status }).from(runs).where(and57(
|
|
54593
54653
|
eq69(runs.projectId, project.id),
|
|
54594
54654
|
eq69(runs.kind, RunKinds["ads-sync"]),
|
|
54595
|
-
|
|
54655
|
+
inArray34(runs.status, [RunStatuses.queued, RunStatuses.running])
|
|
54596
54656
|
)).get();
|
|
54597
54657
|
if (inFlight2) {
|
|
54598
54658
|
const existing = { runId: inFlight2.id, status: inFlight2.status };
|
|
@@ -56623,6 +56683,7 @@ function persistLeadMeasurement(db, input) {
|
|
|
56623
56683
|
leadError: null,
|
|
56624
56684
|
leadSyncedAt: input.syncedAt,
|
|
56625
56685
|
leadAttributionScope: input.report.attributionScope,
|
|
56686
|
+
leadEventNames: input.eventNames,
|
|
56626
56687
|
updatedAt: input.syncedAt
|
|
56627
56688
|
}).onConflictDoUpdate({
|
|
56628
56689
|
target: gaMeasurementSyncStates.projectId,
|
|
@@ -56631,6 +56692,7 @@ function persistLeadMeasurement(db, input) {
|
|
|
56631
56692
|
leadError: null,
|
|
56632
56693
|
leadSyncedAt: input.syncedAt,
|
|
56633
56694
|
leadAttributionScope: input.report.attributionScope,
|
|
56695
|
+
leadEventNames: input.eventNames,
|
|
56634
56696
|
updatedAt: input.syncedAt
|
|
56635
56697
|
}
|
|
56636
56698
|
}).run();
|
|
@@ -56639,12 +56701,23 @@ function persistLeadMeasurement(db, input) {
|
|
|
56639
56701
|
function resetLeadMeasurement(db, projectId, updatedAt) {
|
|
56640
56702
|
db.transaction((tx) => {
|
|
56641
56703
|
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({
|
|
56704
|
+
tx.insert(gaMeasurementSyncStates).values({ projectId, leadStatus: "never-synced", leadError: null, leadSyncedAt: null, leadAttributionScope: null, leadEventNames: null, updatedAt }).onConflictDoUpdate({
|
|
56643
56705
|
target: gaMeasurementSyncStates.projectId,
|
|
56644
|
-
set: { leadStatus: "never-synced", leadError: null, leadSyncedAt: null, leadAttributionScope: null, updatedAt }
|
|
56706
|
+
set: { leadStatus: "never-synced", leadError: null, leadSyncedAt: null, leadAttributionScope: null, leadEventNames: null, updatedAt }
|
|
56645
56707
|
}).run();
|
|
56646
56708
|
});
|
|
56647
56709
|
}
|
|
56710
|
+
function persistKeyEventRead(db, projectId, read, updatedAt) {
|
|
56711
|
+
if (read.status === "disabled") return;
|
|
56712
|
+
const set = read.status === "read" ? { keyEventNames: read.names, keyEventsError: null, updatedAt } : { keyEventsError: read.error ?? "Key event read failed", updatedAt };
|
|
56713
|
+
db.insert(gaMeasurementSyncStates).values({ projectId, ...set }).onConflictDoUpdate({
|
|
56714
|
+
target: gaMeasurementSyncStates.projectId,
|
|
56715
|
+
set
|
|
56716
|
+
}).run();
|
|
56717
|
+
}
|
|
56718
|
+
function sameEventNames(left, right) {
|
|
56719
|
+
return left.length === right.length && left.every((name, index) => name === right[index]);
|
|
56720
|
+
}
|
|
56648
56721
|
function persistMeasurementError(db, projectId, component, message, updatedAt) {
|
|
56649
56722
|
if (component === "acquisition") {
|
|
56650
56723
|
db.insert(gaMeasurementSyncStates).values({
|
|
@@ -56994,8 +57067,9 @@ async function ga4Routes(app, opts) {
|
|
|
56994
57067
|
const syncSearchLanding = !only || only === "search-landing";
|
|
56995
57068
|
const measurementState = app.db.select().from(gaMeasurementSyncStates).where(eq73(gaMeasurementSyncStates.projectId, project.id)).get();
|
|
56996
57069
|
const acquisitionDays = measurementState?.acquisitionSyncedAt != null ? days : GA4_MAX_SYNC_DAYS;
|
|
56997
|
-
|
|
56998
|
-
|
|
57070
|
+
let leadDays = GA4_MAX_SYNC_DAYS;
|
|
57071
|
+
let leadEventNames = [];
|
|
57072
|
+
let keyEventRead = { status: "disabled", names: [] };
|
|
56999
57073
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
57000
57074
|
const runId = crypto47.randomUUID();
|
|
57001
57075
|
app.db.insert(runs).values({
|
|
@@ -57013,6 +57087,18 @@ async function ga4Routes(app, opts) {
|
|
|
57013
57087
|
try {
|
|
57014
57088
|
const { accessToken, propertyId } = await resolveGa4AccessToken(opts, project.name, project.canonicalDomain);
|
|
57015
57089
|
credentialsResolved = true;
|
|
57090
|
+
if (countsKeyEvents(project.measurement)) {
|
|
57091
|
+
try {
|
|
57092
|
+
keyEventRead = { status: "read", names: await fetchKeyEventNames(accessToken, propertyId) };
|
|
57093
|
+
} catch (error) {
|
|
57094
|
+
keyEventRead = { status: "error", names: measurementState?.keyEventNames ?? [], error: describeError(error) };
|
|
57095
|
+
}
|
|
57096
|
+
persistKeyEventRead(app.db, project.id, keyEventRead, (/* @__PURE__ */ new Date()).toISOString());
|
|
57097
|
+
}
|
|
57098
|
+
leadEventNames = countedLeadEventNames(project.measurement.leadEventNames, keyEventRead.names);
|
|
57099
|
+
const previousLeadEvents = measurementState?.leadEventNames ?? null;
|
|
57100
|
+
const leadEventsChanged = previousLeadEvents === null || !sameEventNames(previousLeadEvents, leadEventNames);
|
|
57101
|
+
leadDays = measurementState?.leadSyncedAt != null && !leadEventsChanged ? days : GA4_MAX_SYNC_DAYS;
|
|
57016
57102
|
let rows = [];
|
|
57017
57103
|
let aiReferrals = [];
|
|
57018
57104
|
let socialReferrals = [];
|
|
@@ -57276,13 +57362,16 @@ async function ga4Routes(app, opts) {
|
|
|
57276
57362
|
projectId: project.id,
|
|
57277
57363
|
runId,
|
|
57278
57364
|
syncedAt: measurementNow,
|
|
57279
|
-
report: leadsSettled.value
|
|
57365
|
+
report: leadsSettled.value,
|
|
57366
|
+
eventNames: leadEventNames
|
|
57280
57367
|
});
|
|
57281
57368
|
return {
|
|
57282
57369
|
status: "ready",
|
|
57283
57370
|
days: leadDays,
|
|
57284
57371
|
rowCount: leadsSettled.value.rows.length,
|
|
57285
|
-
attributionScope: leadsSettled.value.attributionScope
|
|
57372
|
+
attributionScope: leadsSettled.value.attributionScope,
|
|
57373
|
+
eventNames: leadEventNames,
|
|
57374
|
+
keyEvents: keyEventRead
|
|
57286
57375
|
};
|
|
57287
57376
|
} catch (error) {
|
|
57288
57377
|
return recordMeasurementFailure("leads", error);
|
|
@@ -60441,7 +60530,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
60441
60530
|
import crypto52 from "crypto";
|
|
60442
60531
|
import { isIP } from "net";
|
|
60443
60532
|
import { isDeepStrictEqual } from "util";
|
|
60444
|
-
import { and as and69, desc as desc39, eq as eq80, gt as gt7, gte as gte19, inArray as
|
|
60533
|
+
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
60534
|
|
|
60446
60535
|
// ../api-routes/src/traffic-limits.ts
|
|
60447
60536
|
var VERCEL_MAX_SYNC_WINDOW_MS = 24 * 60 * 6e4;
|
|
@@ -62187,6 +62276,9 @@ var CLOUDFLARE_QUEUE_RETENTION_READ_TIMEOUT_MS = 1e4;
|
|
|
62187
62276
|
var CLOUDFLARE_QUEUE_VISIBILITY_TIMEOUT_MS = 5 * 6e4;
|
|
62188
62277
|
var CLOUDFLARE_QUEUE_SYNC_LEASE_TTL_MS = 5 * 6e4;
|
|
62189
62278
|
var WORDPRESS_SYNC_LEASE_TTL_MS = 5 * 6e4;
|
|
62279
|
+
var PULL_SYNC_LEASE_TTL_MS = 10 * 6e4;
|
|
62280
|
+
var TRAFFIC_BACKFILL_LEASE_TTL_MS = 5 * 6e4;
|
|
62281
|
+
var TRAFFIC_BACKFILL_LEASE_RENEW_MS = 6e4;
|
|
62190
62282
|
var DEFAULT_CLOUDFLARE_INGEST_RATE_LIMIT_MAX = 6e3;
|
|
62191
62283
|
var SHA256_HEX_PATTERN = /^[0-9a-f]{64}$/i;
|
|
62192
62284
|
function sha256Hex3(value) {
|
|
@@ -62533,6 +62625,9 @@ function isAuthoritativeTrafficSource(db, source) {
|
|
|
62533
62625
|
function trafficConnectStatus(tx, projectId, existingSource) {
|
|
62534
62626
|
return existingSource?.status === TrafficSourceStatuses.paused || hasConnectedTrafficSourceSibling(tx, projectId, existingSource?.id ?? "") ? TrafficSourceStatuses.paused : TrafficSourceStatuses.connected;
|
|
62535
62627
|
}
|
|
62628
|
+
function isSameBackfillSource(current, started, leaseOwner) {
|
|
62629
|
+
return current.syncLeaseOwner === leaseOwner && isSameTrafficSourceGeneration(current, started);
|
|
62630
|
+
}
|
|
62536
62631
|
function isSameTrafficSourceGeneration(current, started) {
|
|
62537
62632
|
return isDeepStrictEqual(current.configJson, started.configJson) && current.updatedAt === started.updatedAt && current.lastSyncedAt === started.lastSyncedAt && current.lastCursor === started.lastCursor && current.wordpressPendingUntil === started.wordpressPendingUntil;
|
|
62538
62633
|
}
|
|
@@ -62586,6 +62681,42 @@ function vercelRetentionClampError(requestedStartMs, effectiveStartMs) {
|
|
|
62586
62681
|
return new VercelRetentionClampError(requestedStartMs, effectiveStartMs);
|
|
62587
62682
|
}
|
|
62588
62683
|
async function runBackfillTask(options) {
|
|
62684
|
+
const { app, sourceRow: sourceRow2, leaseOwner } = options;
|
|
62685
|
+
const stopped = new AbortController();
|
|
62686
|
+
const releaseLease = () => {
|
|
62687
|
+
try {
|
|
62688
|
+
releaseTrafficSyncLease({ db: app.db, sourceId: sourceRow2.id, owner: leaseOwner, now: (/* @__PURE__ */ new Date()).toISOString() });
|
|
62689
|
+
} catch {
|
|
62690
|
+
}
|
|
62691
|
+
};
|
|
62692
|
+
const renewLease2 = setInterval(() => {
|
|
62693
|
+
try {
|
|
62694
|
+
const latest = app.db.select().from(trafficSources).where(eq80(trafficSources.id, sourceRow2.id)).get();
|
|
62695
|
+
if (!latest || !isAuthoritativeTrafficSource(app.db, latest) || !isSameTrafficSourceGeneration(latest, sourceRow2)) {
|
|
62696
|
+
clearInterval(renewLease2);
|
|
62697
|
+
stopped.abort();
|
|
62698
|
+
releaseLease();
|
|
62699
|
+
return;
|
|
62700
|
+
}
|
|
62701
|
+
tryClaimTrafficSyncLease({
|
|
62702
|
+
db: app.db,
|
|
62703
|
+
sourceId: sourceRow2.id,
|
|
62704
|
+
owner: leaseOwner,
|
|
62705
|
+
now: (/* @__PURE__ */ new Date()).toISOString(),
|
|
62706
|
+
ttlMs: TRAFFIC_BACKFILL_LEASE_TTL_MS
|
|
62707
|
+
});
|
|
62708
|
+
} catch {
|
|
62709
|
+
}
|
|
62710
|
+
}, options.leaseRenewMs);
|
|
62711
|
+
renewLease2.unref?.();
|
|
62712
|
+
try {
|
|
62713
|
+
await runBackfillTaskHoldingLease(options, stopped.signal);
|
|
62714
|
+
} finally {
|
|
62715
|
+
clearInterval(renewLease2);
|
|
62716
|
+
releaseLease();
|
|
62717
|
+
}
|
|
62718
|
+
}
|
|
62719
|
+
async function runBackfillTaskHoldingLease(options, signal) {
|
|
62589
62720
|
const {
|
|
62590
62721
|
app,
|
|
62591
62722
|
runId,
|
|
@@ -62595,7 +62726,8 @@ async function runBackfillTask(options) {
|
|
|
62595
62726
|
windowEnd,
|
|
62596
62727
|
journeyKeySecret,
|
|
62597
62728
|
pullForBackfill,
|
|
62598
|
-
pullErrorPrefix
|
|
62729
|
+
pullErrorPrefix,
|
|
62730
|
+
leaseOwner
|
|
62599
62731
|
} = options;
|
|
62600
62732
|
const backfillStartedAt = Date.now();
|
|
62601
62733
|
const target = { feature: "server_traffic", operation: "backfill", attribution: currentOutcomeAttribution() };
|
|
@@ -62609,7 +62741,7 @@ async function runBackfillTask(options) {
|
|
|
62609
62741
|
app.db.transaction((tx) => {
|
|
62610
62742
|
tx.update(runs).set({ status: RunStatuses.failed, error: msg, finishedAt: failedAt }).where(eq80(runs.id, runId)).run();
|
|
62611
62743
|
const latestSource = tx.select().from(trafficSources).where(eq80(trafficSources.id, sourceRow2.id)).get();
|
|
62612
|
-
if (!preserveSourceState && latestSource && isAuthoritativeTrafficSource(tx, latestSource) &&
|
|
62744
|
+
if (!preserveSourceState && latestSource && isAuthoritativeTrafficSource(tx, latestSource) && isSameBackfillSource(latestSource, sourceRow2, leaseOwner)) {
|
|
62613
62745
|
tx.update(trafficSources).set({ status: TrafficSourceStatuses.error, lastError: msg, updatedAt: failedAt }).where(eq80(trafficSources.id, sourceRow2.id)).run();
|
|
62614
62746
|
}
|
|
62615
62747
|
});
|
|
@@ -62623,8 +62755,13 @@ async function runBackfillTask(options) {
|
|
|
62623
62755
|
}
|
|
62624
62756
|
let allEvents;
|
|
62625
62757
|
try {
|
|
62626
|
-
allEvents = await pullForBackfill();
|
|
62758
|
+
allEvents = await pullForBackfill(signal);
|
|
62627
62759
|
} catch (e) {
|
|
62760
|
+
if (signal.aborted) {
|
|
62761
|
+
markFailed("Backfill stopped: the traffic source was reset, reconnected or deactivated while it ran", true);
|
|
62762
|
+
reportBackfill({ status: OutcomeStatuses.failed, reasonCode: OutcomeReasonCodes.NOT_CONNECTED });
|
|
62763
|
+
return;
|
|
62764
|
+
}
|
|
62628
62765
|
markFailed(
|
|
62629
62766
|
`${pullErrorPrefix}: ${describeError(e)}`,
|
|
62630
62767
|
e instanceof VercelRetentionClampError
|
|
@@ -62638,7 +62775,7 @@ async function runBackfillTask(options) {
|
|
|
62638
62775
|
try {
|
|
62639
62776
|
const completed = app.db.transaction((tx) => {
|
|
62640
62777
|
const latestSource = tx.select().from(trafficSources).where(eq80(trafficSources.id, sourceRow2.id)).get();
|
|
62641
|
-
const stillAuthoritative = latestSource && isAuthoritativeTrafficSource(tx, latestSource) &&
|
|
62778
|
+
const stillAuthoritative = latestSource && isAuthoritativeTrafficSource(tx, latestSource) && isSameBackfillSource(latestSource, sourceRow2, leaseOwner);
|
|
62642
62779
|
if (stillAuthoritative) {
|
|
62643
62780
|
enforceRawEventSampleRetention(tx, sourceRow2.id, finishedAt2);
|
|
62644
62781
|
}
|
|
@@ -62681,7 +62818,7 @@ async function runBackfillTask(options) {
|
|
|
62681
62818
|
}).where(eq80(runs.id, runId)).run();
|
|
62682
62819
|
return "wordpress-backfill-unsupported";
|
|
62683
62820
|
}
|
|
62684
|
-
if (!latestSource || !isAuthoritativeTrafficSource(tx, latestSource) || !
|
|
62821
|
+
if (!latestSource || !isAuthoritativeTrafficSource(tx, latestSource) || !isSameBackfillSource(latestSource, sourceRow2, leaseOwner)) {
|
|
62685
62822
|
tx.update(runs).set({
|
|
62686
62823
|
status: RunStatuses.failed,
|
|
62687
62824
|
error: "Traffic source was deactivated or reconfigured during backfill",
|
|
@@ -64205,15 +64342,19 @@ async function trafficRoutes(app, opts) {
|
|
|
64205
64342
|
if (sourceRow2.status === TrafficSourceStatuses.paused || sourceRow2.status === TrafficSourceStatuses.archived || hasConnectedSibling) {
|
|
64206
64343
|
throw validationError("Traffic source must be active before it can sync");
|
|
64207
64344
|
}
|
|
64208
|
-
const
|
|
64209
|
-
|
|
64345
|
+
const isWordpressSource = sourceRow2.sourceType === TrafficSourceTypes.wordpress;
|
|
64346
|
+
const syncLeaseOwner = crypto52.randomUUID();
|
|
64347
|
+
if (!tryClaimTrafficSyncLease({
|
|
64210
64348
|
db: app.db,
|
|
64211
64349
|
sourceId: sourceRow2.id,
|
|
64212
|
-
owner:
|
|
64350
|
+
owner: syncLeaseOwner,
|
|
64213
64351
|
now: (/* @__PURE__ */ new Date()).toISOString(),
|
|
64214
|
-
ttlMs: WORDPRESS_SYNC_LEASE_TTL_MS
|
|
64352
|
+
ttlMs: isWordpressSource ? WORDPRESS_SYNC_LEASE_TTL_MS : PULL_SYNC_LEASE_TTL_MS
|
|
64215
64353
|
})) {
|
|
64216
|
-
throw operationInProgress(
|
|
64354
|
+
throw operationInProgress(
|
|
64355
|
+
isWordpressSource ? "WordPress source sync is already in progress" : "A sync or backfill is already running for this traffic source",
|
|
64356
|
+
{ sourceId: sourceRow2.id }
|
|
64357
|
+
);
|
|
64217
64358
|
}
|
|
64218
64359
|
try {
|
|
64219
64360
|
const syncWindowEnd = /* @__PURE__ */ new Date();
|
|
@@ -64236,7 +64377,7 @@ async function trafficRoutes(app, opts) {
|
|
|
64236
64377
|
app.db.transaction((tx) => {
|
|
64237
64378
|
tx.update(runs).set({ status: RunStatuses.failed, error: msg, finishedAt: failedAt }).where(eq80(runs.id, runId)).run();
|
|
64238
64379
|
const latestSource = tx.select().from(trafficSources).where(eq80(trafficSources.id, sourceRow2.id)).get();
|
|
64239
|
-
if (latestSource?.status === TrafficSourceStatuses.connected && isSameTrafficSourceGeneration(latestSource, sourceRow2) &&
|
|
64380
|
+
if (latestSource?.status === TrafficSourceStatuses.connected && isSameTrafficSourceGeneration(latestSource, sourceRow2) && latestSource.syncLeaseOwner === syncLeaseOwner) {
|
|
64240
64381
|
tx.update(trafficSources).set({ status: TrafficSourceStatuses.error, lastError: msg, updatedAt: failedAt }).where(eq80(trafficSources.id, sourceRow2.id)).run();
|
|
64241
64382
|
}
|
|
64242
64383
|
});
|
|
@@ -64257,11 +64398,11 @@ async function trafficRoutes(app, opts) {
|
|
|
64257
64398
|
}
|
|
64258
64399
|
};
|
|
64259
64400
|
const renewWordpressLease = () => {
|
|
64260
|
-
if (!
|
|
64401
|
+
if (!isWordpressSource) return;
|
|
64261
64402
|
if (!tryClaimTrafficSyncLease({
|
|
64262
64403
|
db: app.db,
|
|
64263
64404
|
sourceId: sourceRow2.id,
|
|
64264
|
-
owner:
|
|
64405
|
+
owner: syncLeaseOwner,
|
|
64265
64406
|
now: (/* @__PURE__ */ new Date()).toISOString(),
|
|
64266
64407
|
ttlMs: WORDPRESS_SYNC_LEASE_TTL_MS
|
|
64267
64408
|
})) {
|
|
@@ -64366,7 +64507,7 @@ async function trafficRoutes(app, opts) {
|
|
|
64366
64507
|
const reservedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
64367
64508
|
const reservedSource = app.db.transaction((tx) => {
|
|
64368
64509
|
const latestSource = tx.select().from(trafficSources).where(eq80(trafficSources.id, sourceRow2.id)).get();
|
|
64369
|
-
if (!latestSource || !isAuthoritativeTrafficSource(tx, latestSource) || !isSameTrafficSourceGeneration(latestSource, sourceRow2) || latestSource.syncLeaseOwner !==
|
|
64510
|
+
if (!latestSource || !isAuthoritativeTrafficSource(tx, latestSource) || !isSameTrafficSourceGeneration(latestSource, sourceRow2) || latestSource.syncLeaseOwner !== syncLeaseOwner || latestSource.lastCursor || latestSource.wordpressPendingUntil) return void 0;
|
|
64370
64511
|
tx.update(trafficSources).set({
|
|
64371
64512
|
lastSyncedAt: windowStartIso2,
|
|
64372
64513
|
wordpressPendingUntil: windowEndIso2,
|
|
@@ -64550,7 +64691,7 @@ async function trafficRoutes(app, opts) {
|
|
|
64550
64691
|
const commitOutcome = app.db.transaction((tx) => {
|
|
64551
64692
|
const latestRow = tx.select().from(trafficSources).where(eq80(trafficSources.id, sourceRow2.id)).get();
|
|
64552
64693
|
const latestHasConnectedSibling = tx.select().from(trafficSources).where(eq80(trafficSources.projectId, project.id)).all().some((row) => row.id !== sourceRow2.id && row.status === TrafficSourceStatuses.connected);
|
|
64553
|
-
if (!latestRow || latestRow.status !== TrafficSourceStatuses.connected && latestRow.status !== TrafficSourceStatuses.error || latestHasConnectedSibling ||
|
|
64694
|
+
if (!latestRow || latestRow.status !== TrafficSourceStatuses.connected && latestRow.status !== TrafficSourceStatuses.error || latestHasConnectedSibling || latestRow.syncLeaseOwner !== syncLeaseOwner || !isSameTrafficSourceGeneration(latestRow, sourceRow2)) {
|
|
64554
64695
|
const abortedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
64555
64696
|
tx.update(runs).set({
|
|
64556
64697
|
status: RunStatuses.failed,
|
|
@@ -64880,17 +65021,15 @@ async function trafficRoutes(app, opts) {
|
|
|
64880
65021
|
};
|
|
64881
65022
|
return response;
|
|
64882
65023
|
} finally {
|
|
64883
|
-
|
|
64884
|
-
|
|
64885
|
-
|
|
64886
|
-
|
|
64887
|
-
|
|
64888
|
-
|
|
64889
|
-
|
|
64890
|
-
|
|
64891
|
-
|
|
64892
|
-
request.log.warn({ sourceId: sourceRow2.id, error: describeError(error) }, "Failed to release WordPress sync lease");
|
|
64893
|
-
}
|
|
65024
|
+
try {
|
|
65025
|
+
releaseTrafficSyncLease({
|
|
65026
|
+
db: app.db,
|
|
65027
|
+
sourceId: sourceRow2.id,
|
|
65028
|
+
owner: syncLeaseOwner,
|
|
65029
|
+
now: (/* @__PURE__ */ new Date()).toISOString()
|
|
65030
|
+
});
|
|
65031
|
+
} catch (error) {
|
|
65032
|
+
request.log.warn({ sourceId: sourceRow2.id, error: describeError(error) }, "Failed to release traffic sync lease");
|
|
64894
65033
|
}
|
|
64895
65034
|
}
|
|
64896
65035
|
});
|
|
@@ -64976,11 +65115,12 @@ async function trafficRoutes(app, opts) {
|
|
|
64976
65115
|
const vercelTeamId = config.teamId ?? credential.teamId;
|
|
64977
65116
|
const vercelEnvironment = config.environment ?? credential.environment;
|
|
64978
65117
|
pullErrorPrefix = "Vercel pull failed";
|
|
64979
|
-
pullForBackfill = async () => {
|
|
65118
|
+
pullForBackfill = async (signal) => {
|
|
64980
65119
|
const collected = [];
|
|
64981
65120
|
const seenEventIds = /* @__PURE__ */ new Set();
|
|
64982
65121
|
const backfillEndMs = windowEnd.getTime();
|
|
64983
65122
|
for (let chunkStartMs = windowStart.getTime(); chunkStartMs < backfillEndMs; chunkStartMs += VERCEL_BACKFILL_CHUNK_MS) {
|
|
65123
|
+
signal.throwIfAborted();
|
|
64984
65124
|
const chunkEndMs = Math.min(chunkStartMs + VERCEL_BACKFILL_CHUNK_MS, backfillEndMs);
|
|
64985
65125
|
const drained = await drainVercelTrafficEvents({
|
|
64986
65126
|
pull: pullVercelEvents,
|
|
@@ -65008,25 +65148,42 @@ async function trafficRoutes(app, opts) {
|
|
|
65008
65148
|
}
|
|
65009
65149
|
const startedAt = windowEnd.toISOString();
|
|
65010
65150
|
const runId = crypto52.randomUUID();
|
|
65011
|
-
|
|
65012
|
-
|
|
65013
|
-
|
|
65014
|
-
|
|
65015
|
-
|
|
65016
|
-
|
|
65017
|
-
|
|
65018
|
-
|
|
65019
|
-
|
|
65020
|
-
|
|
65021
|
-
|
|
65022
|
-
|
|
65023
|
-
|
|
65024
|
-
|
|
65025
|
-
|
|
65026
|
-
|
|
65151
|
+
const leaseOwner = crypto52.randomUUID();
|
|
65152
|
+
if (!tryClaimTrafficSyncLease({
|
|
65153
|
+
db: app.db,
|
|
65154
|
+
sourceId: sourceRow2.id,
|
|
65155
|
+
owner: leaseOwner,
|
|
65156
|
+
now: (/* @__PURE__ */ new Date()).toISOString(),
|
|
65157
|
+
ttlMs: TRAFFIC_BACKFILL_LEASE_TTL_MS
|
|
65158
|
+
})) {
|
|
65159
|
+
throw operationInProgress("A sync or backfill is already running for this traffic source; retry when it finishes", { sourceId: sourceRow2.id });
|
|
65160
|
+
}
|
|
65161
|
+
try {
|
|
65162
|
+
app.db.transaction((tx) => {
|
|
65163
|
+
const latestSource = tx.select().from(trafficSources).where(eq80(trafficSources.id, sourceRow2.id)).get();
|
|
65164
|
+
if (!latestSource || !isAuthoritativeTrafficSource(tx, latestSource) || !isSameTrafficSourceGeneration(latestSource, sourceRow2)) {
|
|
65165
|
+
throw validationError("Traffic source must remain active and unchanged before it can backfill");
|
|
65166
|
+
}
|
|
65167
|
+
tx.insert(runs).values({
|
|
65168
|
+
id: runId,
|
|
65169
|
+
projectId: project.id,
|
|
65170
|
+
kind: RunKinds["traffic-sync"],
|
|
65171
|
+
status: RunStatuses.running,
|
|
65172
|
+
trigger: RunTriggers.backfill,
|
|
65173
|
+
sourceId: sourceRow2.id,
|
|
65174
|
+
startedAt,
|
|
65175
|
+
createdAt: startedAt
|
|
65176
|
+
}).run();
|
|
65177
|
+
});
|
|
65178
|
+
} catch (error) {
|
|
65179
|
+
releaseTrafficSyncLease({ db: app.db, sourceId: sourceRow2.id, owner: leaseOwner, now: (/* @__PURE__ */ new Date()).toISOString() });
|
|
65180
|
+
throw error;
|
|
65181
|
+
}
|
|
65027
65182
|
void runBackfillTask({
|
|
65028
65183
|
app,
|
|
65029
65184
|
runId,
|
|
65185
|
+
leaseOwner,
|
|
65186
|
+
leaseRenewMs: opts.trafficBackfillLeaseRenewMs ?? TRAFFIC_BACKFILL_LEASE_RENEW_MS,
|
|
65030
65187
|
project,
|
|
65031
65188
|
sourceRow: sourceRow2,
|
|
65032
65189
|
journeyKeySecret: opts.journeyKeySecret,
|
|
@@ -65322,7 +65479,7 @@ async function trafficRoutes(app, opts) {
|
|
|
65322
65479
|
const listed = useContentList ? contentPaths : infraPaths;
|
|
65323
65480
|
const IN_LIST_CAP = 2e4;
|
|
65324
65481
|
const listFitsInSql = listed.length <= IN_LIST_CAP;
|
|
65325
|
-
const contentExpr = listed.length === 0 ? useContentList ? sql30`0` : sql30`${crawlerEventsHourly.hits}` : useContentList ? sql30`CASE WHEN ${
|
|
65482
|
+
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`;
|
|
65326
65483
|
if (listFitsInSql) {
|
|
65327
65484
|
const crawlerSeries = app.db.select({
|
|
65328
65485
|
bucket: crawlerSeriesBucket,
|
|
@@ -65711,7 +65868,7 @@ var reportSweepsCheck = {
|
|
|
65711
65868
|
};
|
|
65712
65869
|
|
|
65713
65870
|
// ../api-routes/src/doctor/checks/report-models.ts
|
|
65714
|
-
import { and as and71, eq as eq82, gte as gte21, inArray as
|
|
65871
|
+
import { and as and71, eq as eq82, gte as gte21, inArray as inArray36, lte as lte22 } from "drizzle-orm";
|
|
65715
65872
|
var reportModelsCheck = {
|
|
65716
65873
|
id: "report.models",
|
|
65717
65874
|
category: CheckCategories.providers,
|
|
@@ -65726,7 +65883,7 @@ var reportModelsCheck = {
|
|
|
65726
65883
|
const months = reportMonths.flatMap((month) => {
|
|
65727
65884
|
const bounds = calendarMonthBounds(month);
|
|
65728
65885
|
const previous = new Date(Date.parse(bounds.since) - 1).toISOString().slice(0, 7);
|
|
65729
|
-
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"]),
|
|
65886
|
+
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();
|
|
65730
65887
|
return readVisibilityContinuity(ctx.db, ctx.project.name, { from: previous, to: month }).map(({ frame, continuity: continuity2 }) => ({
|
|
65731
65888
|
month,
|
|
65732
65889
|
previousMonth: previous,
|
|
@@ -66303,7 +66460,7 @@ var BACKLINKS_CHECKS = [
|
|
|
66303
66460
|
];
|
|
66304
66461
|
|
|
66305
66462
|
// ../api-routes/src/doctor/checks/bing-auth.ts
|
|
66306
|
-
import { and as and73, desc as desc40, eq as eq85, inArray as
|
|
66463
|
+
import { and as and73, desc as desc40, eq as eq85, inArray as inArray37 } from "drizzle-orm";
|
|
66307
66464
|
var BING_CONNECTION_ENTITY = "bing_connection";
|
|
66308
66465
|
var BING_CONNECTED_ACTION = "bing.connected";
|
|
66309
66466
|
var BING_DISCONNECTED_ACTION = "bing.disconnected";
|
|
@@ -66314,7 +66471,7 @@ function lostBingConnection(ctx, project) {
|
|
|
66314
66471
|
const lastChange = ctx.db.select({ action: auditLog.action }).from(auditLog).where(and73(
|
|
66315
66472
|
eq85(auditLog.entityType, BING_CONNECTION_ENTITY),
|
|
66316
66473
|
eq85(auditLog.entityId, project.canonicalDomain),
|
|
66317
|
-
|
|
66474
|
+
inArray37(auditLog.action, [BING_CONNECTED_ACTION, BING_DISCONNECTED_ACTION])
|
|
66318
66475
|
)).orderBy(desc40(auditLog.createdAt)).limit(1).get();
|
|
66319
66476
|
return lastChange?.action !== BING_DISCONNECTED_ACTION;
|
|
66320
66477
|
}
|
|
@@ -66860,7 +67017,7 @@ var ga4ConnectionCheck = {
|
|
|
66860
67017
|
var GA_AUTH_CHECKS = [ga4ConnectionCheck];
|
|
66861
67018
|
|
|
66862
67019
|
// ../api-routes/src/doctor/checks/data-freshness.ts
|
|
66863
|
-
import { and as and74, desc as desc41, eq as eq88, inArray as
|
|
67020
|
+
import { and as and74, desc as desc41, eq as eq88, inArray as inArray38 } from "drizzle-orm";
|
|
66864
67021
|
var GA_DATA_AGING_DAYS = 3;
|
|
66865
67022
|
var GA_DATA_STALE_DAYS = 5;
|
|
66866
67023
|
var GSC_DATA_AGING_DAYS = 5;
|
|
@@ -66889,7 +67046,7 @@ function skipped(code, summary3) {
|
|
|
66889
67046
|
return { status: CheckStatuses.skipped, code, summary: summary3, remediation: null };
|
|
66890
67047
|
}
|
|
66891
67048
|
function lastSyncAgeDays(ctx, kinds) {
|
|
66892
|
-
const row = ctx.db.select({ createdAt: runs.createdAt }).from(runs).where(and74(eq88(runs.projectId, ctx.project.id),
|
|
67049
|
+
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();
|
|
66893
67050
|
if (!row?.createdAt) return null;
|
|
66894
67051
|
const age = Math.floor((Date.now() - Date.parse(row.createdAt)) / DAY_MS4);
|
|
66895
67052
|
return Number.isFinite(age) ? age : null;
|
|
@@ -67384,7 +67541,7 @@ async function probeApiHost(host, options = {}) {
|
|
|
67384
67541
|
}
|
|
67385
67542
|
|
|
67386
67543
|
// ../api-routes/src/doctor/checks/integration-sync.ts
|
|
67387
|
-
import { and as and75, count as count7, desc as desc42, eq as eq89, gte as gte22, gt as gt8, inArray as
|
|
67544
|
+
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";
|
|
67388
67545
|
var SYNC_FAILURE_WINDOW = 3;
|
|
67389
67546
|
var SUMMARY_ERROR_LIMIT = 300;
|
|
67390
67547
|
var FINISHED_STATUSES = [RunStatuses.completed, RunStatuses.partial, RunStatuses.failed];
|
|
@@ -67477,8 +67634,8 @@ function readSyncRunState(db, projectId, kind, options = {}) {
|
|
|
67477
67634
|
...options.nothingToSyncErrors?.length ? [or19(isNull14(runs.error), notInArray3(runs.error, [...options.nothingToSyncErrors]))] : []
|
|
67478
67635
|
);
|
|
67479
67636
|
const graded = options.since ? and75(scope, gte22(runs.createdAt, options.since)) : scope;
|
|
67480
|
-
const recent = db.select({ id: runs.id, status: runs.status, trigger: runs.trigger, error: runs.error, createdAt: runs.createdAt }).from(runs).where(and75(graded,
|
|
67481
|
-
const lastSuccess = db.select({ createdAt: runs.createdAt, finishedAt: runs.finishedAt }).from(runs).where(and75(graded,
|
|
67637
|
+
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();
|
|
67638
|
+
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();
|
|
67482
67639
|
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();
|
|
67483
67640
|
const failuresSinceSuccess = Number(failureCount?.count ?? 0);
|
|
67484
67641
|
const latest = recent[0];
|
|
@@ -68039,7 +68196,7 @@ var PLACES_CHECK_BY_ID = Object.fromEntries(
|
|
|
68039
68196
|
);
|
|
68040
68197
|
|
|
68041
68198
|
// ../api-routes/src/doctor/checks/gbp-reviews.ts
|
|
68042
|
-
import { and as and77, desc as desc43, eq as eq93, gte as gte23, inArray as
|
|
68199
|
+
import { and as and77, desc as desc43, eq as eq93, gte as gte23, inArray as inArray40, sql as sql31 } from "drizzle-orm";
|
|
68043
68200
|
var REVIEW_EVENTS = /* @__PURE__ */ new Set(["review.negative", "review.rating-dropped"]);
|
|
68044
68201
|
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`.";
|
|
68045
68202
|
var reviewsAccessCheck = {
|
|
@@ -68162,7 +68319,7 @@ var reviewDeliveryCheck = {
|
|
|
68162
68319
|
payload: reviewWebhookDeliveries.payload
|
|
68163
68320
|
}).from(reviewWebhookDeliveries).where(and77(
|
|
68164
68321
|
eq93(reviewWebhookDeliveries.projectId, ctx.project.id),
|
|
68165
|
-
|
|
68322
|
+
inArray40(reviewWebhookDeliveries.state, [ReviewDeliveryStates.Uncertain, ReviewDeliveryStates.Failed]),
|
|
68166
68323
|
gte23(lastTouched, since)
|
|
68167
68324
|
)).orderBy(desc43(lastTouched)).all();
|
|
68168
68325
|
if (rows.length === 0) {
|
|
@@ -68747,7 +68904,7 @@ var RUNTIME_STATE_CHECKS = [
|
|
|
68747
68904
|
];
|
|
68748
68905
|
|
|
68749
68906
|
// ../api-routes/src/doctor/checks/traffic-source.ts
|
|
68750
|
-
import { and as and78, desc as desc44, eq as eq94, gte as gte24, inArray as
|
|
68907
|
+
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";
|
|
68751
68908
|
var RECENT_DATA_WARN_DAYS = 7;
|
|
68752
68909
|
var RECENT_DATA_FAIL_DAYS = 30;
|
|
68753
68910
|
function isCloudflareDirectPush(source) {
|
|
@@ -68927,7 +69084,7 @@ var recentDataCheck = {
|
|
|
68927
69084
|
ctx.db.select({ total: sql32`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
68928
69085
|
and78(
|
|
68929
69086
|
eq94(crawlerEventsHourly.projectId, ctx.project.id),
|
|
68930
|
-
|
|
69087
|
+
inArray41(crawlerEventsHourly.sourceId, activeSourceIds),
|
|
68931
69088
|
gte24(crawlerEventsHourly.tsHour, warnCutoff)
|
|
68932
69089
|
)
|
|
68933
69090
|
).get()?.total ?? 0
|
|
@@ -68936,7 +69093,7 @@ var recentDataCheck = {
|
|
|
68936
69093
|
ctx.db.select({ total: sql32`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
68937
69094
|
and78(
|
|
68938
69095
|
eq94(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
68939
|
-
|
|
69096
|
+
inArray41(aiReferralEventsHourly.sourceId, activeSourceIds),
|
|
68940
69097
|
gte24(aiReferralEventsHourly.tsHour, warnCutoff)
|
|
68941
69098
|
)
|
|
68942
69099
|
).get()?.total ?? 0
|
|
@@ -68945,7 +69102,7 @@ var recentDataCheck = {
|
|
|
68945
69102
|
ctx.db.select({ total: sql32`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
68946
69103
|
and78(
|
|
68947
69104
|
eq94(aiUserFetchEventsHourly.projectId, ctx.project.id),
|
|
68948
|
-
|
|
69105
|
+
inArray41(aiUserFetchEventsHourly.sourceId, activeSourceIds),
|
|
68949
69106
|
gte24(aiUserFetchEventsHourly.tsHour, warnCutoff)
|
|
68950
69107
|
)
|
|
68951
69108
|
).get()?.total ?? 0
|
|
@@ -68971,7 +69128,7 @@ var recentDataCheck = {
|
|
|
68971
69128
|
ctx.db.select({ total: sql32`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)` }).from(crawlerEventsHourly).where(
|
|
68972
69129
|
and78(
|
|
68973
69130
|
eq94(crawlerEventsHourly.projectId, ctx.project.id),
|
|
68974
|
-
|
|
69131
|
+
inArray41(crawlerEventsHourly.sourceId, activeSourceIds),
|
|
68975
69132
|
gte24(crawlerEventsHourly.tsHour, failCutoff)
|
|
68976
69133
|
)
|
|
68977
69134
|
).get()?.total ?? 0
|
|
@@ -68980,7 +69137,7 @@ var recentDataCheck = {
|
|
|
68980
69137
|
ctx.db.select({ total: sql32`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)` }).from(aiReferralEventsHourly).where(
|
|
68981
69138
|
and78(
|
|
68982
69139
|
eq94(aiReferralEventsHourly.projectId, ctx.project.id),
|
|
68983
|
-
|
|
69140
|
+
inArray41(aiReferralEventsHourly.sourceId, activeSourceIds),
|
|
68984
69141
|
gte24(aiReferralEventsHourly.tsHour, failCutoff)
|
|
68985
69142
|
)
|
|
68986
69143
|
).get()?.total ?? 0
|
|
@@ -68989,7 +69146,7 @@ var recentDataCheck = {
|
|
|
68989
69146
|
ctx.db.select({ total: sql32`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)` }).from(aiUserFetchEventsHourly).where(
|
|
68990
69147
|
and78(
|
|
68991
69148
|
eq94(aiUserFetchEventsHourly.projectId, ctx.project.id),
|
|
68992
|
-
|
|
69149
|
+
inArray41(aiUserFetchEventsHourly.sourceId, activeSourceIds),
|
|
68993
69150
|
gte24(aiUserFetchEventsHourly.tsHour, failCutoff)
|
|
68994
69151
|
)
|
|
68995
69152
|
).get()?.total ?? 0
|
|
@@ -70245,7 +70402,7 @@ async function statusRoutes(app, opts) {
|
|
|
70245
70402
|
|
|
70246
70403
|
// ../api-routes/src/discovery/routes.ts
|
|
70247
70404
|
import crypto54 from "crypto";
|
|
70248
|
-
import { and as and80, desc as desc46, eq as eq96, gte as gte25, inArray as
|
|
70405
|
+
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";
|
|
70249
70406
|
var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
|
|
70250
70407
|
async function discoveryRoutes(app, opts) {
|
|
70251
70408
|
app.post("/projects/:name/discover/run", async (request, reply) => {
|
|
@@ -70300,7 +70457,7 @@ async function discoveryRoutes(app, opts) {
|
|
|
70300
70457
|
// must never reuse another set's session. Null (= Gemini-only
|
|
70301
70458
|
// default, including explicit ['gemini']) matches legacy rows.
|
|
70302
70459
|
seedProviders == null ? isNull16(discoverySessions.seedProviders) : eq96(discoverySessions.seedProviders, seedProviders),
|
|
70303
|
-
|
|
70460
|
+
inArray42(discoverySessions.status, [
|
|
70304
70461
|
DiscoverySessionStatuses.queued,
|
|
70305
70462
|
DiscoverySessionStatuses.seeding,
|
|
70306
70463
|
DiscoverySessionStatuses.probing
|
|
@@ -71008,7 +71165,7 @@ function dedupeStrings(input) {
|
|
|
71008
71165
|
|
|
71009
71166
|
// ../api-routes/src/technical-aeo.ts
|
|
71010
71167
|
import crypto56 from "crypto";
|
|
71011
|
-
import { and as and82, asc as asc21, count as count8, desc as desc47, eq as eq99, gte as gte26, inArray as
|
|
71168
|
+
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";
|
|
71012
71169
|
import { alias } from "drizzle-orm/sqlite-core";
|
|
71013
71170
|
|
|
71014
71171
|
// ../api-routes/src/technical-aeo-issues.ts
|
|
@@ -71644,7 +71801,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
71644
71801
|
eq99(siteCrawlSnapshots.projectId, projectId),
|
|
71645
71802
|
eq99(runs.projectId, projectId),
|
|
71646
71803
|
eq99(runs.kind, RunKinds["site-audit"]),
|
|
71647
|
-
|
|
71804
|
+
inArray43(runs.status, SURFACEABLE_STATUSES),
|
|
71648
71805
|
notProbeRun()
|
|
71649
71806
|
];
|
|
71650
71807
|
const availableScanDatesFor = (projectId, requestedDate) => {
|
|
@@ -71714,7 +71871,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
71714
71871
|
eq99(siteAuditSnapshots.projectId, projectId),
|
|
71715
71872
|
eq99(runs.projectId, projectId),
|
|
71716
71873
|
eq99(runs.kind, RunKinds["site-audit"]),
|
|
71717
|
-
|
|
71874
|
+
inArray43(runs.status, SURFACEABLE_STATUSES),
|
|
71718
71875
|
notProbeRun(),
|
|
71719
71876
|
...recordedBefore ? [lt14(siteAuditSnapshots.createdAt, recordedBefore)] : []
|
|
71720
71877
|
];
|
|
@@ -71857,7 +72014,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
71857
72014
|
eq99(runs.id, runId),
|
|
71858
72015
|
eq99(runs.projectId, projectId),
|
|
71859
72016
|
eq99(runs.kind, RunKinds["site-audit"]),
|
|
71860
|
-
|
|
72017
|
+
inArray43(runs.status, SURFACEABLE_STATUSES),
|
|
71861
72018
|
notProbeRun()
|
|
71862
72019
|
)).limit(1).get());
|
|
71863
72020
|
const assertKnownAuditRun = (projectId, runId) => {
|
|
@@ -71867,7 +72024,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
71867
72024
|
eq99(siteAuditSnapshots.projectId, projectId),
|
|
71868
72025
|
eq99(runs.projectId, projectId),
|
|
71869
72026
|
eq99(runs.kind, RunKinds["site-audit"]),
|
|
71870
|
-
|
|
72027
|
+
inArray43(runs.status, SURFACEABLE_STATUSES),
|
|
71871
72028
|
notProbeRun()
|
|
71872
72029
|
)).limit(1).get());
|
|
71873
72030
|
const emptyCrawlSummary = (projectName, legacyAuditAvailable) => ({
|
|
@@ -71998,7 +72155,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
71998
72155
|
eq99(siteAuditSnapshots.projectId, project.id),
|
|
71999
72156
|
eq99(runs.projectId, project.id),
|
|
72000
72157
|
eq99(runs.kind, RunKinds["site-audit"]),
|
|
72001
|
-
|
|
72158
|
+
inArray43(runs.status, SURFACEABLE_STATUSES),
|
|
72002
72159
|
notProbeRun()
|
|
72003
72160
|
)).orderBy(desc47(siteAuditSnapshots.createdAt)).limit(limit).all();
|
|
72004
72161
|
return { project: project.name, points: rows.reverse() };
|
|
@@ -72313,8 +72470,8 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72313
72470
|
eq99(siteCrawlEdges.internal, true),
|
|
72314
72471
|
isNotNull10(siteCrawlEdges.targetNodeKey),
|
|
72315
72472
|
or21(
|
|
72316
|
-
|
|
72317
|
-
|
|
72473
|
+
inArray43(siteCrawlEdges.sourceNodeKey, frontier),
|
|
72474
|
+
inArray43(siteCrawlEdges.targetNodeKey, frontier)
|
|
72318
72475
|
)
|
|
72319
72476
|
)).orderBy(asc21(siteCrawlEdges.edgeKey)).limit(maxEdges + maxNodes + 1).all();
|
|
72320
72477
|
if (candidates.length > maxEdges + maxNodes) queryTruncated = true;
|
|
@@ -72351,7 +72508,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72351
72508
|
eq99(siteCrawlPages.projectId, scope.projectId),
|
|
72352
72509
|
eq99(siteCrawlPages.runId, scope.runId),
|
|
72353
72510
|
eq99(siteCrawlPages.attemptId, scope.attemptId),
|
|
72354
|
-
|
|
72511
|
+
inArray43(siteCrawlPages.nodeKey, nodeKeys)
|
|
72355
72512
|
)).all();
|
|
72356
72513
|
const persistedNodeKeys = new Set(pageRows.map((row) => row.nodeKey));
|
|
72357
72514
|
const outermostNodeKeys = pageRows.filter((row) => distances.get(row.nodeKey) === hops).map((row) => row.nodeKey);
|
|
@@ -72361,8 +72518,8 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72361
72518
|
eq99(siteCrawlEdges.attemptId, scope.attemptId),
|
|
72362
72519
|
eq99(siteCrawlEdges.internal, true),
|
|
72363
72520
|
isNotNull10(siteCrawlEdges.targetNodeKey),
|
|
72364
|
-
|
|
72365
|
-
|
|
72521
|
+
inArray43(siteCrawlEdges.sourceNodeKey, outermostNodeKeys),
|
|
72522
|
+
inArray43(siteCrawlEdges.targetNodeKey, outermostNodeKeys)
|
|
72366
72523
|
)).limit(1).get();
|
|
72367
72524
|
if (omittedOutermostEdge && !seenEdgeKeys.has(omittedOutermostEdge.edgeKey)) {
|
|
72368
72525
|
omittedEdgeKeys.add(omittedOutermostEdge.edgeKey);
|
|
@@ -72463,7 +72620,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72463
72620
|
eq99(siteCrawlEdges.followable, true),
|
|
72464
72621
|
eq99(siteCrawlEdges.relation, "anchor"),
|
|
72465
72622
|
isNotNull10(siteCrawlEdges.targetNodeKey),
|
|
72466
|
-
|
|
72623
|
+
inArray43(siteCrawlEdges.sourceNodeKey, frontier)
|
|
72467
72624
|
)).orderBy(asc21(siteCrawlEdges.edgeKey)).limit(SITE_HEALTH_PATH_MAX_VISITED_NODES + 1).all();
|
|
72468
72625
|
if (candidates.length > SITE_HEALTH_PATH_MAX_VISITED_NODES) truncated = true;
|
|
72469
72626
|
const candidateTargetKeys = [...new Set(candidates.map((edge) => edge.targetNodeKey).filter((nodeKey) => nodeKey != null))];
|
|
@@ -72471,7 +72628,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72471
72628
|
eq99(siteCrawlPages.projectId, scope.projectId),
|
|
72472
72629
|
eq99(siteCrawlPages.runId, scope.runId),
|
|
72473
72630
|
eq99(siteCrawlPages.attemptId, scope.attemptId),
|
|
72474
|
-
|
|
72631
|
+
inArray43(siteCrawlPages.nodeKey, candidateTargetKeys)
|
|
72475
72632
|
)).all().map((row) => row.nodeKey));
|
|
72476
72633
|
const next = /* @__PURE__ */ new Set();
|
|
72477
72634
|
for (const edge of candidates.slice(0, SITE_HEALTH_PATH_MAX_VISITED_NODES)) {
|
|
@@ -72516,7 +72673,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72516
72673
|
eq99(siteCrawlPages.projectId, scope.projectId),
|
|
72517
72674
|
eq99(siteCrawlPages.runId, scope.runId),
|
|
72518
72675
|
eq99(siteCrawlPages.attemptId, scope.attemptId),
|
|
72519
|
-
|
|
72676
|
+
inArray43(siteCrawlPages.nodeKey, pathKeys)
|
|
72520
72677
|
)).all();
|
|
72521
72678
|
const pageByKey = new Map(pathRows.map((row) => [row.nodeKey, row]));
|
|
72522
72679
|
const pathDetection = templateDetectionOf(snapshot.templateDetection);
|
|
@@ -72807,14 +72964,14 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
72807
72964
|
eq99(siteCrawlPages.projectId, scope.projectId),
|
|
72808
72965
|
eq99(siteCrawlPages.runId, scope.runId),
|
|
72809
72966
|
eq99(siteCrawlPages.attemptId, scope.attemptId),
|
|
72810
|
-
|
|
72967
|
+
inArray43(siteCrawlPages.nodeKey, pageKeys)
|
|
72811
72968
|
)).all();
|
|
72812
72969
|
const edgeRowsFor = (scope) => linkKeys.length === 0 ? [] : app.db.select().from(siteCrawlEdges).where(and82(
|
|
72813
72970
|
eq99(siteCrawlEdges.projectId, scope.projectId),
|
|
72814
72971
|
eq99(siteCrawlEdges.runId, scope.runId),
|
|
72815
72972
|
eq99(siteCrawlEdges.attemptId, scope.attemptId),
|
|
72816
72973
|
eq99(siteCrawlEdges.internal, true),
|
|
72817
|
-
|
|
72974
|
+
inArray43(siteCrawlEdges.edgeKey, linkKeys)
|
|
72818
72975
|
)).all();
|
|
72819
72976
|
const beforePages = new Map(pageRowsFor(beforeScope).map((row) => [row.nodeKey, mapCrawlPage(row)]));
|
|
72820
72977
|
const afterPages = new Map(pageRowsFor(afterScope).map((row) => [row.nodeKey, mapCrawlPage(row)]));
|
|
@@ -73340,9 +73497,9 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
73340
73497
|
eq99(siteCrawlSnapshots.projectId, project.id),
|
|
73341
73498
|
eq99(runs.projectId, project.id),
|
|
73342
73499
|
eq99(runs.kind, RunKinds["site-audit"]),
|
|
73343
|
-
|
|
73500
|
+
inArray43(runs.status, SURFACEABLE_STATUSES),
|
|
73344
73501
|
notProbeRun(),
|
|
73345
|
-
|
|
73502
|
+
inArray43(siteCrawlSnapshots.runId, runIds)
|
|
73346
73503
|
)).all().map((row) => row.runId));
|
|
73347
73504
|
return {
|
|
73348
73505
|
project: project.name,
|
|
@@ -73483,7 +73640,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
73483
73640
|
)).where(and82(
|
|
73484
73641
|
eq99(runs.projectId, project.id),
|
|
73485
73642
|
eq99(runs.kind, RunKinds["site-audit"]),
|
|
73486
|
-
|
|
73643
|
+
inArray43(runs.status, [RunStatuses.queued, RunStatuses.running])
|
|
73487
73644
|
)).get();
|
|
73488
73645
|
if (existing) {
|
|
73489
73646
|
if (existing.identityKey === identityKey) {
|
|
@@ -74342,6 +74499,7 @@ async function apiRoutes(app, opts) {
|
|
|
74342
74499
|
vercelTrafficCredentialStore: opts.vercelTrafficCredentialStore,
|
|
74343
74500
|
pullVercelTrafficEvents: opts.pullVercelTrafficEvents,
|
|
74344
74501
|
vercelSyncDeadlineMs: opts.vercelSyncDeadlineMs,
|
|
74502
|
+
trafficBackfillLeaseRenewMs: opts.trafficBackfillLeaseRenewMs,
|
|
74345
74503
|
cloudflareTrafficCredentialStore: opts.cloudflareTrafficCredentialStore,
|
|
74346
74504
|
pullCloudflareQueueMessages: opts.pullCloudflareQueueMessages,
|
|
74347
74505
|
ackCloudflareQueueMessages: opts.ackCloudflareQueueMessages,
|