@ainyc/canonry 1.24.1 → 1.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/assets/index-D1_RT3XF.css +1 -0
- package/assets/assets/index-cbbEFy_S.js +246 -0
- package/assets/index.html +2 -2
- package/dist/{chunk-QMUO2JYU.js → chunk-JEZMB3YG.js} +35 -6
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +6 -6
- package/assets/assets/index-BUzyFRxr.js +0 -246
- package/assets/assets/index-BidvmvWJ.css +0 -1
package/assets/index.html
CHANGED
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
<link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
|
|
13
13
|
<link rel="apple-touch-icon" href="./apple-touch-icon.png" />
|
|
14
14
|
<title>Canonry</title>
|
|
15
|
-
<script type="module" crossorigin src="./assets/index-
|
|
16
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
15
|
+
<script type="module" crossorigin src="./assets/index-cbbEFy_S.js"></script>
|
|
16
|
+
<link rel="stylesheet" crossorigin href="./assets/index-D1_RT3XF.css">
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
19
19
|
<div id="root"></div>
|
|
@@ -3016,7 +3016,8 @@ async function analyticsRoutes(app) {
|
|
|
3016
3016
|
buckets: [],
|
|
3017
3017
|
overall: { citationRate: 0, cited: 0, total: 0 },
|
|
3018
3018
|
byProvider: {},
|
|
3019
|
-
trend: "stable"
|
|
3019
|
+
trend: "stable",
|
|
3020
|
+
keywordChanges: []
|
|
3020
3021
|
});
|
|
3021
3022
|
}
|
|
3022
3023
|
const runIds = projectRuns.map((r) => r.id);
|
|
@@ -3027,6 +3028,8 @@ async function analyticsRoutes(app) {
|
|
|
3027
3028
|
citationState: querySnapshots.citationState,
|
|
3028
3029
|
createdAt: querySnapshots.createdAt
|
|
3029
3030
|
}).from(querySnapshots).where(inArray2(querySnapshots.runId, runIds)).all();
|
|
3031
|
+
const projectKeywords = app.db.select({ id: keywords.id, createdAt: keywords.createdAt }).from(keywords).where(eq10(keywords.projectId, project.id)).all();
|
|
3032
|
+
const keywordCreatedAt = new Map(projectKeywords.map((k) => [k.id, k.createdAt]));
|
|
3030
3033
|
const overall = computeProviderMetric(allSnapshots);
|
|
3031
3034
|
const byProvider = {};
|
|
3032
3035
|
const providers = new Set(allSnapshots.map((s) => s.provider));
|
|
@@ -3037,9 +3040,10 @@ async function analyticsRoutes(app) {
|
|
|
3037
3040
|
const latest = new Date(projectRuns[projectRuns.length - 1].createdAt);
|
|
3038
3041
|
const spanDays = Math.max(1, Math.ceil((latest.getTime() - earliest.getTime()) / 864e5));
|
|
3039
3042
|
const bucketSize = bucketSizeForSpan(spanDays);
|
|
3040
|
-
const buckets = computeBuckets(allSnapshots, projectRuns, bucketSize);
|
|
3043
|
+
const buckets = computeBuckets(allSnapshots, projectRuns, bucketSize, keywordCreatedAt);
|
|
3041
3044
|
const trend = computeTrend(buckets);
|
|
3042
|
-
|
|
3045
|
+
const keywordChanges = computeKeywordChanges(projectKeywords, cutoff);
|
|
3046
|
+
return reply.send({ window, buckets, overall, byProvider, trend, keywordChanges });
|
|
3043
3047
|
});
|
|
3044
3048
|
app.get("/projects/:name/analytics/gaps", async (request, reply) => {
|
|
3045
3049
|
const project = resolveProjectSafe5(app, request.params.name, reply);
|
|
@@ -3231,7 +3235,7 @@ function computeProviderMetric(snapshots) {
|
|
|
3231
3235
|
total
|
|
3232
3236
|
};
|
|
3233
3237
|
}
|
|
3234
|
-
function computeBuckets(snapshots, projectRuns, bucketDays) {
|
|
3238
|
+
function computeBuckets(snapshots, projectRuns, bucketDays, keywordCreatedAt) {
|
|
3235
3239
|
if (projectRuns.length === 0) return [];
|
|
3236
3240
|
const earliest = new Date(projectRuns[0].createdAt);
|
|
3237
3241
|
const latest = new Date(projectRuns[projectRuns.length - 1].createdAt);
|
|
@@ -3245,19 +3249,44 @@ function computeBuckets(snapshots, projectRuns, bucketDays) {
|
|
|
3245
3249
|
const endISO = end.toISOString();
|
|
3246
3250
|
const inBucket = snapshots.filter((s) => s.createdAt >= startISO && s.createdAt < endISO);
|
|
3247
3251
|
if (inBucket.length > 0) {
|
|
3248
|
-
|
|
3252
|
+
let usable = inBucket;
|
|
3253
|
+
if (keywordCreatedAt) {
|
|
3254
|
+
const eligible = inBucket.filter((s) => {
|
|
3255
|
+
const kwCreated = keywordCreatedAt.get(s.keywordId);
|
|
3256
|
+
return kwCreated !== void 0 && kwCreated < startISO;
|
|
3257
|
+
});
|
|
3258
|
+
if (eligible.length > 0) usable = eligible;
|
|
3259
|
+
}
|
|
3260
|
+
const metric = computeProviderMetric(usable);
|
|
3261
|
+
const keywordCount = new Set(usable.map((s) => s.keywordId)).size;
|
|
3249
3262
|
buckets.push({
|
|
3250
3263
|
startDate: startISO,
|
|
3251
3264
|
endDate: endISO,
|
|
3252
3265
|
citationRate: metric.citationRate,
|
|
3253
3266
|
cited: metric.cited,
|
|
3254
|
-
total: metric.total
|
|
3267
|
+
total: metric.total,
|
|
3268
|
+
keywordCount
|
|
3255
3269
|
});
|
|
3256
3270
|
}
|
|
3257
3271
|
start = end;
|
|
3258
3272
|
}
|
|
3259
3273
|
return buckets;
|
|
3260
3274
|
}
|
|
3275
|
+
function computeKeywordChanges(projectKeywords, cutoff) {
|
|
3276
|
+
const byDay = /* @__PURE__ */ new Map();
|
|
3277
|
+
for (const kw of projectKeywords) {
|
|
3278
|
+
if (cutoff && kw.createdAt < cutoff) continue;
|
|
3279
|
+
const day = kw.createdAt.slice(0, 10);
|
|
3280
|
+
byDay.set(day, (byDay.get(day) ?? 0) + 1);
|
|
3281
|
+
}
|
|
3282
|
+
const days = [...byDay.entries()].sort((a, b) => a[0].localeCompare(b[0]));
|
|
3283
|
+
if (days.length <= 1) return [];
|
|
3284
|
+
return days.slice(1).map(([date, count]) => ({
|
|
3285
|
+
date: (/* @__PURE__ */ new Date(date + "T00:00:00.000Z")).toISOString(),
|
|
3286
|
+
delta: count,
|
|
3287
|
+
label: `+${count} kp`
|
|
3288
|
+
}));
|
|
3289
|
+
}
|
|
3261
3290
|
function computeTrend(buckets) {
|
|
3262
3291
|
const nonEmpty = buckets.filter((b) => b.total > 0);
|
|
3263
3292
|
if (nonEmpty.length < 2) return "stable";
|
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": "1.
|
|
3
|
+
"version": "1.25.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The ultimate open-source AEO monitoring tool - track how answer engines cite your domain",
|
|
6
6
|
"license": "FSL-1.1-ALv2",
|
|
@@ -55,15 +55,15 @@
|
|
|
55
55
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
56
56
|
"@ainyc/canonry-config": "0.0.0",
|
|
57
57
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
58
|
-
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
59
58
|
"@ainyc/canonry-db": "0.0.0",
|
|
60
|
-
"@ainyc/canonry-provider-
|
|
59
|
+
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
60
|
+
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
61
61
|
"@ainyc/canonry-provider-local": "0.0.0",
|
|
62
|
-
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
63
62
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
63
|
+
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
64
|
+
"@ainyc/canonry-provider-perplexity": "0.0.0",
|
|
64
65
|
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
65
|
-
"@ainyc/canonry-
|
|
66
|
-
"@ainyc/canonry-provider-perplexity": "0.0.0"
|
|
66
|
+
"@ainyc/canonry-integration-bing": "0.0.0"
|
|
67
67
|
},
|
|
68
68
|
"scripts": {
|
|
69
69
|
"build": "tsup && tsx build-web.ts",
|