@ainyc/canonry 4.27.1 → 4.27.2
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/dist/{chunk-QNXGCQEM.js → chunk-ICWFH4JA.js} +74 -20
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +9 -9
|
@@ -2612,7 +2612,7 @@ function buildCategoryCounts(counts) {
|
|
|
2612
2612
|
}
|
|
2613
2613
|
|
|
2614
2614
|
// ../api-routes/src/intelligence.ts
|
|
2615
|
-
import { eq as eq11, desc as desc4, and as and3 } from "drizzle-orm";
|
|
2615
|
+
import { eq as eq11, desc as desc4, and as and3, inArray as inArray3 } from "drizzle-orm";
|
|
2616
2616
|
function emptyHealthSnapshot(projectId) {
|
|
2617
2617
|
return {
|
|
2618
2618
|
id: `no-data:${projectId}`,
|
|
@@ -2656,6 +2656,44 @@ function mapHealthRow(r) {
|
|
|
2656
2656
|
status: "ready"
|
|
2657
2657
|
};
|
|
2658
2658
|
}
|
|
2659
|
+
function aggregateHealthSnapshots(projectId, rows) {
|
|
2660
|
+
if (rows.length === 1) return mapHealthRow(rows[0]);
|
|
2661
|
+
let totalPairs = 0;
|
|
2662
|
+
let citedPairs = 0;
|
|
2663
|
+
const mergedProviders = {};
|
|
2664
|
+
let newestCreatedAt = "";
|
|
2665
|
+
const runIds = [];
|
|
2666
|
+
for (const row of rows) {
|
|
2667
|
+
totalPairs += row.totalPairs;
|
|
2668
|
+
citedPairs += row.citedPairs;
|
|
2669
|
+
if (row.createdAt > newestCreatedAt) newestCreatedAt = row.createdAt;
|
|
2670
|
+
if (row.runId) runIds.push(row.runId);
|
|
2671
|
+
const providerBreakdown = parseJsonColumn(row.providerBreakdown, {});
|
|
2672
|
+
for (const [provider, entry] of Object.entries(providerBreakdown)) {
|
|
2673
|
+
const existing = mergedProviders[provider] ?? { total: 0, cited: 0, citedRate: 0 };
|
|
2674
|
+
existing.total += entry.total;
|
|
2675
|
+
existing.cited += entry.cited;
|
|
2676
|
+
mergedProviders[provider] = existing;
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
for (const entry of Object.values(mergedProviders)) {
|
|
2680
|
+
entry.citedRate = entry.total > 0 ? entry.cited / entry.total : 0;
|
|
2681
|
+
}
|
|
2682
|
+
const overallCitedRate = totalPairs > 0 ? citedPairs / totalPairs : 0;
|
|
2683
|
+
return {
|
|
2684
|
+
// Synthetic id so consumers can tell this is an aggregate; concatenate
|
|
2685
|
+
// source runIds for traceability without inventing a new schema column.
|
|
2686
|
+
id: `group:${runIds.join(",")}`,
|
|
2687
|
+
projectId,
|
|
2688
|
+
runId: runIds[0] ?? null,
|
|
2689
|
+
overallCitedRate,
|
|
2690
|
+
totalPairs,
|
|
2691
|
+
citedPairs,
|
|
2692
|
+
providerBreakdown: mergedProviders,
|
|
2693
|
+
createdAt: newestCreatedAt,
|
|
2694
|
+
status: "ready"
|
|
2695
|
+
};
|
|
2696
|
+
}
|
|
2659
2697
|
async function intelligenceRoutes(app) {
|
|
2660
2698
|
app.get("/projects/:name/insights", async (request, reply) => {
|
|
2661
2699
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -2687,11 +2725,27 @@ async function intelligenceRoutes(app) {
|
|
|
2687
2725
|
});
|
|
2688
2726
|
app.get("/projects/:name/health/latest", async (request, reply) => {
|
|
2689
2727
|
const project = resolveProject(app.db, request.params.name);
|
|
2690
|
-
const
|
|
2691
|
-
|
|
2728
|
+
const projectVisRuns = app.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(and3(
|
|
2729
|
+
eq11(runs.projectId, project.id),
|
|
2730
|
+
eq11(runs.kind, RunKinds["answer-visibility"]),
|
|
2731
|
+
inArray3(runs.status, [RunStatuses.completed, RunStatuses.partial])
|
|
2732
|
+
)).orderBy(desc4(runs.createdAt), desc4(runs.id)).all();
|
|
2733
|
+
const latestGroup = groupRunsByCreatedAt(projectVisRuns)[0] ?? [];
|
|
2734
|
+
const latestGroupRunIds = latestGroup.map((r) => r.id);
|
|
2735
|
+
if (latestGroupRunIds.length > 0) {
|
|
2736
|
+
const groupRows = app.db.select().from(healthSnapshots).where(and3(
|
|
2737
|
+
eq11(healthSnapshots.projectId, project.id),
|
|
2738
|
+
inArray3(healthSnapshots.runId, latestGroupRunIds)
|
|
2739
|
+
)).all();
|
|
2740
|
+
if (groupRows.length > 0) {
|
|
2741
|
+
return reply.send(aggregateHealthSnapshots(project.id, groupRows));
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
const fallback = app.db.select().from(healthSnapshots).where(eq11(healthSnapshots.projectId, project.id)).orderBy(desc4(healthSnapshots.createdAt)).limit(1).get();
|
|
2745
|
+
if (!fallback) {
|
|
2692
2746
|
return reply.send(emptyHealthSnapshot(project.id));
|
|
2693
2747
|
}
|
|
2694
|
-
return reply.send(mapHealthRow(
|
|
2748
|
+
return reply.send(mapHealthRow(fallback));
|
|
2695
2749
|
});
|
|
2696
2750
|
app.get("/projects/:name/health/history", async (request, reply) => {
|
|
2697
2751
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -2703,7 +2757,7 @@ async function intelligenceRoutes(app) {
|
|
|
2703
2757
|
}
|
|
2704
2758
|
|
|
2705
2759
|
// ../api-routes/src/report.ts
|
|
2706
|
-
import { and as and5, desc as desc6, eq as eq13, gte, inArray as
|
|
2760
|
+
import { and as and5, desc as desc6, eq as eq13, gte, inArray as inArray5, lt, lte, ne, or as or2, sql as sql3 } from "drizzle-orm";
|
|
2707
2761
|
|
|
2708
2762
|
// ../api-routes/src/report-renderer.ts
|
|
2709
2763
|
var COLORS = {
|
|
@@ -4939,7 +4993,7 @@ function renderReportHtml(report, opts = {}) {
|
|
|
4939
4993
|
}
|
|
4940
4994
|
|
|
4941
4995
|
// ../api-routes/src/content-data.ts
|
|
4942
|
-
import { and as and4, eq as eq12, desc as desc5, inArray as
|
|
4996
|
+
import { and as and4, eq as eq12, desc as desc5, inArray as inArray4 } from "drizzle-orm";
|
|
4943
4997
|
var RECENT_RUNS_WINDOW = 5;
|
|
4944
4998
|
function loadOrchestratorInput(db, project, locationFilter = void 0) {
|
|
4945
4999
|
const projectId = project.id;
|
|
@@ -5069,7 +5123,7 @@ function listRecentAnswerVisibilityRunIds(db, projectId, limit, locationFilter)
|
|
|
5069
5123
|
// Queued/running/failed/cancelled runs may have partial or no
|
|
5070
5124
|
// snapshots; including them risks pointing latestRunId at a run with
|
|
5071
5125
|
// no usable evidence.
|
|
5072
|
-
|
|
5126
|
+
inArray4(runs.status, [RunStatuses.completed, RunStatuses.partial])
|
|
5073
5127
|
)
|
|
5074
5128
|
).orderBy(desc5(runs.createdAt)).all();
|
|
5075
5129
|
const filtered = locationFilter === void 0 ? rows : rows.filter((r) => (r.location ?? null) === locationFilter);
|
|
@@ -5111,7 +5165,7 @@ function buildCandidateQueries(opts) {
|
|
|
5111
5165
|
const queryRows = opts.db.select({ id: queries.id, text: queries.query }).from(queries).where(eq12(queries.projectId, opts.projectId)).all();
|
|
5112
5166
|
const queryIdByText = new Map(queryRows.map((r) => [r.text, r.id]));
|
|
5113
5167
|
const candidateQueryIds = opts.candidateQueryStrings.map((q) => queryIdByText.get(q)).filter((id) => Boolean(id));
|
|
5114
|
-
const snapshotRows = opts.db.select().from(querySnapshots).where(
|
|
5168
|
+
const snapshotRows = opts.db.select().from(querySnapshots).where(inArray4(querySnapshots.runId, opts.recentRunIds)).all().filter((r) => candidateQueryIds.includes(r.queryId));
|
|
5115
5169
|
const snapshotsByQuery = /* @__PURE__ */ new Map();
|
|
5116
5170
|
for (const row of snapshotRows) {
|
|
5117
5171
|
const list = snapshotsByQuery.get(row.queryId) ?? [];
|
|
@@ -5329,7 +5383,7 @@ function loadSnapshotsForRun(db, runId) {
|
|
|
5329
5383
|
}
|
|
5330
5384
|
function loadSnapshotsForRunIds(db, runIds) {
|
|
5331
5385
|
if (runIds.length === 0) return [];
|
|
5332
|
-
const rows = db.select().from(querySnapshots).where(
|
|
5386
|
+
const rows = db.select().from(querySnapshots).where(inArray5(querySnapshots.runId, [...runIds])).all();
|
|
5333
5387
|
return rows.map((r) => ({
|
|
5334
5388
|
id: r.id,
|
|
5335
5389
|
runId: r.runId,
|
|
@@ -5909,7 +5963,7 @@ function buildInsightList(db, projectId, locationFilter) {
|
|
|
5909
5963
|
)
|
|
5910
5964
|
).orderBy(desc6(runs.createdAt)).all().filter((r) => locationFilter === void 0 || (r.location ?? null) === locationFilter).slice(0, INSIGHT_LOOKBACK_RUNS).map((r) => r.id);
|
|
5911
5965
|
if (recentRunIds.length === 0) return [];
|
|
5912
|
-
const rows = db.select().from(insights).where(and5(eq13(insights.projectId, projectId),
|
|
5966
|
+
const rows = db.select().from(insights).where(and5(eq13(insights.projectId, projectId), inArray5(insights.runId, recentRunIds))).orderBy(desc6(insights.createdAt)).all();
|
|
5913
5967
|
const severityRank = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
5914
5968
|
const flat = rows.filter((r) => !r.dismissed).map((r) => {
|
|
5915
5969
|
const recommendation = parseJsonColumn(r.recommendation, null);
|
|
@@ -6671,7 +6725,7 @@ async function reportRoutes(app) {
|
|
|
6671
6725
|
}
|
|
6672
6726
|
|
|
6673
6727
|
// ../api-routes/src/citations.ts
|
|
6674
|
-
import { eq as eq14, inArray as
|
|
6728
|
+
import { eq as eq14, inArray as inArray6 } from "drizzle-orm";
|
|
6675
6729
|
async function citationRoutes(app) {
|
|
6676
6730
|
app.get("/projects/:name/citations/visibility", async (request, reply) => {
|
|
6677
6731
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -6695,7 +6749,7 @@ async function citationRoutes(app) {
|
|
|
6695
6749
|
competitorOverlap: querySnapshots.competitorOverlap,
|
|
6696
6750
|
answerMentioned: querySnapshots.answerMentioned,
|
|
6697
6751
|
createdAt: querySnapshots.createdAt
|
|
6698
|
-
}).from(querySnapshots).where(
|
|
6752
|
+
}).from(querySnapshots).where(inArray6(querySnapshots.runId, projectRuns.map((r) => r.id))).all();
|
|
6699
6753
|
if (rawSnapshots.length === 0) {
|
|
6700
6754
|
return reply.send(emptyCitationVisibility("no-runs-yet"));
|
|
6701
6755
|
}
|
|
@@ -6835,7 +6889,7 @@ function normalizeDomain2(domain) {
|
|
|
6835
6889
|
}
|
|
6836
6890
|
|
|
6837
6891
|
// ../api-routes/src/composites.ts
|
|
6838
|
-
import { eq as eq15, and as and6, desc as desc7, sql as sql4, like, or as or3, inArray as
|
|
6892
|
+
import { eq as eq15, and as and6, desc as desc7, sql as sql4, like, or as or3, inArray as inArray7 } from "drizzle-orm";
|
|
6839
6893
|
var TOP_INSIGHT_LIMIT = 5;
|
|
6840
6894
|
var SEARCH_HIT_HARD_LIMIT = 50;
|
|
6841
6895
|
var SEARCH_SNIPPET_RADIUS = 80;
|
|
@@ -7040,7 +7094,7 @@ function loadSnapshotsByRunIds(app, runIds) {
|
|
|
7040
7094
|
citationState: querySnapshots.citationState,
|
|
7041
7095
|
competitorOverlap: querySnapshots.competitorOverlap,
|
|
7042
7096
|
citedDomains: querySnapshots.citedDomains
|
|
7043
|
-
}).from(querySnapshots).where(
|
|
7097
|
+
}).from(querySnapshots).where(inArray7(querySnapshots.runId, [...runIds])).all();
|
|
7044
7098
|
for (const row of rows) {
|
|
7045
7099
|
const list = result.get(row.runId) ?? [];
|
|
7046
7100
|
list.push({
|
|
@@ -22614,7 +22668,7 @@ import crypto24 from "crypto";
|
|
|
22614
22668
|
import fs7 from "fs";
|
|
22615
22669
|
import path9 from "path";
|
|
22616
22670
|
import os5 from "os";
|
|
22617
|
-
import { and as and16, eq as eq27, inArray as
|
|
22671
|
+
import { and as and16, eq as eq27, inArray as inArray8, sql as sql10 } from "drizzle-orm";
|
|
22618
22672
|
|
|
22619
22673
|
// src/run-telemetry.ts
|
|
22620
22674
|
import crypto23 from "crypto";
|
|
@@ -22955,7 +23009,7 @@ var JobRunner = class {
|
|
|
22955
23009
|
this.registry = registry;
|
|
22956
23010
|
}
|
|
22957
23011
|
recoverStaleRuns() {
|
|
22958
|
-
const stale = this.db.select({ id: runs.id, status: runs.status }).from(runs).where(
|
|
23012
|
+
const stale = this.db.select({ id: runs.id, status: runs.status }).from(runs).where(inArray8(runs.status, ["running", "queued"])).all();
|
|
22959
23013
|
if (stale.length === 0) return;
|
|
22960
23014
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
22961
23015
|
for (const run of stale) {
|
|
@@ -23018,7 +23072,7 @@ var JobRunner = class {
|
|
|
23018
23072
|
}
|
|
23019
23073
|
log.info("run.dispatch", { runId, providerCount: activeProviders.length, providers: activeProviders.map((p) => p.adapter.name) });
|
|
23020
23074
|
const scopedQueryNames = parseJsonColumn(existingRun.queries, null);
|
|
23021
|
-
projectQueries = scopedQueryNames ? this.db.select().from(queries).where(and16(eq27(queries.projectId, projectId),
|
|
23075
|
+
projectQueries = scopedQueryNames ? this.db.select().from(queries).where(and16(eq27(queries.projectId, projectId), inArray8(queries.query, scopedQueryNames))).all() : this.db.select().from(queries).where(eq27(queries.projectId, projectId)).all();
|
|
23022
23076
|
const projectCompetitors = this.db.select().from(competitors).where(eq27(competitors.projectId, projectId)).all();
|
|
23023
23077
|
const competitorDomains = projectCompetitors.map((c) => c.domain);
|
|
23024
23078
|
const allDomains = effectiveDomains({
|
|
@@ -24672,7 +24726,7 @@ var Scheduler = class {
|
|
|
24672
24726
|
};
|
|
24673
24727
|
|
|
24674
24728
|
// src/notifier.ts
|
|
24675
|
-
import { eq as eq35, desc as desc16, and as and22, inArray as
|
|
24729
|
+
import { eq as eq35, desc as desc16, and as and22, inArray as inArray9, or as or4 } from "drizzle-orm";
|
|
24676
24730
|
import crypto31 from "crypto";
|
|
24677
24731
|
var log10 = createLogger("Notifier");
|
|
24678
24732
|
var Notifier = class {
|
|
@@ -24825,13 +24879,13 @@ var Notifier = class {
|
|
|
24825
24879
|
provider: querySnapshots.provider,
|
|
24826
24880
|
location: querySnapshots.location,
|
|
24827
24881
|
citationState: querySnapshots.citationState
|
|
24828
|
-
}).from(querySnapshots).leftJoin(queries, eq35(querySnapshots.queryId, queries.id)).where(
|
|
24882
|
+
}).from(querySnapshots).leftJoin(queries, eq35(querySnapshots.queryId, queries.id)).where(inArray9(querySnapshots.runId, currentRunIds)).all();
|
|
24829
24883
|
const previousSnapshots = this.db.select({
|
|
24830
24884
|
queryId: querySnapshots.queryId,
|
|
24831
24885
|
provider: querySnapshots.provider,
|
|
24832
24886
|
location: querySnapshots.location,
|
|
24833
24887
|
citationState: querySnapshots.citationState
|
|
24834
|
-
}).from(querySnapshots).where(
|
|
24888
|
+
}).from(querySnapshots).where(inArray9(querySnapshots.runId, previousRunIds)).all();
|
|
24835
24889
|
const prevMap = /* @__PURE__ */ new Map();
|
|
24836
24890
|
for (const s of previousSnapshots) {
|
|
24837
24891
|
prevMap.set(`${s.queryId}:${s.provider}:${s.location ?? ""}`, s.citationState);
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "4.27.
|
|
3
|
+
"version": "4.27.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Agent-first open-source AEO operating platform - track how answer engines cite your domain",
|
|
6
6
|
"license": "FSL-1.1-ALv2",
|
|
@@ -60,22 +60,22 @@
|
|
|
60
60
|
"tsup": "^8.5.1",
|
|
61
61
|
"tsx": "^4.19.0",
|
|
62
62
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
63
|
-
"@ainyc/canonry-config": "0.0.0",
|
|
64
63
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
65
|
-
"@ainyc/canonry-
|
|
66
|
-
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
67
|
-
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
68
|
-
"@ainyc/canonry-integration-google": "0.0.0",
|
|
64
|
+
"@ainyc/canonry-config": "0.0.0",
|
|
69
65
|
"@ainyc/canonry-intelligence": "0.0.0",
|
|
70
66
|
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
67
|
+
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
68
|
+
"@ainyc/canonry-db": "0.0.0",
|
|
69
|
+
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
71
70
|
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
72
|
-
"@ainyc/canonry-
|
|
71
|
+
"@ainyc/canonry-integration-google": "0.0.0",
|
|
73
72
|
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
73
|
+
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
74
74
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
75
|
+
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
75
76
|
"@ainyc/canonry-provider-local": "0.0.0",
|
|
76
|
-
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
77
77
|
"@ainyc/canonry-provider-perplexity": "0.0.0",
|
|
78
|
-
"@ainyc/canonry-provider-
|
|
78
|
+
"@ainyc/canonry-provider-openai": "0.0.0"
|
|
79
79
|
},
|
|
80
80
|
"scripts": {
|
|
81
81
|
"build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",
|