@canonry/canonry 7.17.1 → 7.17.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/{AuditHistoryPanel-CzjskfMX.js → AuditHistoryPanel-Dga03Niw.js} +1 -1
- package/assets/assets/BacklinksPage-CfodWuIt.js +1 -0
- package/assets/assets/Hint-DICI5Jq9.js +1 -0
- package/assets/assets/{HistoryPage-BZgVoYGm.js → HistoryPage-BN_vTU5L.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-EBI5sn-D.js → MeasurementPropertyPage-CjiyzOmE.js} +1 -1
- package/assets/assets/{ProjectPage-lGGjM_qj.js → ProjectPage-AxclA3YC.js} +6 -6
- package/assets/assets/{RunsPage-CuHi8241.js → RunsPage-Ca_ziCGC.js} +1 -1
- package/assets/assets/{SettingsPage-D0fgAoVu.js → SettingsPage-SO1xl0d3.js} +1 -1
- package/assets/assets/SiteHealthSection-C9JgRzzs.js +4 -0
- package/assets/assets/{TrafficPage-DD65RqeR.js → TrafficPage-DrcbXNQB.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-CFVCj13J.js → TrafficSourceDetailPage-HDZGKgyd.js} +1 -1
- package/assets/assets/{extract-error-message-D118msoE.js → extract-error-message-D48vwe7I.js} +1 -1
- package/assets/assets/index-BaBHBReI.js +86 -0
- package/assets/assets/{react-sigma_core.esm.min-DdlHLMEz.js → react-sigma_core.esm.min-DVHs4npB.js} +1 -1
- package/assets/assets/{v2-overview-adapter-CoCb2aB0.js → v2-overview-adapter-CTEXuiRt.js} +1 -1
- package/assets/assets/{vendor-lucide-N6vOpZmh.js → vendor-lucide-Y6jANGfG.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-ORA5R7QM.js → chunk-3LPQ4JV5.js} +130 -103
- package/dist/{chunk-OPJCFDNR.js → chunk-4EDH2ORA.js} +3 -3
- package/dist/{chunk-MHB23E3N.js → chunk-MIRAKDRW.js} +106 -79
- package/dist/{chunk-C6GWKYGE.js → chunk-NPNU6UHD.js} +5 -4
- package/dist/{chunk-PLS4EM2Y.js → chunk-P2XY5YX7.js} +2 -2
- package/dist/{chunk-FK7AWV57.js → chunk-QAIJH74T.js} +1 -1
- package/dist/{chunk-ZQ7C6IFA.js → chunk-YJS4OE6I.js} +614 -578
- package/dist/cli.js +13 -15
- package/dist/{demo-server-WQDHQG6P.js → demo-server-54SLPSJF.js} +6 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +6 -6
- package/dist/{intelligence-service-JWZRZ6JZ.js → intelligence-service-62CEP6M2.js} +2 -2
- package/dist/mcp.js +4 -4
- package/package.json +14 -14
- package/assets/assets/BacklinksPage-ToENGBdp.js +0 -1
- package/assets/assets/SiteHealthSection-DhLxldgs.js +0 -4
- package/assets/assets/index-DxFd1t4G.js +0 -86
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
AERO_TOOL_PROFILES,
|
|
4
4
|
OPENAI_RETRIEVAL_CONTRACT,
|
|
5
|
+
allowsKeylessFirstRunSetup,
|
|
5
6
|
checkLatestVersionForCli,
|
|
6
7
|
cliRuntimeContext,
|
|
7
8
|
coerceAgentProvider,
|
|
@@ -33,11 +34,11 @@ import {
|
|
|
33
34
|
trackCliCommandFinished,
|
|
34
35
|
trackEvent,
|
|
35
36
|
waitForServerRuntimeStartup
|
|
36
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-3LPQ4JV5.js";
|
|
37
38
|
import {
|
|
38
39
|
autoSyncSkills,
|
|
39
40
|
formatAutoSyncNotice
|
|
40
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-4EDH2ORA.js";
|
|
41
42
|
import {
|
|
42
43
|
configExists,
|
|
43
44
|
createApiClient,
|
|
@@ -54,13 +55,13 @@ import {
|
|
|
54
55
|
saveConfig,
|
|
55
56
|
saveConfigPatch,
|
|
56
57
|
shouldPrintServeSkillsNudge
|
|
57
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-P2XY5YX7.js";
|
|
58
59
|
import {
|
|
59
60
|
DEFAULT_DEMO_TRUSTED_PROXIES,
|
|
60
61
|
trustedProxiesProblem,
|
|
61
62
|
trustedProxyProblem
|
|
62
63
|
} from "./chunk-RB2F4D3Z.js";
|
|
63
|
-
import "./chunk-
|
|
64
|
+
import "./chunk-NPNU6UHD.js";
|
|
64
65
|
import {
|
|
65
66
|
CliError,
|
|
66
67
|
EXIT_SYSTEM_ERROR,
|
|
@@ -72,7 +73,7 @@ import {
|
|
|
72
73
|
runMeasurementDraftAction,
|
|
73
74
|
systemError,
|
|
74
75
|
usageError
|
|
75
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-QAIJH74T.js";
|
|
76
77
|
import {
|
|
77
78
|
CLOUDFLARE_WORKER_BINDINGS,
|
|
78
79
|
CLOUDFLARE_WORKER_GENERATED_MARKER,
|
|
@@ -104,7 +105,7 @@ import {
|
|
|
104
105
|
rawEventSamples,
|
|
105
106
|
readMarketCompetitorNames,
|
|
106
107
|
runs
|
|
107
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-YJS4OE6I.js";
|
|
108
109
|
import {
|
|
109
110
|
AdsDeliverySnapshotStatuses,
|
|
110
111
|
AdsHistoricalCampaignRollupStatuses,
|
|
@@ -237,7 +238,7 @@ import {
|
|
|
237
238
|
visibilityCompareSelectionSchema,
|
|
238
239
|
visibilityReportRequestSchema,
|
|
239
240
|
winnabilityClassSchema
|
|
240
|
-
} from "./chunk-
|
|
241
|
+
} from "./chunk-MIRAKDRW.js";
|
|
241
242
|
|
|
242
243
|
// src/cli.ts
|
|
243
244
|
import { pathToFileURL } from "url";
|
|
@@ -787,7 +788,7 @@ function parseDemoTrustedProxies(values) {
|
|
|
787
788
|
async function demoCommand(options) {
|
|
788
789
|
const { host, port } = parseDemoListenOptions(options);
|
|
789
790
|
const trustProxy = parseDemoTrustedProxies(options.trustProxy);
|
|
790
|
-
const { createDemoServer } = await import("./demo-server-
|
|
791
|
+
const { createDemoServer } = await import("./demo-server-54SLPSJF.js");
|
|
791
792
|
const app = await createDemoServer({ trustProxy });
|
|
792
793
|
let stopping = false;
|
|
793
794
|
const stop = () => {
|
|
@@ -1201,7 +1202,7 @@ No DB writes performed. Re-run without --dry-run to apply.`);
|
|
|
1201
1202
|
}
|
|
1202
1203
|
}
|
|
1203
1204
|
async function backfillInsightsCommand(project2, opts) {
|
|
1204
|
-
const { IntelligenceService } = await import("./intelligence-service-
|
|
1205
|
+
const { IntelligenceService } = await import("./intelligence-service-62CEP6M2.js");
|
|
1205
1206
|
const config = loadConfig();
|
|
1206
1207
|
const db = createClient(config.database);
|
|
1207
1208
|
migrate(db);
|
|
@@ -17983,7 +17984,7 @@ function buildNextSteps() {
|
|
|
17983
17984
|
"",
|
|
17984
17985
|
" Map your public site and capture a persisted Page Health baseline.",
|
|
17985
17986
|
" AI Visibility is optional and can be configured after Page Health.",
|
|
17986
|
-
"
|
|
17987
|
+
" On a remote or proxied host, dashboard password setup asks for the root API key (apiKey in config.yaml).",
|
|
17987
17988
|
"",
|
|
17988
17989
|
"Prefer the terminal? The same flow as CLI commands:",
|
|
17989
17990
|
"",
|
|
@@ -18239,9 +18240,6 @@ function detectCanonryAgentPlugin(opts = {}) {
|
|
|
18239
18240
|
}
|
|
18240
18241
|
|
|
18241
18242
|
// src/commands/serve.ts
|
|
18242
|
-
function shouldWarnAboutRemoteSetup(host) {
|
|
18243
|
-
return !isLoopbackBindHost(host);
|
|
18244
|
-
}
|
|
18245
18243
|
function readServeOpenState(db) {
|
|
18246
18244
|
try {
|
|
18247
18245
|
const rows = db.select({
|
|
@@ -18345,8 +18343,8 @@ Received ${signal}, stopping server...`);
|
|
|
18345
18343
|
console.log(`
|
|
18346
18344
|
Canonry server running at ${url}`);
|
|
18347
18345
|
console.log(buildServeOpenLine({ url, ...readServeOpenState(db) }));
|
|
18348
|
-
if (
|
|
18349
|
-
console.log("
|
|
18346
|
+
if (!allowsKeylessFirstRunSetup(app)) {
|
|
18347
|
+
console.log(isLoopbackBindHost(host) ? "This server is configured to be reached through a proxy or external URL (publicUrl, apiUrl, basePath, or CANONRY_TRUST_PROXY), so first-run dashboard password setup requires the root API key (apiKey in config.yaml)." : "This server is not bound to loopback, so first-run dashboard password setup requires the root API key (apiKey in config.yaml).");
|
|
18350
18348
|
}
|
|
18351
18349
|
console.log("Press Ctrl+C to stop.\n");
|
|
18352
18350
|
const nudge = getMissingUserSkillsNudge(process.env.HOME, getAgentPluginState());
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
computeFactorAverages,
|
|
6
6
|
layoutSiteCrawlGraphInput,
|
|
7
7
|
persistSiteCrawlGraphLayout
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-NPNU6UHD.js";
|
|
9
9
|
import {
|
|
10
10
|
PACKAGE_VERSION,
|
|
11
11
|
canonryMcpTools
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-QAIJH74T.js";
|
|
13
13
|
import {
|
|
14
14
|
HISTORY_WINDOW_RUNS,
|
|
15
15
|
IntelligenceService,
|
|
@@ -85,7 +85,7 @@ import {
|
|
|
85
85
|
siteCrawlPages,
|
|
86
86
|
siteCrawlSnapshots,
|
|
87
87
|
trafficSources
|
|
88
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-YJS4OE6I.js";
|
|
89
89
|
import {
|
|
90
90
|
RunKinds,
|
|
91
91
|
SiteCrawlFetchStates,
|
|
@@ -98,6 +98,7 @@ import {
|
|
|
98
98
|
canonicalMeasurementExecutionIdentityJson,
|
|
99
99
|
canonicalMeasurementPlanV2Json,
|
|
100
100
|
canonicalSimpleMeasurementDefinitionJson,
|
|
101
|
+
compareText,
|
|
101
102
|
computeCompetitorOverlap,
|
|
102
103
|
deriveSiteHealthState,
|
|
103
104
|
determineAnswerMentioned,
|
|
@@ -114,7 +115,7 @@ import {
|
|
|
114
115
|
roundPreservingTotal,
|
|
115
116
|
siteAuditPageFactorSchema,
|
|
116
117
|
wilsonInterval
|
|
117
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-MIRAKDRW.js";
|
|
118
119
|
|
|
119
120
|
// src/demo-server.ts
|
|
120
121
|
import { dirname, join as join2 } from "path";
|
|
@@ -273,7 +274,7 @@ function engineOrder(left, right) {
|
|
|
273
274
|
const index = ENGINE_ORDER.indexOf(provider);
|
|
274
275
|
return index === -1 ? ENGINE_ORDER.length : index;
|
|
275
276
|
};
|
|
276
|
-
return rank(left) - rank(right) || (left
|
|
277
|
+
return rank(left) - rank(right) || compareText(left, right);
|
|
277
278
|
}
|
|
278
279
|
function tally(answers) {
|
|
279
280
|
return {
|
package/dist/index.d.ts
CHANGED
|
@@ -462,11 +462,13 @@ declare function createServer(opts: {
|
|
|
462
462
|
logger?: boolean;
|
|
463
463
|
/**
|
|
464
464
|
* The network interface the server will bind to (from `canonry serve`).
|
|
465
|
-
* Used to gate the
|
|
466
|
-
*
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
*
|
|
465
|
+
* Used to gate the first-run dashboard password setup: only on a loopback
|
|
466
|
+
* bind, and only while config names no other way in
|
|
467
|
+
* (`configuresExternalAccess`), can a direct local request (see
|
|
468
|
+
* `isDirectLocalRequest`) claim the initial password without the root API
|
|
469
|
+
* key. On a non-loopback bind (`0.0.0.0`, a LAN IP) every setup request must
|
|
470
|
+
* present the root key, so a remote first visitor cannot mint a standing
|
|
471
|
+
* full-access credential.
|
|
470
472
|
* Defaults to loopback when unset (programmatic/test callers).
|
|
471
473
|
*/
|
|
472
474
|
host?: string;
|
package/dist/index.js
CHANGED
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
createGoogleMarketingCredentialStore,
|
|
4
4
|
createGoogleMarketingRuntime,
|
|
5
5
|
createServer
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-3LPQ4JV5.js";
|
|
7
7
|
import {
|
|
8
8
|
loadConfig
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-P2XY5YX7.js";
|
|
10
|
+
import "./chunk-NPNU6UHD.js";
|
|
11
|
+
import "./chunk-QAIJH74T.js";
|
|
12
|
+
import "./chunk-YJS4OE6I.js";
|
|
13
|
+
import "./chunk-MIRAKDRW.js";
|
|
14
14
|
export {
|
|
15
15
|
GoogleMarketingRuntimeError,
|
|
16
16
|
createGoogleMarketingCredentialStore,
|
package/dist/mcp.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
autoSyncSkills
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-4EDH2ORA.js";
|
|
4
4
|
import {
|
|
5
5
|
createApiClient,
|
|
6
6
|
createCanonryMcpServer
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-P2XY5YX7.js";
|
|
8
|
+
import "./chunk-QAIJH74T.js";
|
|
9
9
|
import {
|
|
10
10
|
isReadOnlyKey,
|
|
11
11
|
updateCheckEnvOptOut
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-MIRAKDRW.js";
|
|
13
13
|
|
|
14
14
|
// src/mcp/cli.ts
|
|
15
15
|
import { randomUUID } from "crypto";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonry/canonry",
|
|
3
|
-
"version": "7.17.
|
|
3
|
+
"version": "7.17.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Self-hosted AI visibility (AEO) platform: track how ChatGPT, Claude, Gemini, and Perplexity cite your domain, join it with Search Console, GA4, server-side traffic, and paid media, and fix what you find through agent tools (CLI, REST, MCP). Local SQLite.",
|
|
6
6
|
"keywords": [
|
|
@@ -85,32 +85,32 @@
|
|
|
85
85
|
"@types/node-cron": "^3.0.11",
|
|
86
86
|
"tsup": "^8.5.1",
|
|
87
87
|
"tsx": "^4.19.0",
|
|
88
|
-
"@ainyc/canonry-web": "0.0.0",
|
|
89
88
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
90
|
-
"@ainyc/canonry-config": "0.0.0",
|
|
91
89
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
92
|
-
"@ainyc/canonry-
|
|
90
|
+
"@ainyc/canonry-config": "0.0.0",
|
|
93
91
|
"@ainyc/canonry-db": "0.0.0",
|
|
94
|
-
"@ainyc/canonry-
|
|
92
|
+
"@ainyc/canonry-web": "0.0.0",
|
|
93
|
+
"@ainyc/canonry-api-client": "0.0.0",
|
|
95
94
|
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
96
|
-
"@ainyc/canonry-integration-
|
|
97
|
-
"@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
|
|
98
|
-
"@ainyc/canonry-integration-google": "0.0.0",
|
|
99
|
-
"@ainyc/canonry-integration-google-ads": "0.0.0",
|
|
95
|
+
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
100
96
|
"@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
|
|
101
|
-
"@ainyc/canonry-integration-
|
|
97
|
+
"@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
|
|
98
|
+
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
102
99
|
"@ainyc/canonry-integration-google-business-profile": "0.0.0",
|
|
100
|
+
"@ainyc/canonry-integration-google-ads": "0.0.0",
|
|
101
|
+
"@ainyc/canonry-integration-google": "0.0.0",
|
|
103
102
|
"@ainyc/canonry-integration-google-tag-manager": "0.0.0",
|
|
104
|
-
"@ainyc/canonry-integration-
|
|
103
|
+
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
105
104
|
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
105
|
+
"@ainyc/canonry-integration-openai-ads": "0.0.0",
|
|
106
|
+
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
106
107
|
"@ainyc/canonry-intelligence": "0.0.0",
|
|
107
108
|
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
108
|
-
"@ainyc/canonry-
|
|
109
|
+
"@ainyc/canonry-provider-local": "0.0.0",
|
|
109
110
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
110
|
-
"@ainyc/canonry-provider-muse": "0.0.0",
|
|
111
111
|
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
112
|
+
"@ainyc/canonry-provider-muse": "0.0.0",
|
|
112
113
|
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
113
|
-
"@ainyc/canonry-provider-local": "0.0.0",
|
|
114
114
|
"@ainyc/canonry-provider-perplexity": "0.0.0",
|
|
115
115
|
"@ainyc/canonry-integration-typesafe": "0.0.0"
|
|
116
116
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as n,j as e}from"./vendor-tanstack-ZXXkndVj.js";import{dY as W,aF as H,dZ as U,d_ as Y,d$ as J,v as x,T as j,y as u,B as w,D as $,e0 as K,e1 as V,aI as Z,e2 as X}from"./index-DxFd1t4G.js";import{I as ee,T as se,E as te,j as ae,O as ne,J as re}from"./vendor-lucide-N6vOpZmh.js";import"./vendor-radix-twS1M3FF.js";import"./vendor-recharts-D-cUuLZo.js";import"./vendor-markdown-B4giJcws.js";import"./vendor-yaml-GWJz5H2G.js";function g({children:t,label:h="More info",placement:a="top",className:i}){const d=n.useId(),[y,c]=n.useState(!1);return e.jsxs("span",{className:`relative inline-flex ${i??""}`,children:[e.jsx("button",{type:"button","aria-label":h,"aria-describedby":y?d:void 0,className:"inline-flex h-4 w-4 items-center justify-center rounded-full text-muted hover:text-strong focus:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500",onMouseEnter:()=>c(!0),onMouseLeave:()=>c(!1),onFocus:()=>c(!0),onBlur:()=>c(!1),children:e.jsx(re,{className:"h-3.5 w-3.5","aria-hidden":!0})}),y&&e.jsx("span",{id:d,role:"tooltip",className:`absolute z-50 w-64 rounded border border-strong bg-bg-elevated px-3 py-2 text-xs font-normal leading-relaxed text-strong shadow-lg ${a==="top"?"bottom-full mb-2":"top-full mt-2"} left-1/2 -translate-x-1/2 whitespace-normal`,children:t})]})}const le="https://commoncrawl.org/web-graphs";function S(t){return t==null?"—":t>=1e12?`${(t/1e12).toFixed(1)} TB`:t>=1e9?`${(t/1e9).toFixed(1)} GB`:t>=1e6?`${(t/1e6).toFixed(1)} MB`:t>=1e3?`${(t/1e3).toFixed(1)} KB`:`${t} B`}function b(t){if(!t)return"—";const h=Date.now()-new Date(t).getTime(),a=Math.floor(h/6e4);if(a<1)return"just now";if(a<60)return`${a}m ago`;const i=Math.floor(a/60);return i<24?`${i}h ago`:`${Math.floor(i/24)}d ago`}function C(t){switch(t){case"ready":return"positive";case"failed":return"negative";case"downloading":case"querying":case"queued":return"caution"}}function me(){const[t,h]=n.useState(null),[a,i]=n.useState(null),[d,y]=n.useState([]),[c,P]=n.useState([]),[m,L]=n.useState(null),[B,D]=n.useState(!0),[R,I]=n.useState(!1),[p,E]=n.useState(!1),[N,v]=n.useState(""),[M,k]=n.useState(!1),[A,l]=n.useState(null),[F,o]=n.useState(null),f=n.useCallback(async()=>{D(!0),l(null);try{const[s,r,Q,_,z]=await Promise.all([W(),H().catch(()=>null),U().catch(()=>[]),Y().catch(()=>[]),J().catch(()=>null)]);h(s),i(r),y(Q),P(_),L(z)}catch(s){l(s instanceof Error?s.message:"Failed to load backlinks status")}finally{D(!1)}},[]);n.useEffect(()=>{f()},[f]);async function T(){I(!0),l(null),o(null);try{const s=await K();o(s.alreadyPresent?`DuckDB already installed (${s.version}).`:`Installed DuckDB ${s.version}.`),await f()}catch(s){l(s instanceof Error?s.message:"Failed to install DuckDB")}finally{I(!1)}}async function q(){const s=N.trim()||void 0;E(!0),l(null),o(null);try{const r=await V(s);o(s?`Queued sync for ${r.release}. Download + query runs in the background.`:`Queued sync for auto-discovered release ${r.release}. Download + query runs in the background.`),v(""),k(!1),await f()}catch(r){r instanceof Z&&r.code==="MISSING_DEPENDENCY"?l("DuckDB is not installed. Install it first."):l(r instanceof Error?r.message:"Failed to trigger sync")}finally{E(!1)}}async function G(s){l(null),o(null);try{await X(s),o(`Pruned cached release ${s}.`),await f()}catch(r){l(r instanceof Error?r.message:"Failed to prune release")}}const O=a?.status==="ready"&&c.every(s=>s.release!==a.release);return e.jsxs("div",{className:"page-container",children:[e.jsx("div",{className:"page-header",children:e.jsxs("div",{className:"page-header-left",children:[e.jsx("h1",{className:"page-title",children:"Backlink data"}),e.jsx("p",{className:"page-subtitle",children:"Manage the shared backlink source and review its latest data."})]})}),A&&e.jsx(x,{className:"surface-card p-4 mb-4 border-negative-800/60",children:e.jsx("p",{className:"text-sm text-negative",children:A})}),F&&e.jsx(x,{className:"surface-card p-4 mb-4 border-positive-800/60",children:e.jsx("p",{className:"text-sm text-positive",children:F})}),e.jsxs("section",{className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Readiness"}),e.jsx("h2",{children:"Backlink source"})]}),t?.duckdbInstalled?e.jsx(j,{tone:"positive",children:"Installed"}):e.jsx(j,{tone:"caution",children:"Not installed"})]}),e.jsx(x,{className:"surface-card p-4",children:B?e.jsx("p",{className:"text-sm text-muted",children:"Checking…"}):t?.duckdbInstalled?e.jsx("p",{className:"text-sm text-secondary",children:"Ready to sync a Common Crawl release."}):e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsx("p",{className:"text-sm text-secondary",children:"Install the local query engine to enable release syncs."}),!u()&&e.jsxs(w,{type:"button",size:"sm",disabled:R,onClick:$(T),children:[e.jsx(ee,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),R?"Installing…":"Install DuckDB"]})]})})]}),e.jsxs("section",{className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Latest sync"}),e.jsxs("h2",{className:"flex items-center gap-2",children:["Release sync",e.jsx(g,{label:"What is a release sync?",children:"A release sync downloads one Common Crawl dump (~16 GB) and extracts backlinks for every project in this workspace in one pass. This is the heavy job — subsequent per-project re-runs skip the download and just re-query the cached files."})]})]}),a&&e.jsx(j,{tone:C(a.status),children:a.status})]}),e.jsxs(x,{className:"surface-card p-5",children:[a?e.jsxs("div",{className:"space-y-2 text-sm",children:[e.jsxs("p",{className:"text-strong",children:["Release ",e.jsx("code",{className:"text-neutral",children:a.release})]}),a.phaseDetail&&e.jsx("p",{className:"text-secondary",children:a.phaseDetail}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-4 gap-4 text-xs text-muted pt-2",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Projects"}),e.jsx("p",{className:"text-neutral mt-0.5",children:a.projectsProcessed??"—"})]}),e.jsxs("div",{children:[e.jsxs("p",{className:"text-faint uppercase tracking-wide flex items-center gap-1",children:["Rows",e.jsx(g,{label:"What are rows?",children:"Total number of (project, referring domain) pairs persisted in SQLite from this sync, across every project in the workspace."})]}),e.jsx("p",{className:"text-neutral mt-0.5",children:a.domainsDiscovered??"—"})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Started"}),e.jsx("p",{className:"text-neutral mt-0.5",children:b(a.downloadStartedAt??a.createdAt)})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Finished"}),e.jsx("p",{className:"text-neutral mt-0.5",children:b(a.queryFinishedAt)})]})]}),a.error&&e.jsx("p",{className:"text-sm text-negative-400 pt-2",children:a.error})]}):e.jsx("p",{className:"text-sm text-muted",children:"No release sync has run in this workspace yet."}),O&&e.jsx("div",{className:"mt-4 rounded border border-caution-800/60 bg-caution-950/20 p-3",children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(se,{className:"h-4 w-4 text-caution-400 shrink-0 mt-0.5","aria-hidden":!0}),e.jsxs("div",{className:"text-sm text-neutral leading-relaxed",children:[e.jsx("p",{className:"font-medium text-caution-200",children:"Cached files for this release are missing."}),e.jsx("p",{className:"mt-1 text-secondary",children:"Sync this release again, or sync the newest release, before refreshing individual projects."})]})]})}),e.jsxs("div",{className:"mt-4 rounded border border-base bg-bg-elevated/40 p-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 mb-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] uppercase tracking-wide text-muted",children:"Auto-detected release"}),m?e.jsxs("p",{className:"text-sm text-strong mt-0.5",children:[e.jsx("code",{className:"text-heading",children:m.release}),e.jsxs("span",{className:"ml-2 text-xs text-muted",children:["Vertex ",S(m.vertexBytes),", edges ",S(m.edgesBytes)]})]}):e.jsx("p",{className:"text-sm text-muted mt-0.5",children:B?"Checking Common Crawl…":"Could not find a release. Choose one below."}),e.jsxs("a",{href:le,target:"_blank",rel:"noopener noreferrer",className:"mt-1 inline-flex items-center gap-1 text-xs text-secondary hover:text-strong focus:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",children:["Browse all Common Crawl web-graph releases",e.jsx(te,{className:"h-3 w-3","aria-hidden":!0})]})]}),!u()&&e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[e.jsxs(w,{type:"button",size:"sm",disabled:p||!t?.duckdbInstalled||!m&&!N.trim(),onClick:$(q),children:[e.jsx(ae,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),p?"Queuing…":"Run sync"]}),e.jsxs(g,{label:"What does Run sync do?",children:[e.jsxs("span",{className:"block",children:["Downloads the auto-detected (or chosen) Common Crawl release (~16 GB) to"," ",e.jsx("code",{className:"text-neutral",children:"~/.canonry/cache/commoncrawl/"}),", then runs a single DuckDB query that extracts referring domains for every project in this workspace."]}),e.jsxs("span",{className:"mt-2 block text-secondary",children:["First time for a release: ",e.jsx("span",{className:"text-strong",children:"~10–20 min download + ~5 min query"}),". Re-running the same release later: ",e.jsx("span",{className:"text-strong",children:"skips download, just re-queries"})," (~5 min)."]})]})]})]}),u()?null:M?e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("input",{type:"text",className:"flex-1 min-w-[240px] rounded border border-strong bg-transparent px-2.5 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none",placeholder:"cc-main-2026-jan-feb-mar",value:N,onChange:s=>v(s.target.value),disabled:p,autoFocus:!0}),e.jsx("button",{type:"button",className:"text-sm text-secondary hover:text-neutral focus:text-neutral focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",onClick:()=>{v(""),k(!1)},disabled:p,children:"Cancel"})]}):e.jsx("button",{type:"button",className:"text-sm text-secondary hover:text-neutral focus:text-neutral focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",onClick:()=>k(!0),disabled:p,children:"Use a different release →"})]}),!t?.duckdbInstalled&&e.jsx("p",{className:"text-sm text-secondary mt-2",children:"Install DuckDB first to enable sync."})]})]}),e.jsxs("details",{className:"page-section-divider group",children:[e.jsx("summary",{className:"cursor-pointer text-sm font-medium text-secondary hover:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",children:"Technical details and cache"}),e.jsxs("div",{className:"mt-4",children:[e.jsx("p",{className:"text-sm text-secondary mb-3",children:"Cached releases support project re-extracts. Pruning a release does not remove saved backlink results."}),e.jsx(x,{className:"surface-card overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-base text-left text-xs uppercase tracking-wide text-faint",children:[e.jsx("th",{className:"px-4 py-2 font-medium",children:"Release"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Sync status"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Size"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Last used"}),!u()&&e.jsx("th",{className:"px-4 py-2 font-medium sr-only",children:"Actions"})]})}),e.jsxs("tbody",{children:[c.map(s=>e.jsxs("tr",{className:"border-b border-mono-900 last:border-0",children:[e.jsx("td",{className:"px-4 py-2 text-strong",children:e.jsx("code",{children:s.release})}),e.jsx("td",{className:"px-4 py-2",children:s.syncStatus?e.jsx(j,{tone:C(s.syncStatus),children:s.syncStatus}):e.jsx("span",{className:"text-faint",children:"—"})}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:S(s.bytes)}),e.jsx("td",{className:"px-4 py-2 text-secondary",children:b(s.lastUsedAt)}),!u()&&e.jsx("td",{className:"px-4 py-2 text-right",children:e.jsxs("div",{className:"inline-flex items-center gap-1",children:[e.jsxs(w,{type:"button",variant:"outline",size:"sm",onClick:()=>{G(s.release)},children:[e.jsx(ne,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),"Prune"]}),e.jsx(g,{label:"What does Prune do?",placement:"top",children:"Deletes the ~16 GB cache for this release from disk. Backlink results already in SQLite remain untouched. To re-run extracts against this release, you’d have to sync it again (another ~16 GB download)."})]})})]},s.release)),c.length===0&&e.jsx("tr",{children:e.jsx("td",{className:"px-4 py-4 text-sm text-muted",colSpan:u()?4:5,children:"No cached releases on this machine. If you ran a sync from a different machine (or deleted the cache), the backlink data is still in the database — but you’ll need to re-sync a release to run new extracts."})})]})]})}),e.jsx("p",{className:"mt-3 text-xs text-muted",children:"Common Crawl files are stored locally. DuckDB reads them; Canonry stores results in its normal database."})]})]}),d.length>1&&e.jsxs("section",{className:"page-section-divider",children:[e.jsx("div",{className:"section-head section-head-inline",children:e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"History"}),e.jsx("h2",{children:"Past release syncs"})]})}),e.jsx(x,{className:"surface-card overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-base text-left text-xs uppercase tracking-wide text-faint",children:[e.jsx("th",{className:"px-4 py-2 font-medium",children:"Release"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Status"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Projects"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Rows"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Finished"})]})}),e.jsx("tbody",{children:d.map(s=>e.jsxs("tr",{className:"border-b border-mono-900 last:border-0",children:[e.jsx("td",{className:"px-4 py-2 text-strong",children:e.jsx("code",{children:s.release})}),e.jsx("td",{className:"px-4 py-2",children:e.jsx(j,{tone:C(s.status),children:s.status})}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:s.projectsProcessed??"—"}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:s.domainsDiscovered??"—"}),e.jsx("td",{className:"px-4 py-2 text-secondary",children:b(s.queryFinishedAt??s.updatedAt)})]},s.id))})]})})]})]})}export{me as BacklinksPage};
|