@canonry/canonry 7.0.0 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/agent-workspace/skills/canonry/references/aeo-analysis.md +5 -3
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +19 -2
- package/assets/assets/AuditHistoryPanel-Duvyi8vx.js +1 -0
- package/assets/assets/{BacklinksPage-HIM0fmV7.js → BacklinksPage-CY5AllQu.js} +1 -1
- package/assets/assets/{HistoryPage-BjEVp-fk.js → HistoryPage-C0Gr0gcj.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-BnVDR2y_.js → MeasurementPropertyPage-DrAB6VKX.js} +1 -1
- package/assets/assets/ProjectPage-DSxvvnAd.js +8 -0
- package/assets/assets/{RunsPage-fJQe2qJc.js → RunsPage-DMxOrtfl.js} +1 -1
- package/assets/assets/{SettingsPage-1yam5tl6.js → SettingsPage-sxiUNt2A.js} +1 -1
- package/assets/assets/SiteHealthSection--6tZe3hM.js +4 -0
- package/assets/assets/{TrafficPage-BdNEscz8.js → TrafficPage-CvSQDNTi.js} +2 -2
- package/assets/assets/{TrafficSourceDetailPage-CMEgr4Aw.js → TrafficSourceDetailPage-BaYeIBmc.js} +1 -1
- package/assets/assets/{extract-error-message-D2dhaJaW.js → extract-error-message-76IWhqQF.js} +1 -1
- package/assets/assets/index-BlrH2zRW.js +86 -0
- package/assets/assets/index-HWSQgVum.css +1 -0
- package/assets/assets/{react-sigma_core.esm.min-oP23IWpt.js → react-sigma_core.esm.min-CkAcKW2k.js} +1 -1
- package/assets/assets/{v2-overview-adapter-DYatWs7N.js → v2-overview-adapter-DnEE4E9w.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-TUHQ5BBQ.js → chunk-BYSSJEL7.js} +9 -8
- package/dist/{chunk-LXWY4NKP.js → chunk-EQBYK77W.js} +3 -3
- package/dist/{chunk-HQJ25LI7.js → chunk-FDBQOQLP.js} +2 -2
- package/dist/{chunk-EZ54X4XH.js → chunk-RCQJI3UX.js} +125 -86
- package/dist/{chunk-RRIZ5AKI.js → chunk-SVTVBPIT.js} +2 -2
- package/dist/{chunk-OOUDIVIU.js → chunk-TY3CJKKR.js} +458 -184
- package/dist/{chunk-A5PALGQD.js → chunk-UIDHHZH3.js} +94 -190
- package/dist/cli.js +32 -16
- package/dist/{demo-server-LHHDVXQW.js → demo-server-GWRYDPJC.js} +4 -4
- package/dist/index.js +6 -6
- package/dist/{intelligence-service-ZVKZLLKL.js → intelligence-service-3L2665AK.js} +2 -2
- package/dist/mcp.js +4 -4
- package/package.json +12 -12
- package/assets/assets/AuditHistoryPanel-DBYsgVsn.js +0 -1
- package/assets/assets/ProjectPage-BhCM47KA.js +0 -8
- package/assets/assets/SiteHealthSection-DysU2M6C.js +0 -4
- package/assets/assets/index-CgT2Btdn.css +0 -1
- package/assets/assets/index-D9ODLKpH.js +0 -86
|
@@ -609,6 +609,7 @@ import {
|
|
|
609
609
|
queryTrackingProvenanceSchema,
|
|
610
610
|
queryTrackingWorkspaceResponseSchema,
|
|
611
611
|
quotaExceeded,
|
|
612
|
+
rankCriticizedProperties,
|
|
612
613
|
recommendationBriefDtoSchema,
|
|
613
614
|
recommendationExplainRequestSchema,
|
|
614
615
|
recommendationExplanationDtoSchema,
|
|
@@ -726,6 +727,7 @@ import {
|
|
|
726
727
|
stripCitationChips,
|
|
727
728
|
sumInfraHits,
|
|
728
729
|
summarizeCheckResults,
|
|
730
|
+
summarizeObservedQueryCounts,
|
|
729
731
|
summarizeRunUsage,
|
|
730
732
|
surfaceClassFromCompetitorType,
|
|
731
733
|
surfaceClassLabel,
|
|
@@ -750,6 +752,7 @@ import {
|
|
|
750
752
|
trafficSourceListResponseSchema,
|
|
751
753
|
trafficStatusResponseSchema,
|
|
752
754
|
trafficSyncResponseSchema,
|
|
755
|
+
uiTelemetryEventSchema,
|
|
753
756
|
unsupportedKind,
|
|
754
757
|
upgradeCaveatFor,
|
|
755
758
|
userDtoSchema,
|
|
@@ -777,7 +780,7 @@ import {
|
|
|
777
780
|
wordpressSchemaDeployResultDtoSchema,
|
|
778
781
|
wordpressSchemaStatusResultDtoSchema,
|
|
779
782
|
wordpressStatusDtoSchema
|
|
780
|
-
} from "./chunk-
|
|
783
|
+
} from "./chunk-TY3CJKKR.js";
|
|
781
784
|
|
|
782
785
|
// src/intelligence-service.ts
|
|
783
786
|
import { eq as eq82, desc as desc36, asc as asc15, and as and69, ne as ne14, or as or19, inArray as inArray31, gte as gte22, lte as lte20, isNull as isNull16, sql as sql31, exists } from "drizzle-orm";
|
|
@@ -13803,7 +13806,8 @@ var SentimentService = class {
|
|
|
13803
13806
|
return { ...scoreAssessments(group.measured, group.eligible, options), queryId: group.queryId, queryText: group.queryText, queryClass: selection.queryClass, sourceSnapshotIds: [...new Set(group.eligible.map((item2) => item2.snapshotId))].sort(), assessments, locations, executionNodeKey: group.executionNodeKey };
|
|
13804
13807
|
});
|
|
13805
13808
|
const next = rows.limit !== null && from + rows.limit < ordered.length ? rowKey(page3.at(-1)) : null;
|
|
13806
|
-
|
|
13809
|
+
const criticizedProperties = selection.queryClass === "branded" && !disabled ? rankCriticizedProperties(breakdowns) : void 0;
|
|
13810
|
+
return { summary: { ...base, breakdowns, ...criticizedProperties ? { criticizedProperties } : {} }, queries: queries2, total: ordered.length, next };
|
|
13807
13811
|
}
|
|
13808
13812
|
readSelection(projectId, query, withInput = false) {
|
|
13809
13813
|
if (query.runId && query.runIds) throw validationError("Choose runId or runIds, not both.");
|
|
@@ -13828,7 +13832,7 @@ var SentimentService = class {
|
|
|
13828
13832
|
const unavailable5 = { state: "unsupported", reason: read.reason, provisional: true, score: aggregateSentiment([]).score };
|
|
13829
13833
|
return {
|
|
13830
13834
|
...result,
|
|
13831
|
-
summary: { ...result.summary, ...unavailable5, breakdowns: result.summary.breakdowns.map((row) => ({ ...row, ...unavailable5 })) },
|
|
13835
|
+
summary: { ...result.summary, ...unavailable5, breakdowns: result.summary.breakdowns.map((row) => ({ ...row, ...unavailable5 })), criticizedProperties: void 0 },
|
|
13832
13836
|
queries: result.queries.map((row) => ({ ...row, ...unavailable5, assessments: row.assessments.map((assessment) => ({ ...assessment, state: "unsupported", outcome: null, reason: read.reason })), locations: row.locations.map((location) => ({ ...location, ...unavailable5 })) }))
|
|
13833
13837
|
};
|
|
13834
13838
|
}
|
|
@@ -13866,11 +13870,12 @@ var SentimentService = class {
|
|
|
13866
13870
|
return { configured, branded, nonBrand, overall: overallSentiment(reads, !configured) };
|
|
13867
13871
|
}
|
|
13868
13872
|
evidence(projectId, query, limit, cursor) {
|
|
13869
|
-
const { assessmentId, ...sourceSelection } = query;
|
|
13873
|
+
const { assessmentId, outcome: outcome2, ...sourceSelection } = query;
|
|
13874
|
+
const outcomes = outcome2?.length ? new Set(outcome2) : null;
|
|
13870
13875
|
const settings = this.settings(projectId);
|
|
13871
13876
|
const disabled = !settings.enabled || !settings.installEnabled;
|
|
13872
13877
|
const read = disabled ? this.readSelection(projectId, sourceSelection) : this.readSelection(projectId, sourceSelection, true);
|
|
13873
|
-
const selection = { ...read.selection, ...assessmentId ? { assessmentId } : {} };
|
|
13878
|
+
const selection = { ...read.selection, ...assessmentId ? { assessmentId } : {}, ...outcomes ? { outcome: [...outcomes].sort() } : {} };
|
|
13874
13879
|
let after = "";
|
|
13875
13880
|
if (cursor) {
|
|
13876
13881
|
const token = this.verify(cursor);
|
|
@@ -13879,7 +13884,7 @@ var SentimentService = class {
|
|
|
13879
13884
|
}
|
|
13880
13885
|
const state = this.present(read, settings, null).summary.state;
|
|
13881
13886
|
if (disabled) return { state, selection, items: [], nextCursor: null };
|
|
13882
|
-
const items = read.items.filter((item2) => !assessmentId || item2.work.id === assessmentId).sort((a, b) => a.work.id.localeCompare(b.work.id)).filter((item2) => item2.work.id > after);
|
|
13887
|
+
const items = read.items.filter((item2) => (!assessmentId || item2.work.id === assessmentId) && (!outcomes || outcomes.has(item2.outcome))).sort((a, b) => a.work.id.localeCompare(b.work.id)).filter((item2) => item2.work.id > after);
|
|
13883
13888
|
const page3 = items.slice(0, limit);
|
|
13884
13889
|
return { state, selection, items: page3.map((item2) => item2.evidence), nextCursor: items.length > limit ? this.sign({ projectId, selection, fingerprint: read.fingerprint, after: page3.at(-1).work.id }) : null };
|
|
13885
13890
|
}
|
|
@@ -13896,8 +13901,8 @@ var SentimentService = class {
|
|
|
13896
13901
|
const fromUnits = units(fromItems), toUnits = units(toItems);
|
|
13897
13902
|
const common = new Set([...fromUnits.byUnit.keys()].filter((key) => toUnits.byUnit.has(key)));
|
|
13898
13903
|
const settings = this.settings(projectId);
|
|
13899
|
-
const fromSummary = withoutNodeKeys(this.aggregate(from.selection, fromItems.filter((item2) => common.has(fromUnits.byItem.get(item2))), from.source, settings, COMPACT_ROWS, fromItems));
|
|
13900
|
-
const toSummary = withoutNodeKeys(this.aggregate(to.selection, toItems.filter((item2) => common.has(toUnits.byItem.get(item2))), to.source, settings, COMPACT_ROWS, toItems));
|
|
13904
|
+
const fromSummary = withoutCriticizedProperties(withoutNodeKeys(this.aggregate(from.selection, fromItems.filter((item2) => common.has(fromUnits.byItem.get(item2))), from.source, settings, COMPACT_ROWS, fromItems)));
|
|
13905
|
+
const toSummary = withoutCriticizedProperties(withoutNodeKeys(this.aggregate(to.selection, toItems.filter((item2) => common.has(toUnits.byItem.get(item2))), to.source, settings, COMPACT_ROWS, toItems)));
|
|
13901
13906
|
const refusalReasons = [];
|
|
13902
13907
|
const expectedFrom = from.source.assessments.length, expectedTo = to.source.assessments.length;
|
|
13903
13908
|
if (fromItems.length < expectedFrom || toItems.length < expectedTo) refusalReasons.push("classification-coverage-gap");
|
|
@@ -13970,6 +13975,10 @@ function append2(map, key, value) {
|
|
|
13970
13975
|
function queryRowKey(edge) {
|
|
13971
13976
|
return `${"queryKey" in edge ? edge.queryKey : edge.queryId}\0${edge.executionNodeKey ?? ""}`;
|
|
13972
13977
|
}
|
|
13978
|
+
function withoutCriticizedProperties(summary3) {
|
|
13979
|
+
const { criticizedProperties: _criticized, ...rest } = summary3;
|
|
13980
|
+
return rest;
|
|
13981
|
+
}
|
|
13973
13982
|
function withoutNodeKeys({ summary: summary3, queries: queries2 }) {
|
|
13974
13983
|
return { ...summary3, queries: queries2.map(({ executionNodeKey: _node, ...row }) => row) };
|
|
13975
13984
|
}
|
|
@@ -19061,7 +19070,7 @@ function evaluateRunFill(db, run, input = {}) {
|
|
|
19061
19070
|
"The measurement plan was republished since this run, so answers added now would mix two revisions in one run."
|
|
19062
19071
|
);
|
|
19063
19072
|
}
|
|
19064
|
-
const now =
|
|
19073
|
+
const now = Date.now();
|
|
19065
19074
|
const age = runFillAgeAnchor(run, { hadProviderBatch: runHadProviderBatch(db, run.id) });
|
|
19066
19075
|
const anchoredAt = Date.parse(age.anchor);
|
|
19067
19076
|
if (Number.isFinite(anchoredAt) && now - anchoredAt > RUN_FILL_MAX_AGE_MS) {
|
|
@@ -19195,7 +19204,7 @@ function queueRunFill(db, runId, input = {}) {
|
|
|
19195
19204
|
if (activeFill) return { kind: "fill-in-progress", fillId: activeFill.id };
|
|
19196
19205
|
const activeSweep = activeSweepFor(txDb, run.projectId);
|
|
19197
19206
|
if (activeSweep) return { kind: "run-in-progress", activeRunId: activeSweep.id };
|
|
19198
|
-
const now = (
|
|
19207
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
19199
19208
|
const id = crypto14.randomUUID();
|
|
19200
19209
|
txDb.insert(runFills).values({
|
|
19201
19210
|
id,
|
|
@@ -19777,61 +19786,66 @@ function loadRunDetail(app, run) {
|
|
|
19777
19786
|
rawResponse: querySnapshots.rawResponse,
|
|
19778
19787
|
createdAt: querySnapshots.createdAt
|
|
19779
19788
|
}).from(querySnapshots).leftJoin(queries, eq24(querySnapshots.queryId, queries.id)).where(eq24(querySnapshots.runId, run.id)).all();
|
|
19789
|
+
const mappedSnapshots = snapshots.map((s) => {
|
|
19790
|
+
const rawParsed = parseSnapshotRawResponse(s.rawResponse);
|
|
19791
|
+
const signalGroundingSources = rawParsed.groundingSources.filter(
|
|
19792
|
+
(source) => typeof source === "object" && source !== null && typeof source.uri === "string"
|
|
19793
|
+
);
|
|
19794
|
+
const competitiveSignals = competitiveSignalResolver.resolve({
|
|
19795
|
+
citedDomains: s.citedDomains,
|
|
19796
|
+
groundingSources: signalGroundingSources,
|
|
19797
|
+
answerText: s.answerText
|
|
19798
|
+
});
|
|
19799
|
+
const answerMentioned = project ? resolveSnapshotAnswerMentioned(s, project) : s.answerMentioned ?? false;
|
|
19800
|
+
return {
|
|
19801
|
+
id: s.id,
|
|
19802
|
+
runId: s.runId,
|
|
19803
|
+
queryId: s.queryId,
|
|
19804
|
+
query: s.query,
|
|
19805
|
+
provider: s.provider,
|
|
19806
|
+
citationState: s.citationState,
|
|
19807
|
+
answerMentioned,
|
|
19808
|
+
// Legacy alias of `mentionState`, retained for backwards compatibility.
|
|
19809
|
+
visibilityState: project ? resolveSnapshotVisibilityState(s, project) : answerMentioned ? "visible" : "not-visible",
|
|
19810
|
+
// Canonical vocabulary for answer-text presence; new consumers prefer this.
|
|
19811
|
+
mentionState: project ? resolveSnapshotMentionState(s, project) : answerMentioned ? "mentioned" : "not-mentioned",
|
|
19812
|
+
answerText: s.answerText,
|
|
19813
|
+
citedDomains: s.citedDomains,
|
|
19814
|
+
citedUrls: s.citedUrls,
|
|
19815
|
+
captureStatus: s.captureStatus,
|
|
19816
|
+
sourceCount: s.sourceCount,
|
|
19817
|
+
resolvedCount: s.resolvedCount,
|
|
19818
|
+
captureVersion: s.captureVersion,
|
|
19819
|
+
...competitiveSignals,
|
|
19820
|
+
// Legacy mixed signal retained for backwards compatibility.
|
|
19821
|
+
competitorOverlap: s.competitorOverlap,
|
|
19822
|
+
recommendedCompetitors: s.recommendedCompetitors,
|
|
19823
|
+
matchedTerms: project ? resolveSnapshotMatchedTerms(s, project) : [],
|
|
19824
|
+
model: s.model ?? rawParsed.model,
|
|
19825
|
+
// Column only. `model` may fall back to the stored envelope because both
|
|
19826
|
+
// record the same requested value; a served id has no such equivalent —
|
|
19827
|
+
// an unrecoverable one stays null rather than echoing configuration.
|
|
19828
|
+
servedModel: s.servedModel,
|
|
19829
|
+
location: s.location,
|
|
19830
|
+
requestedContext: s.requestedContext,
|
|
19831
|
+
supportedContext: s.supportedContext,
|
|
19832
|
+
dispatchMode: s.dispatchMode,
|
|
19833
|
+
stopReason: s.stopReason,
|
|
19834
|
+
usage: s.usage,
|
|
19835
|
+
groundingSources: rawParsed.groundingSources,
|
|
19836
|
+
searchQueries: rawParsed.searchQueries,
|
|
19837
|
+
createdAt: s.createdAt
|
|
19838
|
+
};
|
|
19839
|
+
});
|
|
19840
|
+
const identifiedSignals = mappedSnapshots.flatMap(
|
|
19841
|
+
(snapshot) => typeof snapshot.queryId === "string" && snapshot.queryId.length > 0 ? [{ queryId: snapshot.queryId, citationState: snapshot.citationState, answerMentioned: snapshot.answerMentioned }] : []
|
|
19842
|
+
);
|
|
19780
19843
|
return {
|
|
19781
19844
|
...formatRun(run),
|
|
19782
19845
|
providerBatches: readRunProviderBatches(app.db, run.id),
|
|
19783
19846
|
usage: summarizeRunUsage(snapshots),
|
|
19784
|
-
snapshots:
|
|
19785
|
-
|
|
19786
|
-
const signalGroundingSources = rawParsed.groundingSources.filter(
|
|
19787
|
-
(source) => typeof source === "object" && source !== null && typeof source.uri === "string"
|
|
19788
|
-
);
|
|
19789
|
-
const competitiveSignals = competitiveSignalResolver.resolve({
|
|
19790
|
-
citedDomains: s.citedDomains,
|
|
19791
|
-
groundingSources: signalGroundingSources,
|
|
19792
|
-
answerText: s.answerText
|
|
19793
|
-
});
|
|
19794
|
-
const answerMentioned = project ? resolveSnapshotAnswerMentioned(s, project) : s.answerMentioned ?? false;
|
|
19795
|
-
return {
|
|
19796
|
-
id: s.id,
|
|
19797
|
-
runId: s.runId,
|
|
19798
|
-
queryId: s.queryId,
|
|
19799
|
-
query: s.query,
|
|
19800
|
-
provider: s.provider,
|
|
19801
|
-
citationState: s.citationState,
|
|
19802
|
-
answerMentioned,
|
|
19803
|
-
// Legacy alias of `mentionState`, retained for backwards compatibility.
|
|
19804
|
-
visibilityState: project ? resolveSnapshotVisibilityState(s, project) : answerMentioned ? "visible" : "not-visible",
|
|
19805
|
-
// Canonical vocabulary for answer-text presence; new consumers prefer this.
|
|
19806
|
-
mentionState: project ? resolveSnapshotMentionState(s, project) : answerMentioned ? "mentioned" : "not-mentioned",
|
|
19807
|
-
answerText: s.answerText,
|
|
19808
|
-
citedDomains: s.citedDomains,
|
|
19809
|
-
citedUrls: s.citedUrls,
|
|
19810
|
-
captureStatus: s.captureStatus,
|
|
19811
|
-
sourceCount: s.sourceCount,
|
|
19812
|
-
resolvedCount: s.resolvedCount,
|
|
19813
|
-
captureVersion: s.captureVersion,
|
|
19814
|
-
...competitiveSignals,
|
|
19815
|
-
// Legacy mixed signal retained for backwards compatibility.
|
|
19816
|
-
competitorOverlap: s.competitorOverlap,
|
|
19817
|
-
recommendedCompetitors: s.recommendedCompetitors,
|
|
19818
|
-
matchedTerms: project ? resolveSnapshotMatchedTerms(s, project) : [],
|
|
19819
|
-
model: s.model ?? rawParsed.model,
|
|
19820
|
-
// Column only. `model` may fall back to the stored envelope because both
|
|
19821
|
-
// record the same requested value; a served id has no such equivalent —
|
|
19822
|
-
// an unrecoverable one stays null rather than echoing configuration.
|
|
19823
|
-
servedModel: s.servedModel,
|
|
19824
|
-
location: s.location,
|
|
19825
|
-
requestedContext: s.requestedContext,
|
|
19826
|
-
supportedContext: s.supportedContext,
|
|
19827
|
-
dispatchMode: s.dispatchMode,
|
|
19828
|
-
stopReason: s.stopReason,
|
|
19829
|
-
usage: s.usage,
|
|
19830
|
-
groundingSources: rawParsed.groundingSources,
|
|
19831
|
-
searchQueries: rawParsed.searchQueries,
|
|
19832
|
-
createdAt: s.createdAt
|
|
19833
|
-
};
|
|
19834
|
-
})
|
|
19847
|
+
snapshots: mappedSnapshots,
|
|
19848
|
+
queryCounts: identifiedSignals.length === mappedSnapshots.length ? summarizeObservedQueryCounts(identifiedSignals) : null
|
|
19835
19849
|
};
|
|
19836
19850
|
}
|
|
19837
19851
|
|
|
@@ -34050,6 +34064,11 @@ function readEarliestGscDataDate(db, projectId) {
|
|
|
34050
34064
|
const dimensioned = db.select({ earliest: min(gscSearchData.date) }).from(gscSearchData).where(eq44(gscSearchData.projectId, projectId)).get()?.earliest ?? null;
|
|
34051
34065
|
return [property, dimensioned].filter((d) => d !== null).reduce((earliest, d) => earliest === null || d < earliest ? d : earliest, null);
|
|
34052
34066
|
}
|
|
34067
|
+
function readEarliestGscQueryDataDate(db, projectId) {
|
|
34068
|
+
const accurate = db.select({ earliest: min(gscQueryDailyTotals.date) }).from(gscQueryDailyTotals).where(and39(eq44(gscQueryDailyTotals.projectId, projectId), sql17`${gscQueryDailyTotals.date} <> ''`)).get()?.earliest ?? null;
|
|
34069
|
+
const dimensioned = db.select({ earliest: min(gscSearchData.date) }).from(gscSearchData).where(and39(eq44(gscSearchData.projectId, projectId), sql17`${gscSearchData.date} <> ''`)).get()?.earliest ?? null;
|
|
34070
|
+
return [accurate, dimensioned].filter((d) => d !== null).reduce((earliest, d) => earliest === null || d < earliest ? d : earliest, null);
|
|
34071
|
+
}
|
|
34053
34072
|
function readGscDailyTotals(db, projectId, startDate, endDate) {
|
|
34054
34073
|
const rows = db.select({
|
|
34055
34074
|
date: gscDailyTotals.date,
|
|
@@ -34588,34 +34607,17 @@ function summarizeFromSnapshots(snapshots) {
|
|
|
34588
34607
|
providers: []
|
|
34589
34608
|
};
|
|
34590
34609
|
if (snapshots.length === 0) return empty;
|
|
34591
|
-
const
|
|
34592
|
-
const perQueryMentioned = /* @__PURE__ */ new Map();
|
|
34610
|
+
const { totalQueries, citedQueries, mentionedQueries } = summarizeObservedQueryCounts(snapshots);
|
|
34593
34611
|
const perProvider = /* @__PURE__ */ new Map();
|
|
34594
34612
|
for (const snap of snapshots) {
|
|
34595
34613
|
const cited = snap.citationState === CitationStates.cited;
|
|
34596
|
-
if (!perQuery.has(snap.queryId) || cited) {
|
|
34597
|
-
perQuery.set(snap.queryId, cited);
|
|
34598
|
-
}
|
|
34599
|
-
const mentioned = snap.answerMentioned === true;
|
|
34600
|
-
if (!perQueryMentioned.has(snap.queryId) || mentioned) {
|
|
34601
|
-
perQueryMentioned.set(snap.queryId, mentioned);
|
|
34602
|
-
}
|
|
34603
34614
|
const bucket = perProvider.get(snap.provider) ?? { cited: 0, total: 0 };
|
|
34604
34615
|
bucket.total += 1;
|
|
34605
34616
|
if (cited) bucket.cited += 1;
|
|
34606
34617
|
perProvider.set(snap.provider, bucket);
|
|
34607
34618
|
}
|
|
34608
|
-
const totalQueries = perQuery.size;
|
|
34609
|
-
let citedQueries = 0;
|
|
34610
|
-
for (const wasCited of perQuery.values()) {
|
|
34611
|
-
if (wasCited) citedQueries += 1;
|
|
34612
|
-
}
|
|
34613
34619
|
const notCitedQueries = totalQueries - citedQueries;
|
|
34614
34620
|
const citedRate = totalQueries === 0 ? 0 : Number((citedQueries / totalQueries).toFixed(4));
|
|
34615
|
-
let mentionedQueries = 0;
|
|
34616
|
-
for (const wasMentioned of perQueryMentioned.values()) {
|
|
34617
|
-
if (wasMentioned) mentionedQueries += 1;
|
|
34618
|
-
}
|
|
34619
34621
|
const notMentionedQueries = totalQueries - mentionedQueries;
|
|
34620
34622
|
const mentionRate3 = totalQueries === 0 ? 0 : Number((mentionedQueries / totalQueries).toFixed(4));
|
|
34621
34623
|
const providers = [...perProvider.entries()].map(([provider, { cited, total }]) => ({
|
|
@@ -36011,6 +36013,7 @@ var SCHEMA_TABLE = {
|
|
|
36011
36013
|
MeasurementSetupResponse: measurementSetupResponseSchema,
|
|
36012
36014
|
NotificationDto: notificationDtoSchema,
|
|
36013
36015
|
OnboardingTelemetryEvent: onboardingTelemetryEventSchema,
|
|
36016
|
+
UiTelemetryEvent: uiTelemetryEventSchema,
|
|
36014
36017
|
OrganicEvidenceDto: organicEvidenceDtoSchema,
|
|
36015
36018
|
ProjectCreateRequest: projectCreateRequestSchema,
|
|
36016
36019
|
ProjectDto: projectDtoSchema,
|
|
@@ -37296,7 +37299,7 @@ var routeCatalog = [
|
|
|
37296
37299
|
path: "/api/v1/projects/{name}/sentiment/evidence",
|
|
37297
37300
|
summary: "Read verbatim sentiment evidence",
|
|
37298
37301
|
tags: ["sentiment"],
|
|
37299
|
-
parameters: [nameParameter, ...sentimentSelectionParameters, { name: "assessmentId", in: "query", description: "Exact stored assessment within the authorized source, subject, scope, and evaluator selection. Does not widen access.", schema: stringSchema }, { name: "cursor", in: "query", description: "Opaque cursor bound to every selection field and resolved evaluator ID.", schema: stringSchema }, { name: "limit", in: "query", description: "Page size only; does not change assessment identity.", schema: { type: "integer", minimum: 1, maximum: 100, default: 50 } }],
|
|
37302
|
+
parameters: [nameParameter, ...sentimentSelectionParameters, { name: "assessmentId", in: "query", description: "Exact stored assessment within the authorized source, subject, scope, and evaluator selection. Does not widen access.", schema: stringSchema }, { name: "outcome", in: "query", description: "Outcomes to keep, repeated or comma-separated (for example mixed,unfavorable). Narrows the page to assessments with these outcomes; never changes how they were scored.", style: "form", explode: true, schema: { type: "array", items: { type: "string", enum: [...sentimentOutcomeSchema.options] }, minItems: 1 } }, { name: "cursor", in: "query", description: "Opaque cursor bound to every selection field and resolved evaluator ID.", schema: stringSchema }, { name: "limit", in: "query", description: "Page size only; does not change assessment identity.", schema: { type: "integer", minimum: 1, maximum: 100, default: 50 } }],
|
|
37300
37303
|
responses: { 200: jsonResponse("Stored answer-subject evidence page.", "SentimentEvidencePage"), 400: errorResponse("Invalid cursor or selection."), 404: errorResponse("Project or selected source not found.") }
|
|
37301
37304
|
},
|
|
37302
37305
|
{
|
|
@@ -38386,6 +38389,7 @@ var routeCatalog = [
|
|
|
38386
38389
|
method: "get",
|
|
38387
38390
|
path: "/api/v1/runs/{id}",
|
|
38388
38391
|
summary: "Get a run and its snapshots",
|
|
38392
|
+
description: "Includes independent citation and mention counts over distinct observed query IDs in this exact run. queryCounts is null when any snapshot lacks query identity; these counts are not planned-slot completeness.",
|
|
38389
38393
|
tags: ["runs"],
|
|
38390
38394
|
parameters: [runIdParameter],
|
|
38391
38395
|
responses: {
|
|
@@ -39175,6 +39179,25 @@ var routeCatalog = [
|
|
|
39175
39179
|
400: errorResponse("Invalid onboarding telemetry event.")
|
|
39176
39180
|
}
|
|
39177
39181
|
},
|
|
39182
|
+
{
|
|
39183
|
+
method: "post",
|
|
39184
|
+
path: "/api/v1/telemetry/ui",
|
|
39185
|
+
summary: "Record a privacy-safe dashboard usage event",
|
|
39186
|
+
description: "Page views (route patterns), allowlisted feature actions, UI errors (class names and route templates only), and web vitals ratings from the dashboard. Forwarded through the opt-in anonymous telemetry path; accepted:false when this host does not collect telemetry.",
|
|
39187
|
+
tags: ["telemetry"],
|
|
39188
|
+
requestBody: {
|
|
39189
|
+
required: true,
|
|
39190
|
+
content: {
|
|
39191
|
+
"application/json": {
|
|
39192
|
+
schema: { $ref: "#/components/schemas/UiTelemetryEvent" }
|
|
39193
|
+
}
|
|
39194
|
+
}
|
|
39195
|
+
},
|
|
39196
|
+
responses: {
|
|
39197
|
+
202: jsonResponse("UI event accepted.", "TelemetryEventAcceptedDto"),
|
|
39198
|
+
400: errorResponse("Invalid UI telemetry event.")
|
|
39199
|
+
}
|
|
39200
|
+
},
|
|
39178
39201
|
{
|
|
39179
39202
|
method: "post",
|
|
39180
39203
|
path: "/api/v1/feedback",
|
|
@@ -39918,7 +39941,7 @@ var routeCatalog = [
|
|
|
39918
39941
|
method: "get",
|
|
39919
39942
|
path: "/api/v1/projects/{name}/google/gsc/query-totals",
|
|
39920
39943
|
summary: "Get GSC totals per query for a date window",
|
|
39921
|
-
description: "One row per search query over the window, read from stored sync data (no call to Google, no writes): clicks, impressions, CTR, impression-weighted average position (sum(position*impressions)/sum(impressions)) and the number of days the query appeared. Rows are ordered by clicks desc, impressions desc, then query ascending by code point, and paged with `limit` / `offset`; `totalMatching` counts every query and `truncated` says more rows follow. The rows cover the queries Google names only: Google leaves rare and anonymised queries out of per-query data, so their sum is below the property total (read `/google/gsc/performance/daily` for that). Each row carries `source`: `google` when every day came from Google's per-query fetch, `page-summed` when every day came from the legacy page-dimensioned table (impressions over-count), `mixed` when the window spans both.",
|
|
39944
|
+
description: "One row per search query over the window, read from stored sync data (no call to Google, no writes): clicks, impressions, CTR, impression-weighted average position (sum(position*impressions)/sum(impressions)) and the number of days the query appeared. Rows are ordered by clicks desc, impressions desc, then query ascending by code point, and paged with `limit` / `offset`; `totalMatching` counts every query and `truncated` says more rows follow. The rows cover the queries Google names only: Google leaves rare and anonymised queries out of per-query data, so their sum is below the property total (read `/google/gsc/performance/daily` for that). Each row carries `source`: `google` when every day came from Google's per-query fetch, `page-summed` when every day came from the legacy page-dimensioned table (impressions over-count), `mixed` when the window spans both. `window.earliestDataDate` is the first stored per-query date (null with none): a window that starts before it is only partly covered, so its missing days were never synced rather than zero traffic.",
|
|
39922
39945
|
tags: ["google"],
|
|
39923
39946
|
parameters: [
|
|
39924
39947
|
nameParameter,
|
|
@@ -43927,6 +43950,19 @@ async function telemetryRoutes(app, opts) {
|
|
|
43927
43950
|
opts.recordOnboardingEvent?.(normalizeOnboardingEventForCollection(parsed.data));
|
|
43928
43951
|
return reply.status(202).send({ accepted: Boolean(opts.recordOnboardingEvent) });
|
|
43929
43952
|
});
|
|
43953
|
+
app.post("/telemetry/ui", async (request, reply) => {
|
|
43954
|
+
const parsed = uiTelemetryEventSchema.safeParse(request.body);
|
|
43955
|
+
if (!parsed.success) {
|
|
43956
|
+
throw validationError("Invalid UI telemetry event", {
|
|
43957
|
+
issues: parsed.error.issues.map((issue) => ({
|
|
43958
|
+
code: issue.code,
|
|
43959
|
+
path: issue.path.join(".")
|
|
43960
|
+
}))
|
|
43961
|
+
});
|
|
43962
|
+
}
|
|
43963
|
+
const accepted = opts.recordUiEvent ? opts.recordUiEvent(parsed.data) : false;
|
|
43964
|
+
return reply.status(202).send({ accepted });
|
|
43965
|
+
});
|
|
43930
43966
|
}
|
|
43931
43967
|
|
|
43932
43968
|
// ../api-routes/src/feedback.ts
|
|
@@ -47362,7 +47398,9 @@ async function googleRoutes(app, opts) {
|
|
|
47362
47398
|
// Measured from where this page ends, so a page past the end is not
|
|
47363
47399
|
// reported as truncated.
|
|
47364
47400
|
truncated: offsetVal + rows.length < totalMatching,
|
|
47365
|
-
window
|
|
47401
|
+
// The floor beside the frontier, so a caller can tell a window the store
|
|
47402
|
+
// does not reach from one with little traffic.
|
|
47403
|
+
window: { ...window, earliestDataDate: readEarliestGscQueryDataDate(app.db, project.id) }
|
|
47366
47404
|
};
|
|
47367
47405
|
});
|
|
47368
47406
|
app.post("/projects/:name/google/gsc/inspect", async (request) => {
|
|
@@ -59044,7 +59082,7 @@ async function installDuckdb(opts = {}) {
|
|
|
59044
59082
|
const version = readInstalledVersion({ pluginPkgJson }) ?? "unknown";
|
|
59045
59083
|
return { alreadyPresent: false, version, path: pluginDir };
|
|
59046
59084
|
}
|
|
59047
|
-
async function ensurePluginDir(pluginDir
|
|
59085
|
+
async function ensurePluginDir(pluginDir, pluginPkgJson) {
|
|
59048
59086
|
await fs4.mkdir(pluginDir, { recursive: true });
|
|
59049
59087
|
try {
|
|
59050
59088
|
await fs4.access(pluginPkgJson);
|
|
@@ -75230,7 +75268,6 @@ async function resolveRetainedStart(options, unservableStartMs, endMs) {
|
|
|
75230
75268
|
async function drainVercelTrafficEvents(options) {
|
|
75231
75269
|
const startMs = toMs(options.startDate);
|
|
75232
75270
|
const endMs = toMs(options.endDate);
|
|
75233
|
-
const now = options.now ?? (() => Date.now());
|
|
75234
75271
|
const events = [];
|
|
75235
75272
|
const seenEventIds = /* @__PURE__ */ new Set();
|
|
75236
75273
|
if (endMs <= startMs) {
|
|
@@ -75249,7 +75286,7 @@ async function drainVercelTrafficEvents(options) {
|
|
|
75249
75286
|
const truncatedSliceStartsMs = [];
|
|
75250
75287
|
const deadlineSkippedSliceStartsMs = [];
|
|
75251
75288
|
while (cursorMs < endMs) {
|
|
75252
|
-
if (options.deadlineMs !== void 0 && now() >= options.deadlineMs) {
|
|
75289
|
+
if (options.deadlineMs !== void 0 && Date.now() >= options.deadlineMs) {
|
|
75253
75290
|
deadlineReached = true;
|
|
75254
75291
|
if (cursorMs === effectiveStartMs && subWindowCount > 0 && cursorMs < endMs) {
|
|
75255
75292
|
deadlineSkippedSliceStartsMs.push(cursorMs);
|
|
@@ -86928,7 +86965,8 @@ async function apiRoutes(app, opts) {
|
|
|
86928
86965
|
await api.register(telemetryRoutes, {
|
|
86929
86966
|
getTelemetryStatus: opts.getTelemetryStatus,
|
|
86930
86967
|
setTelemetryEnabled: opts.setTelemetryEnabled,
|
|
86931
|
-
recordOnboardingEvent: opts.recordOnboardingEvent
|
|
86968
|
+
recordOnboardingEvent: opts.recordOnboardingEvent,
|
|
86969
|
+
recordUiEvent: opts.recordUiEvent
|
|
86932
86970
|
});
|
|
86933
86971
|
await api.register(feedbackRoutes, {
|
|
86934
86972
|
submitFeedback: opts.submitFeedback
|
|
@@ -88520,6 +88558,7 @@ export {
|
|
|
88520
88558
|
createCredentialChecker,
|
|
88521
88559
|
requireInstanceAdministrator,
|
|
88522
88560
|
hashApiKey,
|
|
88561
|
+
notProbeRun,
|
|
88523
88562
|
registerAgentConversationRoutes,
|
|
88524
88563
|
measurementSlotKey,
|
|
88525
88564
|
measurementRunSlotState,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
siteCrawlGraphNodes,
|
|
6
6
|
siteCrawlPages,
|
|
7
7
|
siteCrawlSnapshots
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-RCQJI3UX.js";
|
|
9
9
|
import {
|
|
10
10
|
SITE_CRAWL_GRAPH_MAX_EDGES,
|
|
11
11
|
SITE_CRAWL_GRAPH_MAX_NODES,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
TEMPLATE_LINK_RATIO_THRESHOLD,
|
|
14
14
|
factorStatusFromScore,
|
|
15
15
|
roundPreservingTotal
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-TY3CJKKR.js";
|
|
17
17
|
|
|
18
18
|
// src/site-audit-factors.ts
|
|
19
19
|
function recordedSharePct(factor) {
|