@ainyc/canonry 3.2.0 → 3.2.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/assets/assets/index-B8epngdo.js +302 -0
- package/assets/assets/index-CQGbgHZY.css +1 -0
- package/assets/index.html +2 -2
- package/dist/{chunk-33ATDBGM.js → chunk-QA5HRDRS.js} +110 -23
- package/dist/{chunk-YGIWXQGM.js → chunk-TBFRAJU2.js} +23 -4
- package/dist/cli.js +30 -14
- package/dist/index.js +2 -2
- package/dist/mcp.js +1 -1
- package/package.json +4 -4
- package/assets/assets/index-DZm9xxNs.css +0 -1
- package/assets/assets/index-Z2rYL3K8.js +0 -302
|
@@ -62,7 +62,7 @@ import {
|
|
|
62
62
|
visibilityStateFromAnswerMentioned,
|
|
63
63
|
windowCutoff,
|
|
64
64
|
wordpressEnvSchema
|
|
65
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-TBFRAJU2.js";
|
|
66
66
|
import {
|
|
67
67
|
IntelligenceService,
|
|
68
68
|
agentMemory,
|
|
@@ -8694,6 +8694,13 @@ function gaLog(level, action, ctx) {
|
|
|
8694
8694
|
const stream = level === "error" ? process.stderr : process.stdout;
|
|
8695
8695
|
stream.write(JSON.stringify(entry) + "\n");
|
|
8696
8696
|
}
|
|
8697
|
+
function formatSharePct(numerator, total) {
|
|
8698
|
+
if (total <= 0 || numerator <= 0) return "0%";
|
|
8699
|
+
const pct = numerator / total * 100;
|
|
8700
|
+
const rounded = Math.round(pct);
|
|
8701
|
+
if (rounded === 0) return "<1%";
|
|
8702
|
+
return `${rounded}%`;
|
|
8703
|
+
}
|
|
8697
8704
|
async function refreshOAuthTokenIfNeeded(googleStore, authConfig, canonicalDomain, oauthConn) {
|
|
8698
8705
|
const expiresAt = oauthConn.tokenExpiresAt ? new Date(oauthConn.tokenExpiresAt).getTime() : 0;
|
|
8699
8706
|
const fiveMinutes = 5 * 60 * 1e3;
|
|
@@ -9179,6 +9186,11 @@ async function ga4Routes(app, opts) {
|
|
|
9179
9186
|
aiSharePctBySession: total > 0 ? Math.round((aiBySession?.sessions ?? 0) / total * 100) : 0,
|
|
9180
9187
|
directSharePct: total > 0 ? Math.round(totalDirectSessions / total * 100) : 0,
|
|
9181
9188
|
socialSharePct: total > 0 ? Math.round((socialTotals?.sessions ?? 0) / total * 100) : 0,
|
|
9189
|
+
organicSharePctDisplay: formatSharePct(summaryRow?.totalOrganicSessions ?? 0, total),
|
|
9190
|
+
aiSharePctDisplay: formatSharePct(aiDeduped?.sessions ?? 0, total),
|
|
9191
|
+
aiSharePctBySessionDisplay: formatSharePct(aiBySession?.sessions ?? 0, total),
|
|
9192
|
+
directSharePctDisplay: formatSharePct(totalDirectSessions, total),
|
|
9193
|
+
socialSharePctDisplay: formatSharePct(socialTotals?.sessions ?? 0, total),
|
|
9182
9194
|
lastSyncedAt: latestSync?.syncedAt ?? null,
|
|
9183
9195
|
periodStart: (() => {
|
|
9184
9196
|
const start = cutoffDate ?? summaryMeta?.periodStart ?? null;
|
|
@@ -11021,7 +11033,7 @@ async function wordpressRoutes(app, opts) {
|
|
|
11021
11033
|
|
|
11022
11034
|
// ../api-routes/src/backlinks.ts
|
|
11023
11035
|
import crypto18 from "crypto";
|
|
11024
|
-
import { and as
|
|
11036
|
+
import { and as and10, asc as asc2, desc as desc10, eq as eq21, sql as sql6 } from "drizzle-orm";
|
|
11025
11037
|
|
|
11026
11038
|
// ../integration-commoncrawl/src/constants.ts
|
|
11027
11039
|
import os2 from "os";
|
|
@@ -11417,6 +11429,35 @@ function pruneCachedRelease(release, opts = {}) {
|
|
|
11417
11429
|
fs5.rmSync(dir, { recursive: true, force: true });
|
|
11418
11430
|
}
|
|
11419
11431
|
|
|
11432
|
+
// ../api-routes/src/backlinks-filter.ts
|
|
11433
|
+
import { and as and9, ne, notLike } from "drizzle-orm";
|
|
11434
|
+
var BACKLINK_FILTER_PATTERNS = [
|
|
11435
|
+
"*.google.com",
|
|
11436
|
+
"*.googleusercontent.com",
|
|
11437
|
+
"*.translate.goog",
|
|
11438
|
+
"*.bing.com",
|
|
11439
|
+
"*.yandex.com",
|
|
11440
|
+
"*.yandex.ru",
|
|
11441
|
+
"*.baidu.com",
|
|
11442
|
+
"*.duckduckgo.com",
|
|
11443
|
+
"*.archive.org"
|
|
11444
|
+
];
|
|
11445
|
+
function backlinkCrawlerExclusionClause() {
|
|
11446
|
+
const conditions = [];
|
|
11447
|
+
for (const pattern of BACKLINK_FILTER_PATTERNS) {
|
|
11448
|
+
if (pattern.startsWith("*.")) {
|
|
11449
|
+
const suffix = pattern.slice(2);
|
|
11450
|
+
conditions.push(ne(backlinkDomains.linkingDomain, suffix));
|
|
11451
|
+
conditions.push(notLike(backlinkDomains.linkingDomain, `%.${suffix}`));
|
|
11452
|
+
} else {
|
|
11453
|
+
conditions.push(ne(backlinkDomains.linkingDomain, pattern));
|
|
11454
|
+
}
|
|
11455
|
+
}
|
|
11456
|
+
const combined = and9(...conditions);
|
|
11457
|
+
if (!combined) throw new Error("BACKLINK_FILTER_PATTERNS is unexpectedly empty");
|
|
11458
|
+
return combined;
|
|
11459
|
+
}
|
|
11460
|
+
|
|
11420
11461
|
// ../api-routes/src/backlinks.ts
|
|
11421
11462
|
var BACKLINKS_UNSUPPORTED_MESSAGE = "Backlinks sync and install are only available from a local canonry install. Run `canonry backlinks install` locally to use this feature.";
|
|
11422
11463
|
var NON_TERMINAL_SYNC_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -11473,9 +11514,47 @@ function mapRunRow(row) {
|
|
|
11473
11514
|
};
|
|
11474
11515
|
}
|
|
11475
11516
|
function latestSummaryForProject(db, projectId, release) {
|
|
11476
|
-
const condition = release ?
|
|
11517
|
+
const condition = release ? and10(eq21(backlinkSummaries.projectId, projectId), eq21(backlinkSummaries.release, release)) : eq21(backlinkSummaries.projectId, projectId);
|
|
11477
11518
|
return db.select().from(backlinkSummaries).where(condition).orderBy(desc10(backlinkSummaries.queriedAt)).limit(1).get();
|
|
11478
11519
|
}
|
|
11520
|
+
function parseExcludeCrawlers(value) {
|
|
11521
|
+
if (!value) return false;
|
|
11522
|
+
const lower = value.toLowerCase();
|
|
11523
|
+
return lower === "1" || lower === "true" || lower === "yes";
|
|
11524
|
+
}
|
|
11525
|
+
function computeFilteredSummary(db, base) {
|
|
11526
|
+
const baseDomainCondition = and10(
|
|
11527
|
+
eq21(backlinkDomains.projectId, base.projectId),
|
|
11528
|
+
eq21(backlinkDomains.release, base.release)
|
|
11529
|
+
);
|
|
11530
|
+
const filteredCondition = and10(baseDomainCondition, backlinkCrawlerExclusionClause());
|
|
11531
|
+
const unfilteredAgg = db.select({
|
|
11532
|
+
count: sql6`count(*)`,
|
|
11533
|
+
total: sql6`coalesce(sum(${backlinkDomains.numHosts}), 0)`
|
|
11534
|
+
}).from(backlinkDomains).where(baseDomainCondition).get();
|
|
11535
|
+
const filteredAgg = db.select({
|
|
11536
|
+
count: sql6`count(*)`,
|
|
11537
|
+
total: sql6`coalesce(sum(${backlinkDomains.numHosts}), 0)`
|
|
11538
|
+
}).from(backlinkDomains).where(filteredCondition).get();
|
|
11539
|
+
const top10Rows = db.select({ numHosts: backlinkDomains.numHosts }).from(backlinkDomains).where(filteredCondition).orderBy(desc10(backlinkDomains.numHosts)).limit(10).all();
|
|
11540
|
+
const totalLinkingDomains = Number(filteredAgg?.count ?? 0);
|
|
11541
|
+
const totalHosts = Number(filteredAgg?.total ?? 0);
|
|
11542
|
+
const unfilteredLinkingDomains = Number(unfilteredAgg?.count ?? 0);
|
|
11543
|
+
const unfilteredHosts = Number(unfilteredAgg?.total ?? 0);
|
|
11544
|
+
const top10Sum = top10Rows.reduce((sum, r) => sum + r.numHosts, 0);
|
|
11545
|
+
const top10Share = totalHosts > 0 ? top10Sum / totalHosts : 0;
|
|
11546
|
+
return {
|
|
11547
|
+
projectId: base.projectId,
|
|
11548
|
+
release: base.release,
|
|
11549
|
+
targetDomain: base.targetDomain,
|
|
11550
|
+
totalLinkingDomains,
|
|
11551
|
+
totalHosts,
|
|
11552
|
+
top10HostsShare: top10Share.toFixed(6),
|
|
11553
|
+
queriedAt: base.queriedAt,
|
|
11554
|
+
excludedLinkingDomains: Math.max(0, unfilteredLinkingDomains - totalLinkingDomains),
|
|
11555
|
+
excludedHosts: Math.max(0, unfilteredHosts - totalHosts)
|
|
11556
|
+
};
|
|
11557
|
+
}
|
|
11479
11558
|
async function backlinksRoutes(app, opts) {
|
|
11480
11559
|
app.get("/backlinks/status", async (_request, reply) => {
|
|
11481
11560
|
if (!opts.getBacklinksStatus) {
|
|
@@ -11608,7 +11687,9 @@ async function backlinksRoutes(app, opts) {
|
|
|
11608
11687
|
async (request, reply) => {
|
|
11609
11688
|
const project = resolveProject(app.db, request.params.name);
|
|
11610
11689
|
const row = latestSummaryForProject(app.db, project.id, request.query.release);
|
|
11611
|
-
return reply.send(
|
|
11690
|
+
if (!row) return reply.send(null);
|
|
11691
|
+
const excludeCrawlers = parseExcludeCrawlers(request.query.excludeCrawlers);
|
|
11692
|
+
return reply.send(excludeCrawlers ? computeFilteredSummary(app.db, row) : mapSummaryRow(row));
|
|
11612
11693
|
}
|
|
11613
11694
|
);
|
|
11614
11695
|
app.get("/projects/:name/backlinks/domains", async (request, reply) => {
|
|
@@ -11621,17 +11702,23 @@ async function backlinksRoutes(app, opts) {
|
|
|
11621
11702
|
}
|
|
11622
11703
|
const limit = Math.min(Math.max(parseInt(request.query.limit ?? "50", 10) || 50, 1), 500);
|
|
11623
11704
|
const offset = Math.max(parseInt(request.query.offset ?? "0", 10) || 0, 0);
|
|
11624
|
-
const
|
|
11705
|
+
const excludeCrawlers = parseExcludeCrawlers(request.query.excludeCrawlers);
|
|
11706
|
+
const baseDomainCondition = and10(
|
|
11625
11707
|
eq21(backlinkDomains.projectId, project.id),
|
|
11626
11708
|
eq21(backlinkDomains.release, targetRelease)
|
|
11627
11709
|
);
|
|
11710
|
+
const domainCondition = excludeCrawlers ? and10(baseDomainCondition, backlinkCrawlerExclusionClause()) : baseDomainCondition;
|
|
11628
11711
|
const totalRow = app.db.select({ count: sql6`count(*)` }).from(backlinkDomains).where(domainCondition).get();
|
|
11629
11712
|
const rows = app.db.select({
|
|
11630
11713
|
linkingDomain: backlinkDomains.linkingDomain,
|
|
11631
11714
|
numHosts: backlinkDomains.numHosts
|
|
11632
11715
|
}).from(backlinkDomains).where(domainCondition).orderBy(desc10(backlinkDomains.numHosts)).limit(limit).offset(offset).all();
|
|
11716
|
+
let summary = null;
|
|
11717
|
+
if (summaryRow) {
|
|
11718
|
+
summary = excludeCrawlers ? computeFilteredSummary(app.db, summaryRow) : mapSummaryRow(summaryRow);
|
|
11719
|
+
}
|
|
11633
11720
|
const response = {
|
|
11634
|
-
summary
|
|
11721
|
+
summary,
|
|
11635
11722
|
total: Number(totalRow?.count ?? 0),
|
|
11636
11723
|
rows
|
|
11637
11724
|
};
|
|
@@ -14985,7 +15072,7 @@ import crypto19 from "crypto";
|
|
|
14985
15072
|
import fs7 from "fs";
|
|
14986
15073
|
import path9 from "path";
|
|
14987
15074
|
import os4 from "os";
|
|
14988
|
-
import { and as
|
|
15075
|
+
import { and as and11, eq as eq22, inArray as inArray5, sql as sql7 } from "drizzle-orm";
|
|
14989
15076
|
|
|
14990
15077
|
// src/citation-utils.ts
|
|
14991
15078
|
function domainMatches(domain, canonicalDomain) {
|
|
@@ -15269,7 +15356,7 @@ var JobRunner = class {
|
|
|
15269
15356
|
throw new Error(`Run ${runId} is not executable from status '${existingRun.status}'`);
|
|
15270
15357
|
}
|
|
15271
15358
|
if (existingRun.status === "queued") {
|
|
15272
|
-
this.db.update(runs).set({ status: "running", startedAt: now }).where(
|
|
15359
|
+
this.db.update(runs).set({ status: "running", startedAt: now }).where(and11(eq22(runs.id, runId), eq22(runs.status, "queued"))).run();
|
|
15273
15360
|
}
|
|
15274
15361
|
this.throwIfRunCancelled(runId);
|
|
15275
15362
|
const project = this.db.select().from(projects).where(eq22(projects.id, projectId)).get();
|
|
@@ -15572,7 +15659,7 @@ function getCurrentUsageDay() {
|
|
|
15572
15659
|
|
|
15573
15660
|
// src/gsc-sync.ts
|
|
15574
15661
|
import crypto20 from "crypto";
|
|
15575
|
-
import { eq as eq23, and as
|
|
15662
|
+
import { eq as eq23, and as and12, sql as sql8 } from "drizzle-orm";
|
|
15576
15663
|
var log2 = createLogger("GscSync");
|
|
15577
15664
|
function formatDate2(d) {
|
|
15578
15665
|
return d.toISOString().split("T")[0];
|
|
@@ -15624,7 +15711,7 @@ async function executeGscSync(db, runId, projectId, opts) {
|
|
|
15624
15711
|
});
|
|
15625
15712
|
log2.info("fetch.complete", { runId, projectId, rowCount: rows.length });
|
|
15626
15713
|
db.delete(gscSearchData).where(
|
|
15627
|
-
|
|
15714
|
+
and12(
|
|
15628
15715
|
eq23(gscSearchData.projectId, projectId),
|
|
15629
15716
|
sql8`${gscSearchData.date} >= ${startDate}`,
|
|
15630
15717
|
sql8`${gscSearchData.date} <= ${endDate}`
|
|
@@ -15713,7 +15800,7 @@ async function executeGscSync(db, runId, projectId, opts) {
|
|
|
15713
15800
|
}
|
|
15714
15801
|
}
|
|
15715
15802
|
const snapshotDate = formatDate2(/* @__PURE__ */ new Date());
|
|
15716
|
-
db.delete(gscCoverageSnapshots).where(
|
|
15803
|
+
db.delete(gscCoverageSnapshots).where(and12(eq23(gscCoverageSnapshots.projectId, projectId), eq23(gscCoverageSnapshots.date, snapshotDate))).run();
|
|
15717
15804
|
db.insert(gscCoverageSnapshots).values({
|
|
15718
15805
|
id: crypto20.randomUUID(),
|
|
15719
15806
|
projectId,
|
|
@@ -15736,7 +15823,7 @@ async function executeGscSync(db, runId, projectId, opts) {
|
|
|
15736
15823
|
|
|
15737
15824
|
// src/gsc-inspect-sitemap.ts
|
|
15738
15825
|
import crypto21 from "crypto";
|
|
15739
|
-
import { eq as eq24, and as
|
|
15826
|
+
import { eq as eq24, and as and13 } from "drizzle-orm";
|
|
15740
15827
|
|
|
15741
15828
|
// src/sitemap-parser.ts
|
|
15742
15829
|
var log3 = createLogger("SitemapParser");
|
|
@@ -15952,7 +16039,7 @@ async function executeInspectSitemap(db, runId, projectId, opts) {
|
|
|
15952
16039
|
}
|
|
15953
16040
|
}
|
|
15954
16041
|
const snapshotDate = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
15955
|
-
db.delete(gscCoverageSnapshots).where(
|
|
16042
|
+
db.delete(gscCoverageSnapshots).where(and13(eq24(gscCoverageSnapshots.projectId, projectId), eq24(gscCoverageSnapshots.date, snapshotDate))).run();
|
|
15956
16043
|
db.insert(gscCoverageSnapshots).values({
|
|
15957
16044
|
id: crypto21.randomUUID(),
|
|
15958
16045
|
projectId,
|
|
@@ -16163,7 +16250,7 @@ async function executeBingInspectSitemap(db, runId, projectId, opts) {
|
|
|
16163
16250
|
// src/commoncrawl-sync.ts
|
|
16164
16251
|
import crypto23 from "crypto";
|
|
16165
16252
|
import path10 from "path";
|
|
16166
|
-
import { and as
|
|
16253
|
+
import { and as and14, eq as eq26, sql as sql9 } from "drizzle-orm";
|
|
16167
16254
|
var log6 = createLogger("CommonCrawlSync");
|
|
16168
16255
|
var INSERT_CHUNK_SIZE = 1e4;
|
|
16169
16256
|
function defaultDeps() {
|
|
@@ -16354,7 +16441,7 @@ function computeSummary(rows) {
|
|
|
16354
16441
|
// src/backlink-extract.ts
|
|
16355
16442
|
import crypto24 from "crypto";
|
|
16356
16443
|
import fs8 from "fs";
|
|
16357
|
-
import { and as
|
|
16444
|
+
import { and as and15, desc as desc12, eq as eq27 } from "drizzle-orm";
|
|
16358
16445
|
var log7 = createLogger("BacklinkExtract");
|
|
16359
16446
|
function defaultDeps2() {
|
|
16360
16447
|
return {
|
|
@@ -16400,7 +16487,7 @@ async function executeBacklinkExtract(db, runId, projectId, opts = {}) {
|
|
|
16400
16487
|
const targetDomain = project.canonicalDomain;
|
|
16401
16488
|
db.transaction((tx) => {
|
|
16402
16489
|
tx.delete(backlinkDomains).where(
|
|
16403
|
-
|
|
16490
|
+
and15(eq27(backlinkDomains.projectId, projectId), eq27(backlinkDomains.release, release))
|
|
16404
16491
|
).run();
|
|
16405
16492
|
if (rows.length > 0) {
|
|
16406
16493
|
const values = rows.map((r) => ({
|
|
@@ -16656,7 +16743,7 @@ var Scheduler = class {
|
|
|
16656
16743
|
};
|
|
16657
16744
|
|
|
16658
16745
|
// src/notifier.ts
|
|
16659
|
-
import { eq as eq29, desc as desc13, and as
|
|
16746
|
+
import { eq as eq29, desc as desc13, and as and16, or as or3 } from "drizzle-orm";
|
|
16660
16747
|
import crypto25 from "crypto";
|
|
16661
16748
|
var log9 = createLogger("Notifier");
|
|
16662
16749
|
var Notifier = class {
|
|
@@ -16762,7 +16849,7 @@ var Notifier = class {
|
|
|
16762
16849
|
}
|
|
16763
16850
|
computeTransitions(runId, projectId) {
|
|
16764
16851
|
const recentRuns = this.db.select().from(runs).where(
|
|
16765
|
-
|
|
16852
|
+
and16(
|
|
16766
16853
|
eq29(runs.projectId, projectId),
|
|
16767
16854
|
or3(eq29(runs.status, "completed"), eq29(runs.status, "partial"))
|
|
16768
16855
|
)
|
|
@@ -17248,7 +17335,7 @@ function resolveSessionProviderAndModel(config, opts) {
|
|
|
17248
17335
|
|
|
17249
17336
|
// src/agent/memory-store.ts
|
|
17250
17337
|
import crypto26 from "crypto";
|
|
17251
|
-
import { and as
|
|
17338
|
+
import { and as and17, desc as desc14, eq as eq30, like as like2, sql as sql10 } from "drizzle-orm";
|
|
17252
17339
|
var COMPACTION_KEY_PREFIX = "compaction:";
|
|
17253
17340
|
var COMPACTION_NOTES_PER_SESSION = 3;
|
|
17254
17341
|
function rowToDto(row) {
|
|
@@ -17293,12 +17380,12 @@ function upsertMemoryEntry(db, args) {
|
|
|
17293
17380
|
updatedAt: now
|
|
17294
17381
|
}
|
|
17295
17382
|
}).run();
|
|
17296
|
-
const row = db.select().from(agentMemory).where(
|
|
17383
|
+
const row = db.select().from(agentMemory).where(and17(eq30(agentMemory.projectId, args.projectId), eq30(agentMemory.key, args.key))).get();
|
|
17297
17384
|
if (!row) throw new Error("memory upsert produced no row");
|
|
17298
17385
|
return rowToDto(row);
|
|
17299
17386
|
}
|
|
17300
17387
|
function deleteMemoryEntry(db, projectId, key) {
|
|
17301
|
-
const result = db.delete(agentMemory).where(
|
|
17388
|
+
const result = db.delete(agentMemory).where(and17(eq30(agentMemory.projectId, projectId), eq30(agentMemory.key, key))).run();
|
|
17302
17389
|
const changes = result.changes ?? 0;
|
|
17303
17390
|
return changes > 0;
|
|
17304
17391
|
}
|
|
@@ -17327,7 +17414,7 @@ function writeCompactionNote(db, args) {
|
|
|
17327
17414
|
}).run();
|
|
17328
17415
|
const sessionPrefix = `${COMPACTION_KEY_PREFIX}${args.sessionId}:`;
|
|
17329
17416
|
const existing = tx.select({ id: agentMemory.id, updatedAt: agentMemory.updatedAt }).from(agentMemory).where(
|
|
17330
|
-
|
|
17417
|
+
and17(
|
|
17331
17418
|
eq30(agentMemory.projectId, args.projectId),
|
|
17332
17419
|
like2(agentMemory.key, `${sessionPrefix}%`)
|
|
17333
17420
|
)
|
|
@@ -17336,7 +17423,7 @@ function writeCompactionNote(db, args) {
|
|
|
17336
17423
|
if (stale.length > 0) {
|
|
17337
17424
|
tx.delete(agentMemory).where(sql10`${agentMemory.id} IN (${sql10.join(stale.map((s) => sql10`${s}`), sql10`, `)})`).run();
|
|
17338
17425
|
}
|
|
17339
|
-
const row = tx.select().from(agentMemory).where(
|
|
17426
|
+
const row = tx.select().from(agentMemory).where(and17(eq30(agentMemory.projectId, args.projectId), eq30(agentMemory.key, key))).get();
|
|
17340
17427
|
if (row) inserted = rowToDto(row);
|
|
17341
17428
|
});
|
|
17342
17429
|
if (!inserted) throw new Error("compaction note write produced no row");
|
|
@@ -1342,6 +1342,16 @@ var ga4TrafficSummaryDtoSchema = z12.object({
|
|
|
1342
1342
|
directSharePct: z12.number(),
|
|
1343
1343
|
/** Social sessions as a percentage of total sessions (0–100, rounded). */
|
|
1344
1344
|
socialSharePct: z12.number(),
|
|
1345
|
+
/** Display string for organicSharePct ('10%' or '<1%' when there are sessions but the rounded pct is 0). */
|
|
1346
|
+
organicSharePctDisplay: z12.string(),
|
|
1347
|
+
/** Display string for aiSharePct ('5%' or '<1%' when there are sessions but the rounded pct is 0). */
|
|
1348
|
+
aiSharePctDisplay: z12.string(),
|
|
1349
|
+
/** Display string for aiSharePctBySession ('5%' or '<1%' when there are sessions but the rounded pct is 0). */
|
|
1350
|
+
aiSharePctBySessionDisplay: z12.string(),
|
|
1351
|
+
/** Display string for directSharePct ('20%' or '<1%' when there are sessions but the rounded pct is 0). */
|
|
1352
|
+
directSharePctDisplay: z12.string(),
|
|
1353
|
+
/** Display string for socialSharePct ('15%' or '<1%' when there are sessions but the rounded pct is 0). */
|
|
1354
|
+
socialSharePctDisplay: z12.string(),
|
|
1345
1355
|
lastSyncedAt: z12.string().nullable()
|
|
1346
1356
|
});
|
|
1347
1357
|
var ga4AiReferralHistoryEntrySchema = z12.object({
|
|
@@ -1567,7 +1577,12 @@ var backlinkSummaryDtoSchema = z14.object({
|
|
|
1567
1577
|
totalLinkingDomains: z14.number().int(),
|
|
1568
1578
|
totalHosts: z14.number().int(),
|
|
1569
1579
|
top10HostsShare: z14.string(),
|
|
1570
|
-
queriedAt: z14.string()
|
|
1580
|
+
queriedAt: z14.string(),
|
|
1581
|
+
// Populated when the response is filtered (e.g. ?excludeCrawlers=1).
|
|
1582
|
+
// Counts the rows omitted from totalLinkingDomains/totalHosts so callers
|
|
1583
|
+
// can show "N hidden" hints without re-deriving them.
|
|
1584
|
+
excludedLinkingDomains: z14.number().int().optional(),
|
|
1585
|
+
excludedHosts: z14.number().int().optional()
|
|
1571
1586
|
});
|
|
1572
1587
|
var backlinkListResponseSchema = z14.object({
|
|
1573
1588
|
summary: backlinkSummaryDtoSchema.nullable(),
|
|
@@ -2640,15 +2655,19 @@ var ApiClient = class {
|
|
|
2640
2655
|
async backlinksExtract(project, release) {
|
|
2641
2656
|
return this.request("POST", `/projects/${encodeURIComponent(project)}/backlinks/extract`, release ? { release } : {});
|
|
2642
2657
|
}
|
|
2643
|
-
async backlinksSummary(project,
|
|
2644
|
-
const qs =
|
|
2645
|
-
|
|
2658
|
+
async backlinksSummary(project, opts = {}) {
|
|
2659
|
+
const qs = new URLSearchParams();
|
|
2660
|
+
if (opts.release) qs.set("release", opts.release);
|
|
2661
|
+
if (opts.excludeCrawlers) qs.set("excludeCrawlers", "1");
|
|
2662
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
2663
|
+
return this.request("GET", `/projects/${encodeURIComponent(project)}/backlinks/summary${suffix}`);
|
|
2646
2664
|
}
|
|
2647
2665
|
async backlinksDomains(project, opts = {}) {
|
|
2648
2666
|
const qs = new URLSearchParams();
|
|
2649
2667
|
if (opts.limit !== void 0) qs.set("limit", String(opts.limit));
|
|
2650
2668
|
if (opts.offset !== void 0) qs.set("offset", String(opts.offset));
|
|
2651
2669
|
if (opts.release) qs.set("release", opts.release);
|
|
2670
|
+
if (opts.excludeCrawlers) qs.set("excludeCrawlers", "1");
|
|
2652
2671
|
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
2653
2672
|
return this.request("GET", `/projects/${encodeURIComponent(project)}/backlinks/domains${suffix}`);
|
|
2654
2673
|
}
|
package/dist/cli.js
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
setGoogleAuthConfig,
|
|
18
18
|
showFirstRunNotice,
|
|
19
19
|
trackEvent
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-QA5HRDRS.js";
|
|
21
21
|
import {
|
|
22
22
|
CcReleaseSyncStatuses,
|
|
23
23
|
CheckScopes,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
saveConfig,
|
|
46
46
|
saveConfigPatch,
|
|
47
47
|
usageError
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-TBFRAJU2.js";
|
|
49
49
|
import {
|
|
50
50
|
apiKeys,
|
|
51
51
|
competitors,
|
|
@@ -728,6 +728,9 @@ function formatSummaryAndDomains(project, response) {
|
|
|
728
728
|
lines.push(`Linking domains: ${s.totalLinkingDomains}`);
|
|
729
729
|
lines.push(`Total hosts: ${s.totalHosts}`);
|
|
730
730
|
lines.push(`Top-10 share: ${s.top10HostsShare}`);
|
|
731
|
+
if (s.excludedLinkingDomains !== void 0 && s.excludedLinkingDomains > 0) {
|
|
732
|
+
lines.push(`Excluded: ${s.excludedLinkingDomains} crawler/proxy domains (${s.excludedHosts ?? 0} hosts)`);
|
|
733
|
+
}
|
|
731
734
|
if (response.rows.length > 0) {
|
|
732
735
|
lines.push("");
|
|
733
736
|
lines.push(`Top ${response.rows.length} linking domains (of ${response.total}):`);
|
|
@@ -861,7 +864,8 @@ async function backlinksList(opts) {
|
|
|
861
864
|
const client = getClient();
|
|
862
865
|
const response = await client.backlinksDomains(opts.project, {
|
|
863
866
|
limit: opts.limit ?? 50,
|
|
864
|
-
release: opts.release
|
|
867
|
+
release: opts.release,
|
|
868
|
+
excludeCrawlers: opts.excludeCrawlers
|
|
865
869
|
});
|
|
866
870
|
if (opts.format === "json") {
|
|
867
871
|
printJson(response);
|
|
@@ -943,16 +947,17 @@ var BACKLINKS_CLI_COMMANDS = [
|
|
|
943
947
|
},
|
|
944
948
|
{
|
|
945
949
|
path: ["backlinks", "list"],
|
|
946
|
-
usage: "canonry backlinks list <project> [--limit <n>] [--release <id>] [--format json]",
|
|
950
|
+
usage: "canonry backlinks list <project> [--limit <n>] [--release <id>] [--exclude-crawlers] [--format json]",
|
|
947
951
|
options: {
|
|
948
952
|
limit: stringOption(),
|
|
949
|
-
release: stringOption()
|
|
953
|
+
release: stringOption(),
|
|
954
|
+
"exclude-crawlers": { type: "boolean" }
|
|
950
955
|
},
|
|
951
956
|
run: async (input) => {
|
|
952
957
|
const project = requireProject(
|
|
953
958
|
input,
|
|
954
959
|
"backlinks list",
|
|
955
|
-
"canonry backlinks list <project> [--limit <n>] [--release <id>]"
|
|
960
|
+
"canonry backlinks list <project> [--limit <n>] [--release <id>] [--exclude-crawlers]"
|
|
956
961
|
);
|
|
957
962
|
const limit = parseIntegerOption(input, "limit", {
|
|
958
963
|
message: "--limit must be an integer",
|
|
@@ -963,6 +968,7 @@ var BACKLINKS_CLI_COMMANDS = [
|
|
|
963
968
|
project,
|
|
964
969
|
limit,
|
|
965
970
|
release: getString(input.values, "release"),
|
|
971
|
+
excludeCrawlers: getBoolean(input.values, "exclude-crawlers"),
|
|
966
972
|
format: input.format
|
|
967
973
|
});
|
|
968
974
|
}
|
|
@@ -2222,6 +2228,11 @@ async function gaAttribution(project, opts) {
|
|
|
2222
2228
|
socialSharePct: traffic.socialSharePct,
|
|
2223
2229
|
organicSharePct: traffic.organicSharePct,
|
|
2224
2230
|
directSharePct: traffic.directSharePct,
|
|
2231
|
+
organicSharePctDisplay: traffic.organicSharePctDisplay,
|
|
2232
|
+
aiSharePctDisplay: traffic.aiSharePctDisplay,
|
|
2233
|
+
aiSharePctBySessionDisplay: traffic.aiSharePctBySessionDisplay,
|
|
2234
|
+
socialSharePctDisplay: traffic.socialSharePctDisplay,
|
|
2235
|
+
directSharePctDisplay: traffic.directSharePctDisplay,
|
|
2225
2236
|
aiReferrals: traffic.aiReferrals,
|
|
2226
2237
|
aiReferralLandingPages: traffic.aiReferralLandingPages,
|
|
2227
2238
|
socialReferrals: traffic.socialReferrals,
|
|
@@ -2239,10 +2250,10 @@ async function gaAttribution(project, opts) {
|
|
|
2239
2250
|
console.log(` Total Users: ${traffic.totalUsers}`);
|
|
2240
2251
|
console.log();
|
|
2241
2252
|
console.log(" CHANNEL BREAKDOWN 7d trend 30d trend");
|
|
2242
|
-
console.log(` Organic Search: ${String(traffic.totalOrganicSessions).padEnd(6)} (${
|
|
2243
|
-
console.log(` Social: ${String(traffic.socialSessions).padEnd(6)} (${
|
|
2244
|
-
console.log(` Direct: ${String(traffic.totalDirectSessions).padEnd(6)} (${
|
|
2245
|
-
console.log(` AI Referrals: ${String(traffic.aiSessionsBySession).padEnd(6)} (${
|
|
2253
|
+
console.log(` Organic Search: ${String(traffic.totalOrganicSessions).padEnd(6)} (${traffic.organicSharePctDisplay.padStart(4)}) ${fmtTrend(trend.organic.trend7dPct).padEnd(12)} ${fmtTrend(trend.organic.trend30dPct)}`);
|
|
2254
|
+
console.log(` Social: ${String(traffic.socialSessions).padEnd(6)} (${traffic.socialSharePctDisplay.padStart(4)}) ${fmtTrend(trend.social.trend7dPct).padEnd(12)} ${fmtTrend(trend.social.trend30dPct)}`);
|
|
2255
|
+
console.log(` Direct: ${String(traffic.totalDirectSessions).padEnd(6)} (${traffic.directSharePctDisplay.padStart(4)}) ${fmtTrend(trend.direct.trend7dPct).padEnd(12)} ${fmtTrend(trend.direct.trend30dPct)}`);
|
|
2256
|
+
console.log(` AI Referrals: ${String(traffic.aiSessionsBySession).padEnd(6)} (${traffic.aiSharePctBySessionDisplay.padStart(4)}) ${fmtTrend(trend.ai.trend7dPct).padEnd(12)} ${fmtTrend(trend.ai.trend30dPct)} (lower bound \u2014 sessionSource only; referrer-stripped traffic falls under Direct)`);
|
|
2246
2257
|
const otherSessions2 = traffic.totalSessions - traffic.totalOrganicSessions - traffic.aiSessionsBySession - traffic.socialSessions - traffic.totalDirectSessions;
|
|
2247
2258
|
if (otherSessions2 > 0) {
|
|
2248
2259
|
const otherPct = traffic.totalSessions > 0 ? Math.round(otherSessions2 / traffic.totalSessions * 100) : 0;
|
|
@@ -2285,6 +2296,11 @@ async function gaAttribution(project, opts) {
|
|
|
2285
2296
|
socialSharePct: traffic.socialSharePct,
|
|
2286
2297
|
organicSharePct: traffic.organicSharePct,
|
|
2287
2298
|
directSharePct: traffic.directSharePct,
|
|
2299
|
+
organicSharePctDisplay: traffic.organicSharePctDisplay,
|
|
2300
|
+
aiSharePctDisplay: traffic.aiSharePctDisplay,
|
|
2301
|
+
aiSharePctBySessionDisplay: traffic.aiSharePctBySessionDisplay,
|
|
2302
|
+
socialSharePctDisplay: traffic.socialSharePctDisplay,
|
|
2303
|
+
directSharePctDisplay: traffic.directSharePctDisplay,
|
|
2288
2304
|
aiReferrals: traffic.aiReferrals,
|
|
2289
2305
|
aiReferralLandingPages: traffic.aiReferralLandingPages,
|
|
2290
2306
|
socialReferrals: traffic.socialReferrals,
|
|
@@ -2303,10 +2319,10 @@ async function gaAttribution(project, opts) {
|
|
|
2303
2319
|
console.log(` Total Users: ${traffic.totalUsers}`);
|
|
2304
2320
|
console.log();
|
|
2305
2321
|
console.log(" CHANNEL BREAKDOWN");
|
|
2306
|
-
console.log(` Organic Search: ${traffic.totalOrganicSessions} sessions (${traffic.
|
|
2307
|
-
console.log(` Social: ${traffic.socialSessions} sessions (${traffic.
|
|
2308
|
-
console.log(` Direct: ${traffic.totalDirectSessions} sessions (${traffic.
|
|
2309
|
-
console.log(` AI Referrals: ${traffic.aiSessionsBySession} sessions (${traffic.
|
|
2322
|
+
console.log(` Organic Search: ${traffic.totalOrganicSessions} sessions (${traffic.organicSharePctDisplay})`);
|
|
2323
|
+
console.log(` Social: ${traffic.socialSessions} sessions (${traffic.socialSharePctDisplay})`);
|
|
2324
|
+
console.log(` Direct: ${traffic.totalDirectSessions} sessions (${traffic.directSharePctDisplay})`);
|
|
2325
|
+
console.log(` AI Referrals: ${traffic.aiSessionsBySession} sessions (${traffic.aiSharePctBySessionDisplay}) (lower bound \u2014 sessionSource only; referrer-stripped traffic falls under Direct)`);
|
|
2310
2326
|
const otherSessions = traffic.totalSessions - traffic.totalOrganicSessions - traffic.aiSessionsBySession - traffic.socialSessions - traffic.totalDirectSessions;
|
|
2311
2327
|
if (otherSessions > 0) {
|
|
2312
2328
|
const otherPct = traffic.totalSessions > 0 ? Math.round(otherSessions / traffic.totalSessions * 100) : 0;
|
package/dist/index.js
CHANGED
package/dist/mcp.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.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,19 +60,19 @@
|
|
|
60
60
|
"tsup": "^8.5.1",
|
|
61
61
|
"tsx": "^4.19.0",
|
|
62
62
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
63
|
+
"@ainyc/canonry-db": "0.0.0",
|
|
63
64
|
"@ainyc/canonry-config": "0.0.0",
|
|
65
|
+
"@ainyc/canonry-intelligence": "0.0.0",
|
|
64
66
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
65
67
|
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
66
|
-
"@ainyc/canonry-db": "0.0.0",
|
|
67
68
|
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
68
69
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
69
70
|
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
70
|
-
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
71
|
-
"@ainyc/canonry-intelligence": "0.0.0",
|
|
72
71
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
73
72
|
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
74
73
|
"@ainyc/canonry-provider-local": "0.0.0",
|
|
75
74
|
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
75
|
+
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
76
76
|
"@ainyc/canonry-provider-perplexity": "0.0.0"
|
|
77
77
|
},
|
|
78
78
|
"scripts": {
|