@ainyc/canonry 4.67.0 → 4.69.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/README.md +1 -0
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +8 -1
- package/assets/assets/{BacklinksPage-B9oyoljV.js → BacklinksPage-BXVoTc3S.js} +1 -1
- package/assets/assets/ChartPrimitives-pJRJPd17.js +1 -0
- package/assets/assets/ProjectPage-CQ1_itHh.js +6 -0
- package/assets/assets/{RunRow-vHM36Fdi.js → RunRow-DPL4FxPl.js} +1 -1
- package/assets/assets/{RunsPage-Cr58nTet.js → RunsPage-B4dCG_66.js} +1 -1
- package/assets/assets/{SettingsPage-BuiP8ZOv.js → SettingsPage-D8aWhLsU.js} +1 -1
- package/assets/assets/{TrafficPage-bwOxChyo.js → TrafficPage-COZa5_Q_.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-B0uY6VIB.js → TrafficSourceDetailPage-CN8Cx6YI.js} +1 -1
- package/assets/assets/{extract-error-message-CWdzuNp4.js → extract-error-message-D8g8YXDH.js} +1 -1
- package/assets/assets/index-BUNCrWTe.css +1 -0
- package/assets/assets/{index-DiN_mzYU.js → index-DPO3uDWZ.js} +79 -79
- package/assets/assets/{server-traffic-D3aICbxr.js → server-traffic-0JT1Vbj_.js} +1 -1
- package/assets/assets/{trash-2-CVKno2W2.js → trash-2-_1TgguOP.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-KHN3XMOR.js → chunk-B2CH7GBW.js} +93 -28
- package/dist/{chunk-34PATQZM.js → chunk-D75O5A27.js} +36 -1
- package/dist/{chunk-4V3V4MFF.js → chunk-WQ44ZXGQ.js} +45 -8
- package/dist/{chunk-RQCVITY4.js → chunk-YYFBMDLC.js} +15 -1
- package/dist/cli.js +27 -11
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-SMU5JVVD.js → intelligence-service-IUKD3PMZ.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +11 -10
- package/assets/assets/ChartPrimitives-CvfM24iC.js +0 -1
- package/assets/assets/ProjectPage-DELbOAlm.js +0 -6
- package/assets/assets/index-yMJe1bJR.css +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as d,j as a,
|
|
1
|
+
import{c as d,j as a,bU as S,bO as l,bV as v,av as m,l as t,bW as y,bP as i,bX as T,bY as h,bZ as p,b_ as b}from"./index-DPO3uDWZ.js";import{u as s,r as C,n as c,o as u}from"./vendor-tanstack-Dq7p98wZ.js";const g=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],B=d("refresh-cw",g);function M(e){switch(e){case i.connected:return"positive";case i.paused:return"caution";case i.error:return"negative";case i.archived:return"neutral"}}function w(e){const r={};return e.kind&&e.kind!=="all"&&(r.kind=e.kind),e.sourceId&&(r.sourceId=e.sourceId),e.sinceMinutes!==void 0&&(r.since=new Date(Date.now()-e.sinceMinutes*6e4).toISOString()),e.limit!==void 0&&(r.limit=String(e.limit)),r}function o(e){e.invalidateQueries({predicate:r=>{const n=r.queryKey[0];return typeof n?._id=="string"&&n._id.startsWith("getApiV1ProjectsByNameTraffic")}})}function V(e){return s({...S({client:t,path:{name:e??""}}),enabled:!!e,staleTime:a})}function k(e){return s({...b({client:t,path:{name:e??""}}),enabled:!!e,staleTime:a})}function F(e,r){return s({...l({client:t,path:{name:e??"",id:r??""}}),enabled:!!(e&&r),staleTime:a})}function A(e,r){const n=C.useMemo(()=>w(r),[r.kind,r.sourceId,r.sinceMinutes,r.limit]);return s({...v({client:t,path:{name:e??""},query:n}),enabled:!!e,staleTime:a})}function E(e){const r=c();return u({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a Cloud Run source");return p(e,n)},onSuccess:()=>{e&&o(r)}})}function I(e){const r=c();return u({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a WordPress source");return T(e,n)},onSuccess:()=>{e&&o(r)}})}function Q(e){const r=c();return u({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a Vercel source");return h(e,n)},onSuccess:()=>{e&&o(r)}})}function R(e,r){const n=c();return u({mutationFn:f=>{if(!e||!r)throw new Error("Project and sourceId are required to sync");return y(e,r,f??void 0)},onSuccess:()=>{e&&(o(n),n.invalidateQueries({queryKey:m({client:t})}))}})}export{B as R,I as a,Q as b,E as c,V as d,F as e,A as f,R as g,M as t,k as u};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c}from"./index-
|
|
1
|
+
import{c}from"./index-DPO3uDWZ.js";const a=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],h=c("circle-check",a);const e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],n=c("circle-question-mark",e);const o=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],s=c("download",o);const t=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],r=c("trash-2",t);export{h as C,s as D,r as T,n as a};
|
package/assets/index.html
CHANGED
|
@@ -12,12 +12,12 @@
|
|
|
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-
|
|
15
|
+
<script type="module" crossorigin src="./assets/index-DPO3uDWZ.js"></script>
|
|
16
16
|
<link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-Dq7p98wZ.js">
|
|
17
17
|
<link rel="modulepreload" crossorigin href="./assets/vendor-radix-B57xfQbP.js">
|
|
18
18
|
<link rel="modulepreload" crossorigin href="./assets/vendor-recharts-ClRVR6aX.js">
|
|
19
19
|
<link rel="modulepreload" crossorigin href="./assets/vendor-markdown-DK7fbRNb.js">
|
|
20
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
20
|
+
<link rel="stylesheet" crossorigin href="./assets/index-BUNCrWTe.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
|
23
23
|
<div id="root"></div>
|
|
@@ -51,6 +51,7 @@ import {
|
|
|
51
51
|
bingUrlInspectionDtoSchema,
|
|
52
52
|
brandKeyFromText,
|
|
53
53
|
brandLabelFromDomain,
|
|
54
|
+
brandMetricsDtoSchema,
|
|
54
55
|
categorizeSource,
|
|
55
56
|
categorizeSourceWithCompetitors,
|
|
56
57
|
categoryLabel,
|
|
@@ -207,7 +208,7 @@ import {
|
|
|
207
208
|
wordpressSchemaDeployResultDtoSchema,
|
|
208
209
|
wordpressSchemaStatusResultDtoSchema,
|
|
209
210
|
wordpressStatusDtoSchema
|
|
210
|
-
} from "./chunk-
|
|
211
|
+
} from "./chunk-D75O5A27.js";
|
|
211
212
|
|
|
212
213
|
// src/intelligence-service.ts
|
|
213
214
|
import { eq as eq30, desc as desc15, asc as asc3, and as and23, ne as ne5, or as or5, inArray as inArray11, gte as gte6, lte as lte3 } from "drizzle-orm";
|
|
@@ -6131,6 +6132,7 @@ import crypto10 from "crypto";
|
|
|
6131
6132
|
import { and as and3, eq as eq8 } from "drizzle-orm";
|
|
6132
6133
|
|
|
6133
6134
|
// ../api-routes/src/schedule-utils.ts
|
|
6135
|
+
import { CronExpressionParser } from "cron-parser";
|
|
6134
6136
|
var DAY_MAP = {
|
|
6135
6137
|
sun: "0",
|
|
6136
6138
|
mon: "1",
|
|
@@ -6217,6 +6219,17 @@ function isValidTimezone(tz) {
|
|
|
6217
6219
|
return false;
|
|
6218
6220
|
}
|
|
6219
6221
|
}
|
|
6222
|
+
function nextRunFromCron(cronExpr, timezone, from = /* @__PURE__ */ new Date()) {
|
|
6223
|
+
try {
|
|
6224
|
+
const interval = CronExpressionParser.parse(cronExpr, {
|
|
6225
|
+
currentDate: from,
|
|
6226
|
+
tz: timezone
|
|
6227
|
+
});
|
|
6228
|
+
return interval.next().toDate().toISOString();
|
|
6229
|
+
} catch {
|
|
6230
|
+
return null;
|
|
6231
|
+
}
|
|
6232
|
+
}
|
|
6220
6233
|
|
|
6221
6234
|
// ../api-routes/src/webhooks.ts
|
|
6222
6235
|
import crypto9 from "crypto";
|
|
@@ -7243,6 +7256,10 @@ function computeBuckets(snapshots, projectRuns, bucketDays, queryCreatedAt) {
|
|
|
7243
7256
|
}
|
|
7244
7257
|
const metric = computeProviderMetric(usable);
|
|
7245
7258
|
const queryCount = new Set(usable.map((s) => s.queryId)).size;
|
|
7259
|
+
const byProvider = {};
|
|
7260
|
+
for (const provider of new Set(usable.map((s) => s.provider))) {
|
|
7261
|
+
byProvider[provider] = computeProviderMetric(usable.filter((s) => s.provider === provider));
|
|
7262
|
+
}
|
|
7246
7263
|
buckets.push({
|
|
7247
7264
|
startDate: startISO,
|
|
7248
7265
|
endDate: endISO,
|
|
@@ -7251,7 +7268,8 @@ function computeBuckets(snapshots, projectRuns, bucketDays, queryCreatedAt) {
|
|
|
7251
7268
|
total: metric.total,
|
|
7252
7269
|
queryCount,
|
|
7253
7270
|
mentionRate: metric.mentionRate,
|
|
7254
|
-
mentionedCount: metric.mentionedCount
|
|
7271
|
+
mentionedCount: metric.mentionedCount,
|
|
7272
|
+
byProvider
|
|
7255
7273
|
});
|
|
7256
7274
|
}
|
|
7257
7275
|
start = end;
|
|
@@ -12012,6 +12030,7 @@ async function compositeRoutes(app) {
|
|
|
12012
12030
|
const attentionItems = buildAttentionItems(insightRows, allRuns);
|
|
12013
12031
|
const sparklineRuns = visibilityRuns.slice(0, DEFAULT_RUN_HISTORY_LIMIT).map((r) => ({ id: r.id, createdAt: r.createdAt, status: r.status }));
|
|
12014
12032
|
const runHistory = buildRunHistory(sparklineRuns, snapshotsByRun);
|
|
12033
|
+
scores.visibility.trend = runHistory.map((p) => p.citationRate);
|
|
12015
12034
|
const suggestedQueries = buildSuggestedQueriesFromGsc(
|
|
12016
12035
|
app,
|
|
12017
12036
|
project.id,
|
|
@@ -12171,17 +12190,30 @@ function loadSnapshotsByRunIds(app, runIds) {
|
|
|
12171
12190
|
}
|
|
12172
12191
|
function summarizeFromSnapshots(snapshots) {
|
|
12173
12192
|
const empty = {
|
|
12174
|
-
queryCounts: {
|
|
12193
|
+
queryCounts: {
|
|
12194
|
+
totalQueries: 0,
|
|
12195
|
+
citedQueries: 0,
|
|
12196
|
+
notCitedQueries: 0,
|
|
12197
|
+
citedRate: 0,
|
|
12198
|
+
mentionedQueries: 0,
|
|
12199
|
+
notMentionedQueries: 0,
|
|
12200
|
+
mentionRate: 0
|
|
12201
|
+
},
|
|
12175
12202
|
providers: []
|
|
12176
12203
|
};
|
|
12177
12204
|
if (snapshots.length === 0) return empty;
|
|
12178
12205
|
const perQuery = /* @__PURE__ */ new Map();
|
|
12206
|
+
const perQueryMentioned = /* @__PURE__ */ new Map();
|
|
12179
12207
|
const perProvider = /* @__PURE__ */ new Map();
|
|
12180
12208
|
for (const snap of snapshots) {
|
|
12181
12209
|
const cited = snap.citationState === CitationStates.cited;
|
|
12182
12210
|
if (!perQuery.has(snap.queryId) || cited) {
|
|
12183
12211
|
perQuery.set(snap.queryId, cited);
|
|
12184
12212
|
}
|
|
12213
|
+
const mentioned = snap.answerMentioned === true;
|
|
12214
|
+
if (!perQueryMentioned.has(snap.queryId) || mentioned) {
|
|
12215
|
+
perQueryMentioned.set(snap.queryId, mentioned);
|
|
12216
|
+
}
|
|
12185
12217
|
const bucket = perProvider.get(snap.provider) ?? { cited: 0, total: 0 };
|
|
12186
12218
|
bucket.total += 1;
|
|
12187
12219
|
if (cited) bucket.cited += 1;
|
|
@@ -12194,6 +12226,12 @@ function summarizeFromSnapshots(snapshots) {
|
|
|
12194
12226
|
}
|
|
12195
12227
|
const notCitedQueries = totalQueries - citedQueries;
|
|
12196
12228
|
const citedRate = totalQueries === 0 ? 0 : Number((citedQueries / totalQueries).toFixed(4));
|
|
12229
|
+
let mentionedQueries = 0;
|
|
12230
|
+
for (const wasMentioned of perQueryMentioned.values()) {
|
|
12231
|
+
if (wasMentioned) mentionedQueries += 1;
|
|
12232
|
+
}
|
|
12233
|
+
const notMentionedQueries = totalQueries - mentionedQueries;
|
|
12234
|
+
const mentionRate = totalQueries === 0 ? 0 : Number((mentionedQueries / totalQueries).toFixed(4));
|
|
12197
12235
|
const providers = [...perProvider.entries()].map(([provider, { cited, total }]) => ({
|
|
12198
12236
|
provider,
|
|
12199
12237
|
cited,
|
|
@@ -12201,7 +12239,15 @@ function summarizeFromSnapshots(snapshots) {
|
|
|
12201
12239
|
citedRate: total === 0 ? 0 : Number((cited / total).toFixed(4))
|
|
12202
12240
|
})).sort((a, b) => a.provider.localeCompare(b.provider));
|
|
12203
12241
|
return {
|
|
12204
|
-
queryCounts: {
|
|
12242
|
+
queryCounts: {
|
|
12243
|
+
totalQueries,
|
|
12244
|
+
citedQueries,
|
|
12245
|
+
notCitedQueries,
|
|
12246
|
+
citedRate,
|
|
12247
|
+
mentionedQueries,
|
|
12248
|
+
notMentionedQueries,
|
|
12249
|
+
mentionRate
|
|
12250
|
+
},
|
|
12205
12251
|
providers
|
|
12206
12252
|
};
|
|
12207
12253
|
}
|
|
@@ -12544,6 +12590,7 @@ var SCHEMA_TABLE = {
|
|
|
12544
12590
|
BingSitesResponseDto: bingSitesResponseDtoSchema,
|
|
12545
12591
|
BingStatusDto: bingStatusDtoSchema,
|
|
12546
12592
|
BingUrlInspectionDto: bingUrlInspectionDtoSchema,
|
|
12593
|
+
BrandMetricsDto: brandMetricsDtoSchema,
|
|
12547
12594
|
CcAvailableRelease: ccAvailableReleaseSchema,
|
|
12548
12595
|
CcCachedRelease: ccCachedReleaseSchema,
|
|
12549
12596
|
CcReleaseSyncDto: ccReleaseSyncDtoSchema,
|
|
@@ -12595,6 +12642,7 @@ var SCHEMA_TABLE = {
|
|
|
12595
12642
|
QueryDto: queryDtoSchema,
|
|
12596
12643
|
RunDetailDto: runDetailDtoSchema,
|
|
12597
12644
|
RunDto: runDtoSchema,
|
|
12645
|
+
SchedulableRunKind: schedulableRunKindSchema,
|
|
12598
12646
|
ScheduleDto: scheduleDtoSchema,
|
|
12599
12647
|
SettingsDto: settingsDtoSchema,
|
|
12600
12648
|
SnapshotDiffResponse: snapshotDiffResponseSchema,
|
|
@@ -12630,11 +12678,20 @@ var SCHEMA_TABLE = {
|
|
|
12630
12678
|
})
|
|
12631
12679
|
})
|
|
12632
12680
|
};
|
|
12681
|
+
var SHARED_ENUM_REFS = [
|
|
12682
|
+
{ schema: "ScheduleDto", property: "kind", component: "SchedulableRunKind" }
|
|
12683
|
+
];
|
|
12633
12684
|
function buildComponentSchemas() {
|
|
12634
12685
|
const out = {};
|
|
12635
12686
|
for (const [name, schema] of Object.entries(SCHEMA_TABLE)) {
|
|
12636
12687
|
out[name] = z.toJSONSchema(schema, { target: "openapi-3.0" });
|
|
12637
12688
|
}
|
|
12689
|
+
for (const { schema, property, component } of SHARED_ENUM_REFS) {
|
|
12690
|
+
const properties = out[schema]?.properties;
|
|
12691
|
+
if (properties && properties[property]) {
|
|
12692
|
+
properties[property] = { $ref: `#/components/schemas/${component}` };
|
|
12693
|
+
}
|
|
12694
|
+
}
|
|
12638
12695
|
return out;
|
|
12639
12696
|
}
|
|
12640
12697
|
function jsonResponse(description, schemaName) {
|
|
@@ -12680,7 +12737,6 @@ var integerSchema = { type: "integer" };
|
|
|
12680
12737
|
var objectSchema = { type: "object", additionalProperties: true };
|
|
12681
12738
|
var stringArraySchema = { type: "array", items: stringSchema };
|
|
12682
12739
|
var googleConnectionTypeSchema = { type: "string", enum: ["gsc", "ga4", "gbp"] };
|
|
12683
|
-
var scheduleKindEnum = Object.values(SchedulableRunKinds);
|
|
12684
12740
|
var locationSchema = {
|
|
12685
12741
|
type: "object",
|
|
12686
12742
|
required: ["label", "city", "region", "country"],
|
|
@@ -12770,7 +12826,7 @@ var scheduleKindQueryParameter = {
|
|
|
12770
12826
|
name: "kind",
|
|
12771
12827
|
in: "query",
|
|
12772
12828
|
description: 'Schedulable run kind. Defaults to "answer-visibility" for backward compatibility.',
|
|
12773
|
-
schema: {
|
|
12829
|
+
schema: { $ref: "#/components/schemas/SchedulableRunKind" }
|
|
12774
12830
|
};
|
|
12775
12831
|
var runsListKindQueryParameter = {
|
|
12776
12832
|
name: "kind",
|
|
@@ -13516,8 +13572,7 @@ var routeCatalog = [
|
|
|
13516
13572
|
tags: ["analytics"],
|
|
13517
13573
|
parameters: [nameParameter, analyticsWindowParameter],
|
|
13518
13574
|
responses: {
|
|
13519
|
-
|
|
13520
|
-
200: rawJsonResponse("Citation metrics returned.", looseObjectSchema),
|
|
13575
|
+
200: jsonResponse("Citation metrics returned.", "BrandMetricsDto"),
|
|
13521
13576
|
404: errorResponse("Project not found.")
|
|
13522
13577
|
}
|
|
13523
13578
|
},
|
|
@@ -13731,7 +13786,7 @@ var routeCatalog = [
|
|
|
13731
13786
|
schema: {
|
|
13732
13787
|
type: "object",
|
|
13733
13788
|
properties: {
|
|
13734
|
-
kind: {
|
|
13789
|
+
kind: { $ref: "#/components/schemas/SchedulableRunKind" },
|
|
13735
13790
|
preset: stringSchema,
|
|
13736
13791
|
cron: stringSchema,
|
|
13737
13792
|
timezone: stringSchema,
|
|
@@ -16583,6 +16638,9 @@ async function scheduleRoutes(app, opts) {
|
|
|
16583
16638
|
} else if (sourceId) {
|
|
16584
16639
|
throw validationError(`"sourceId" is only valid when kind is "traffic-sync"`);
|
|
16585
16640
|
}
|
|
16641
|
+
if (kind === SchedulableRunKinds["backlinks-sync"] && providers && providers.length > 0) {
|
|
16642
|
+
throw validationError('"providers" is not valid for kind "backlinks-sync"');
|
|
16643
|
+
}
|
|
16586
16644
|
const validNames = opts.validProviderNames ?? [];
|
|
16587
16645
|
if (validNames.length && providers?.length) {
|
|
16588
16646
|
const invalid = providers.filter((p) => !validNames.includes(p));
|
|
@@ -22781,7 +22839,8 @@ var PLUGIN_DIR = path2.join(os2.homedir(), ".canonry", "plugins");
|
|
|
22781
22839
|
var PLUGIN_PKG_JSON = path2.join(PLUGIN_DIR, "package.json");
|
|
22782
22840
|
var DUCKDB_SPEC = process.env.CANONRY_DUCKDB_SPEC ?? "@duckdb/node-api@1.4.4-r.3";
|
|
22783
22841
|
var CC_CACHE_DIR = process.env.CANONRY_CC_CACHE_DIR ?? path2.join(os2.homedir(), ".canonry", "cache", "commoncrawl");
|
|
22784
|
-
var
|
|
22842
|
+
var CC_MONTH = "(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)";
|
|
22843
|
+
var RELEASE_ID_REGEX = new RegExp(`^cc-main-(\\d{4})-(${CC_MONTH}-${CC_MONTH}-${CC_MONTH})$`);
|
|
22785
22844
|
function ccReleasePaths(release) {
|
|
22786
22845
|
const base = `${CC_BASE_URL}/${release}/domain`;
|
|
22787
22846
|
const vertexFilename = `${release}-domain-vertices.txt.gz`;
|
|
@@ -22806,23 +22865,28 @@ function forwardDomain(revDomain) {
|
|
|
22806
22865
|
function isValidReleaseId(id) {
|
|
22807
22866
|
return RELEASE_ID_REGEX.test(id);
|
|
22808
22867
|
}
|
|
22809
|
-
function formatReleaseId(year,
|
|
22810
|
-
return `cc-main-${year}-${
|
|
22868
|
+
function formatReleaseId(year, window) {
|
|
22869
|
+
return `cc-main-${year}-${window}`;
|
|
22811
22870
|
}
|
|
22812
22871
|
|
|
22813
22872
|
// ../integration-commoncrawl/src/release-discovery.ts
|
|
22814
|
-
var
|
|
22815
|
-
|
|
22816
|
-
|
|
22817
|
-
|
|
22818
|
-
|
|
22819
|
-
|
|
22820
|
-
|
|
22821
|
-
|
|
22873
|
+
var MONTHS = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"];
|
|
22874
|
+
function windowSlug(firstMonthIndex) {
|
|
22875
|
+
const a = MONTHS[firstMonthIndex % 12];
|
|
22876
|
+
const b = MONTHS[(firstMonthIndex + 1) % 12];
|
|
22877
|
+
const c = MONTHS[(firstMonthIndex + 2) % 12];
|
|
22878
|
+
return `${a}-${b}-${c}`;
|
|
22879
|
+
}
|
|
22880
|
+
function probeCandidates(now, maxMonthsBack) {
|
|
22881
|
+
let year = now.getUTCFullYear();
|
|
22882
|
+
let month = now.getUTCMonth();
|
|
22822
22883
|
const out = [];
|
|
22823
|
-
for (let
|
|
22824
|
-
|
|
22825
|
-
|
|
22884
|
+
for (let step = 0; step <= maxMonthsBack; step++) {
|
|
22885
|
+
out.push({ year, window: windowSlug(month) });
|
|
22886
|
+
month -= 1;
|
|
22887
|
+
if (month < 0) {
|
|
22888
|
+
month = 11;
|
|
22889
|
+
year -= 1;
|
|
22826
22890
|
}
|
|
22827
22891
|
}
|
|
22828
22892
|
return out;
|
|
@@ -22845,11 +22909,11 @@ async function probeRelease(release, fetchImpl = fetch) {
|
|
|
22845
22909
|
}
|
|
22846
22910
|
async function probeLatestRelease(opts = {}) {
|
|
22847
22911
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
22848
|
-
const maxBack = opts.
|
|
22912
|
+
const maxBack = opts.maxMonthsBack ?? 14;
|
|
22849
22913
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
22850
22914
|
const candidates = probeCandidates(now, maxBack);
|
|
22851
|
-
for (const { year,
|
|
22852
|
-
const release = formatReleaseId(year,
|
|
22915
|
+
for (const { year, window } of candidates) {
|
|
22916
|
+
const release = formatReleaseId(year, window);
|
|
22853
22917
|
const result = await probeRelease(release, fetchImpl);
|
|
22854
22918
|
if (result) return result;
|
|
22855
22919
|
}
|
|
@@ -23312,7 +23376,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
23312
23376
|
if (!release) {
|
|
23313
23377
|
if (!opts.discoverLatestRelease) {
|
|
23314
23378
|
throw validationError(
|
|
23315
|
-
"No `release` provided and auto-discovery is unavailable on this deployment. Pass an explicit release id (e.g., cc-main-2026-
|
|
23379
|
+
"No `release` provided and auto-discovery is unavailable on this deployment. Pass an explicit release id (e.g., cc-main-2026-mar-apr-may)."
|
|
23316
23380
|
);
|
|
23317
23381
|
}
|
|
23318
23382
|
const discovered = await opts.discoverLatestRelease();
|
|
@@ -23324,7 +23388,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
23324
23388
|
release = discovered.release;
|
|
23325
23389
|
}
|
|
23326
23390
|
if (!isValidReleaseId(release)) {
|
|
23327
|
-
throw validationError("Invalid release id. Expected form: cc-main-YYYY-
|
|
23391
|
+
throw validationError("Invalid release id. Expected form: cc-main-YYYY-<mon>-<mon>-<mon> (a rolling 3-month window, e.g. cc-main-2026-mar-apr-may).");
|
|
23328
23392
|
}
|
|
23329
23393
|
if (!opts.getBacklinksStatus || !opts.onReleaseSyncRequested) {
|
|
23330
23394
|
throw missingDependency(BACKLINKS_UNSUPPORTED_MESSAGE);
|
|
@@ -31959,6 +32023,7 @@ export {
|
|
|
31959
32023
|
getPlaceDetails,
|
|
31960
32024
|
hashPlaceDetails,
|
|
31961
32025
|
queueRunIfProjectIdle,
|
|
32026
|
+
nextRunFromCron,
|
|
31962
32027
|
resolveWebhookTarget,
|
|
31963
32028
|
deliverWebhook,
|
|
31964
32029
|
redactNotificationUrl,
|
|
@@ -1498,7 +1498,7 @@ var snapshotReportSchema = z12.object({
|
|
|
1498
1498
|
|
|
1499
1499
|
// ../contracts/src/schedule.ts
|
|
1500
1500
|
import { z as z13 } from "zod";
|
|
1501
|
-
var schedulableRunKindSchema = z13.enum(["answer-visibility", "traffic-sync", "gbp-sync", "data-refresh"]);
|
|
1501
|
+
var schedulableRunKindSchema = z13.enum(["answer-visibility", "traffic-sync", "gbp-sync", "data-refresh", "backlinks-sync"]);
|
|
1502
1502
|
var SchedulableRunKinds = schedulableRunKindSchema.enum;
|
|
1503
1503
|
var scheduleDtoSchema = z13.object({
|
|
1504
1504
|
id: z13.string(),
|
|
@@ -1534,8 +1534,42 @@ var scheduleUpsertRequestSchema = z13.object({
|
|
|
1534
1534
|
|
|
1535
1535
|
// ../contracts/src/analytics.ts
|
|
1536
1536
|
import { z as z14 } from "zod";
|
|
1537
|
+
var metricsWindowSchema = z14.enum(["7d", "30d", "90d", "all"]);
|
|
1538
|
+
var trendDirectionSchema = z14.enum(["improving", "declining", "stable"]);
|
|
1537
1539
|
var visibilityMetricModeSchema = z14.enum(["mentioned", "cited"]);
|
|
1538
1540
|
var VisibilityMetricModes = visibilityMetricModeSchema.enum;
|
|
1541
|
+
var providerMetricSchema = z14.object({
|
|
1542
|
+
citationRate: z14.number(),
|
|
1543
|
+
cited: z14.number().int(),
|
|
1544
|
+
total: z14.number().int(),
|
|
1545
|
+
mentionRate: z14.number(),
|
|
1546
|
+
mentionedCount: z14.number().int()
|
|
1547
|
+
});
|
|
1548
|
+
var timeBucketSchema = z14.object({
|
|
1549
|
+
startDate: z14.string(),
|
|
1550
|
+
endDate: z14.string(),
|
|
1551
|
+
citationRate: z14.number(),
|
|
1552
|
+
cited: z14.number().int(),
|
|
1553
|
+
total: z14.number().int(),
|
|
1554
|
+
queryCount: z14.number().int(),
|
|
1555
|
+
mentionRate: z14.number(),
|
|
1556
|
+
mentionedCount: z14.number().int(),
|
|
1557
|
+
byProvider: z14.record(z14.string(), providerMetricSchema)
|
|
1558
|
+
});
|
|
1559
|
+
var queryChangeEventSchema = z14.object({
|
|
1560
|
+
date: z14.string(),
|
|
1561
|
+
delta: z14.number().int(),
|
|
1562
|
+
label: z14.string()
|
|
1563
|
+
});
|
|
1564
|
+
var brandMetricsDtoSchema = z14.object({
|
|
1565
|
+
window: metricsWindowSchema,
|
|
1566
|
+
buckets: z14.array(timeBucketSchema),
|
|
1567
|
+
overall: providerMetricSchema,
|
|
1568
|
+
byProvider: z14.record(z14.string(), providerMetricSchema),
|
|
1569
|
+
trend: trendDirectionSchema,
|
|
1570
|
+
mentionTrend: trendDirectionSchema,
|
|
1571
|
+
queryChanges: z14.array(queryChangeEventSchema)
|
|
1572
|
+
});
|
|
1539
1573
|
function parseWindow(value) {
|
|
1540
1574
|
if (value === "7d" || value === "30d" || value === "90d" || value === "all") return value;
|
|
1541
1575
|
return "all";
|
|
@@ -4010,6 +4044,7 @@ export {
|
|
|
4010
4044
|
SchedulableRunKinds,
|
|
4011
4045
|
scheduleDtoSchema,
|
|
4012
4046
|
scheduleUpsertRequestSchema,
|
|
4047
|
+
brandMetricsDtoSchema,
|
|
4013
4048
|
parseWindow,
|
|
4014
4049
|
windowCutoff,
|
|
4015
4050
|
categorizeSource,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
loadConfig,
|
|
10
10
|
loadConfigRaw,
|
|
11
11
|
saveConfigPatch
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-YYFBMDLC.js";
|
|
13
13
|
import {
|
|
14
14
|
CC_CACHE_DIR,
|
|
15
15
|
DUCKDB_SPEC,
|
|
@@ -77,6 +77,7 @@ import {
|
|
|
77
77
|
loadDuckdb,
|
|
78
78
|
markSessionFailed,
|
|
79
79
|
migrate,
|
|
80
|
+
nextRunFromCron,
|
|
80
81
|
notifications,
|
|
81
82
|
parseJsonColumn,
|
|
82
83
|
probeLatestRelease,
|
|
@@ -94,7 +95,7 @@ import {
|
|
|
94
95
|
runs,
|
|
95
96
|
schedules,
|
|
96
97
|
usageCounters
|
|
97
|
-
} from "./chunk-
|
|
98
|
+
} from "./chunk-B2CH7GBW.js";
|
|
98
99
|
import {
|
|
99
100
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
100
101
|
AGENT_PROVIDER_IDS,
|
|
@@ -142,7 +143,7 @@ import {
|
|
|
142
143
|
skillsClientSchema,
|
|
143
144
|
validationError,
|
|
144
145
|
withRetry
|
|
145
|
-
} from "./chunk-
|
|
146
|
+
} from "./chunk-D75O5A27.js";
|
|
146
147
|
|
|
147
148
|
// src/telemetry.ts
|
|
148
149
|
import crypto from "crypto";
|
|
@@ -434,7 +435,7 @@ import crypto17 from "crypto";
|
|
|
434
435
|
import fs8 from "fs";
|
|
435
436
|
import path9 from "path";
|
|
436
437
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
437
|
-
import { eq as eq17 } from "drizzle-orm";
|
|
438
|
+
import { and as and13, eq as eq17 } from "drizzle-orm";
|
|
438
439
|
import Fastify from "fastify";
|
|
439
440
|
import os5 from "os";
|
|
440
441
|
|
|
@@ -5617,7 +5618,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
5617
5618
|
return result;
|
|
5618
5619
|
}
|
|
5619
5620
|
async function backfillInsightsCommand(project, opts) {
|
|
5620
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
5621
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-IUKD3PMZ.js");
|
|
5621
5622
|
const config = loadConfig();
|
|
5622
5623
|
const db = createClient(config.database);
|
|
5623
5624
|
migrate(db);
|
|
@@ -6602,7 +6603,7 @@ var Scheduler = class {
|
|
|
6602
6603
|
});
|
|
6603
6604
|
this.tasks.set(taskKey(projectId, kind), task);
|
|
6604
6605
|
this.db.update(schedules).set({
|
|
6605
|
-
nextRunAt:
|
|
6606
|
+
nextRunAt: nextRunFromCron(cronExpr, timezone),
|
|
6606
6607
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6607
6608
|
}).where(eq11(schedules.id, scheduleId)).run();
|
|
6608
6609
|
const label = schedule.preset ?? cronExpr;
|
|
@@ -6617,8 +6618,7 @@ var Scheduler = class {
|
|
|
6617
6618
|
this.remove(projectId, kind);
|
|
6618
6619
|
return;
|
|
6619
6620
|
}
|
|
6620
|
-
const
|
|
6621
|
-
const nextRunAt = task?.getNextRun()?.toISOString() ?? null;
|
|
6621
|
+
const nextRunAt = nextRunFromCron(currentSchedule.cronExpr, currentSchedule.timezone);
|
|
6622
6622
|
const project = this.db.select().from(projects).where(eq11(projects.id, projectId)).get();
|
|
6623
6623
|
if (!project) {
|
|
6624
6624
|
log11.error("project.not-found", { projectId, kind, msg: "skipping scheduled run" });
|
|
@@ -6681,6 +6681,20 @@ var Scheduler = class {
|
|
|
6681
6681
|
this.callbacks.onDataRefreshRequested(project.name);
|
|
6682
6682
|
return;
|
|
6683
6683
|
}
|
|
6684
|
+
if (kind === SchedulableRunKinds["backlinks-sync"]) {
|
|
6685
|
+
if (!this.callbacks.onBacklinksSyncRequested) {
|
|
6686
|
+
log11.warn("backlinks-sync.no-callback", { scheduleId, projectId, msg: "host did not register onBacklinksSyncRequested" });
|
|
6687
|
+
return;
|
|
6688
|
+
}
|
|
6689
|
+
this.db.update(schedules).set({
|
|
6690
|
+
lastRunAt: now,
|
|
6691
|
+
nextRunAt,
|
|
6692
|
+
updatedAt: now
|
|
6693
|
+
}).where(eq11(schedules.id, currentSchedule.id)).run();
|
|
6694
|
+
log11.info("backlinks-sync.triggered", { projectName: project.name });
|
|
6695
|
+
this.callbacks.onBacklinksSyncRequested(project.name);
|
|
6696
|
+
return;
|
|
6697
|
+
}
|
|
6684
6698
|
const projectLocations = project.locations;
|
|
6685
6699
|
let resolvedLocation;
|
|
6686
6700
|
if (project.defaultLocation) {
|
|
@@ -9452,6 +9466,29 @@ async function createServer(opts) {
|
|
|
9452
9466
|
},
|
|
9453
9467
|
onDataRefreshRequested: (projectName) => {
|
|
9454
9468
|
void refreshAllIntegrations(aeroClient, projectName);
|
|
9469
|
+
},
|
|
9470
|
+
onBacklinksSyncRequested: (projectName) => {
|
|
9471
|
+
void (async () => {
|
|
9472
|
+
const probed = await probeLatestRelease().catch((err) => {
|
|
9473
|
+
app.log.warn({ projectName, err }, "Scheduled backlinks sync: latest-release probe failed");
|
|
9474
|
+
return null;
|
|
9475
|
+
});
|
|
9476
|
+
if (!probed) return;
|
|
9477
|
+
const alreadySynced = opts.db.select().from(ccReleaseSyncs).where(and13(
|
|
9478
|
+
eq17(ccReleaseSyncs.release, probed.release),
|
|
9479
|
+
eq17(ccReleaseSyncs.status, CcReleaseSyncStatuses.ready)
|
|
9480
|
+
)).limit(1).get();
|
|
9481
|
+
if (alreadySynced) {
|
|
9482
|
+
app.log.info({ projectName, release: probed.release }, "Scheduled backlinks sync: already up to date, skipping");
|
|
9483
|
+
return;
|
|
9484
|
+
}
|
|
9485
|
+
aeroClient.backlinksTriggerSync(probed.release).catch((err) => {
|
|
9486
|
+
app.log.error(
|
|
9487
|
+
{ projectName, release: probed.release, err: err instanceof Error ? err.message : String(err) },
|
|
9488
|
+
"Scheduled backlinks sync failed"
|
|
9489
|
+
);
|
|
9490
|
+
});
|
|
9491
|
+
})();
|
|
9455
9492
|
}
|
|
9456
9493
|
});
|
|
9457
9494
|
const providerSummary = API_ADAPTERS.map((adapter) => ({
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
trafficConnectVercelRequestSchema,
|
|
23
23
|
trafficConnectWordpressRequestSchema,
|
|
24
24
|
trafficEventKindSchema
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-D75O5A27.js";
|
|
26
26
|
|
|
27
27
|
// src/config.ts
|
|
28
28
|
import fs from "fs";
|
|
@@ -5131,6 +5131,20 @@ var canonryMcpTools = [
|
|
|
5131
5131
|
openApiOperations: ["GET /api/v1/projects/{name}/report"],
|
|
5132
5132
|
handler: (client2, input) => client2.getReport(input.project)
|
|
5133
5133
|
}),
|
|
5134
|
+
defineTool({
|
|
5135
|
+
name: "canonry_analytics_metrics",
|
|
5136
|
+
title: "Get citation & mention trend",
|
|
5137
|
+
description: "Citation and mention rates over time for a project, bucketed adaptively (daily \u2192 monthly by span) and probe-excluded. Returns overall + per-provider window aggregates AND a per-bucket `byProvider` breakdown so you can read how each engine's cited/mentioned rate moved run-over-run \u2014 the same data the dashboard's \"Citations & mentions over time\" chart plots. Includes trend direction (improving/declining/stable) for both signals and query-set-change annotations. Filter the range with `window` (7d/30d/90d/all).",
|
|
5138
|
+
access: "read",
|
|
5139
|
+
tier: "monitoring",
|
|
5140
|
+
inputSchema: z2.object({
|
|
5141
|
+
project: projectNameSchema,
|
|
5142
|
+
window: analyticsWindowSchema.optional().describe("Time range: 7d, 30d, 90d, or all (default all).")
|
|
5143
|
+
}),
|
|
5144
|
+
annotations: readAnnotations(),
|
|
5145
|
+
openApiOperations: ["GET /api/v1/projects/{name}/analytics/metrics"],
|
|
5146
|
+
handler: (client2, input) => client2.getAnalyticsMetrics(input.project, input.window)
|
|
5147
|
+
}),
|
|
5134
5148
|
defineTool({
|
|
5135
5149
|
name: "canonry_search",
|
|
5136
5150
|
title: "Search project (composite)",
|