@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.
Files changed (34) hide show
  1. package/assets/assets/{AuditHistoryPanel-CzjskfMX.js → AuditHistoryPanel-Dga03Niw.js} +1 -1
  2. package/assets/assets/BacklinksPage-CfodWuIt.js +1 -0
  3. package/assets/assets/Hint-DICI5Jq9.js +1 -0
  4. package/assets/assets/{HistoryPage-BZgVoYGm.js → HistoryPage-BN_vTU5L.js} +1 -1
  5. package/assets/assets/{MeasurementPropertyPage-EBI5sn-D.js → MeasurementPropertyPage-CjiyzOmE.js} +1 -1
  6. package/assets/assets/{ProjectPage-lGGjM_qj.js → ProjectPage-AxclA3YC.js} +6 -6
  7. package/assets/assets/{RunsPage-CuHi8241.js → RunsPage-Ca_ziCGC.js} +1 -1
  8. package/assets/assets/{SettingsPage-D0fgAoVu.js → SettingsPage-SO1xl0d3.js} +1 -1
  9. package/assets/assets/SiteHealthSection-C9JgRzzs.js +4 -0
  10. package/assets/assets/{TrafficPage-DD65RqeR.js → TrafficPage-DrcbXNQB.js} +1 -1
  11. package/assets/assets/{TrafficSourceDetailPage-CFVCj13J.js → TrafficSourceDetailPage-HDZGKgyd.js} +1 -1
  12. package/assets/assets/{extract-error-message-D118msoE.js → extract-error-message-D48vwe7I.js} +1 -1
  13. package/assets/assets/index-BaBHBReI.js +86 -0
  14. package/assets/assets/{react-sigma_core.esm.min-DdlHLMEz.js → react-sigma_core.esm.min-DVHs4npB.js} +1 -1
  15. package/assets/assets/{v2-overview-adapter-CoCb2aB0.js → v2-overview-adapter-CTEXuiRt.js} +1 -1
  16. package/assets/assets/{vendor-lucide-N6vOpZmh.js → vendor-lucide-Y6jANGfG.js} +1 -1
  17. package/assets/index.html +2 -2
  18. package/dist/{chunk-ORA5R7QM.js → chunk-3LPQ4JV5.js} +130 -103
  19. package/dist/{chunk-OPJCFDNR.js → chunk-4EDH2ORA.js} +3 -3
  20. package/dist/{chunk-MHB23E3N.js → chunk-MIRAKDRW.js} +106 -79
  21. package/dist/{chunk-C6GWKYGE.js → chunk-NPNU6UHD.js} +5 -4
  22. package/dist/{chunk-PLS4EM2Y.js → chunk-P2XY5YX7.js} +2 -2
  23. package/dist/{chunk-FK7AWV57.js → chunk-QAIJH74T.js} +1 -1
  24. package/dist/{chunk-ZQ7C6IFA.js → chunk-YJS4OE6I.js} +614 -578
  25. package/dist/cli.js +13 -15
  26. package/dist/{demo-server-WQDHQG6P.js → demo-server-54SLPSJF.js} +6 -5
  27. package/dist/index.d.ts +7 -5
  28. package/dist/index.js +6 -6
  29. package/dist/{intelligence-service-JWZRZ6JZ.js → intelligence-service-62CEP6M2.js} +2 -2
  30. package/dist/mcp.js +4 -4
  31. package/package.json +14 -14
  32. package/assets/assets/BacklinksPage-ToENGBdp.js +0 -1
  33. package/assets/assets/SiteHealthSection-DhLxldgs.js +0 -4
  34. 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-ORA5R7QM.js";
37
+ } from "./chunk-3LPQ4JV5.js";
37
38
  import {
38
39
  autoSyncSkills,
39
40
  formatAutoSyncNotice
40
- } from "./chunk-OPJCFDNR.js";
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-PLS4EM2Y.js";
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-C6GWKYGE.js";
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-FK7AWV57.js";
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-ZQ7C6IFA.js";
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-MHB23E3N.js";
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-WQDHQG6P.js");
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-JWZRZ6JZ.js");
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
- " For remote/exposed hosts, complete dashboard password setup from loopback first.",
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 (shouldWarnAboutRemoteSetup(host)) {
18349
- console.log("First-run dashboard password setup is unauthenticated only on loopback; complete setup from this machine first or use a bearer cnry_... key.");
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-C6GWKYGE.js";
8
+ } from "./chunk-NPNU6UHD.js";
9
9
  import {
10
10
  PACKAGE_VERSION,
11
11
  canonryMcpTools
12
- } from "./chunk-FK7AWV57.js";
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-ZQ7C6IFA.js";
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-MHB23E3N.js";
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 < right ? -1 : left > right ? 1 : 0);
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 unauthenticated first-run dashboard password setup: on a
466
- * loopback bind only local processes can reach `/session/setup`, so claiming
467
- * the initial password without the API key is safe. On a non-loopback bind
468
- * (`0.0.0.0`, a LAN IP) the setup endpoint additionally requires a valid
469
- * bearer key so a remote first-visitor cannot mint a full-access session.
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-ORA5R7QM.js";
6
+ } from "./chunk-3LPQ4JV5.js";
7
7
  import {
8
8
  loadConfig
9
- } from "./chunk-PLS4EM2Y.js";
10
- import "./chunk-C6GWKYGE.js";
11
- import "./chunk-FK7AWV57.js";
12
- import "./chunk-ZQ7C6IFA.js";
13
- import "./chunk-MHB23E3N.js";
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,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  HISTORY_WINDOW_RUNS,
3
3
  IntelligenceService
4
- } from "./chunk-ZQ7C6IFA.js";
5
- import "./chunk-MHB23E3N.js";
4
+ } from "./chunk-YJS4OE6I.js";
5
+ import "./chunk-MIRAKDRW.js";
6
6
  export {
7
7
  HISTORY_WINDOW_RUNS,
8
8
  IntelligenceService
package/dist/mcp.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  autoSyncSkills
3
- } from "./chunk-OPJCFDNR.js";
3
+ } from "./chunk-4EDH2ORA.js";
4
4
  import {
5
5
  createApiClient,
6
6
  createCanonryMcpServer
7
- } from "./chunk-PLS4EM2Y.js";
8
- import "./chunk-FK7AWV57.js";
7
+ } from "./chunk-P2XY5YX7.js";
8
+ import "./chunk-QAIJH74T.js";
9
9
  import {
10
10
  isReadOnlyKey,
11
11
  updateCheckEnvOptOut
12
- } from "./chunk-MHB23E3N.js";
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.1",
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-api-client": "0.0.0",
90
+ "@ainyc/canonry-config": "0.0.0",
93
91
  "@ainyc/canonry-db": "0.0.0",
94
- "@ainyc/canonry-integration-bing": "0.0.0",
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-commoncrawl": "0.0.0",
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-google-places": "0.0.0",
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-openai-ads": "0.0.0",
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-integration-wordpress": "0.0.0",
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};