@gscdump/cli 0.40.2 → 1.0.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 -1
- package/dist/_chunks/auth.mjs +1 -1
- package/dist/_chunks/auth2.mjs +1 -1
- package/dist/_chunks/context.mjs +1 -1
- package/dist/_chunks/doctor.mjs +1 -1
- package/dist/_chunks/entities.mjs +1 -2
- package/dist/_chunks/error-handler.mjs +20 -1
- package/dist/_chunks/indexing.mjs +1 -1
- package/dist/_chunks/init.mjs +1 -1
- package/dist/_chunks/inspect.mjs +1 -1
- package/dist/_chunks/mcp.mjs +2 -2
- package/dist/_chunks/query.mjs +1 -1
- package/dist/_chunks/sitemaps.mjs +1 -1
- package/dist/_chunks/sites.mjs +1 -1
- package/dist/_chunks/sync.mjs +2 -3
- package/dist/_chunks/utils.mjs +26 -2
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://npm.chart.dev/@gscdump/cli)
|
|
5
5
|
[](https://github.com/harlan-zw/gscdump/blob/main/LICENSE)
|
|
6
6
|
|
|
7
|
-
> CLI for Google Search Console — sync to a local DuckDB/Parquet store, run typed queries, execute
|
|
7
|
+
> CLI for Google Search Console — sync to a local DuckDB/Parquet store, run typed queries, execute 29 SEO analyzers, and serve an MCP endpoint for AI assistants.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
package/dist/_chunks/auth.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import fs from "node:fs/promises";
|
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { isCancel, text } from "@clack/prompts";
|
|
9
9
|
import { err, ok, unwrapResult } from "gscdump/result";
|
|
10
|
-
import { createAuth } from "gscdump
|
|
10
|
+
import { createAuth } from "gscdump";
|
|
11
11
|
import { createServer } from "node:http";
|
|
12
12
|
import { JWT, OAuth2Client } from "google-auth-library";
|
|
13
13
|
import { ofetch } from "ofetch";
|
package/dist/_chunks/auth2.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { runSmokeTest } from "./init.mjs";
|
|
|
6
6
|
import process from "node:process";
|
|
7
7
|
import { defineCommand } from "citty";
|
|
8
8
|
import path from "node:path";
|
|
9
|
-
import { hasGscWriteScope, hasIndexingScope } from "gscdump
|
|
9
|
+
import { hasGscWriteScope, hasIndexingScope } from "gscdump";
|
|
10
10
|
import { ofetch } from "ofetch";
|
|
11
11
|
const AUTH_SUBCOMMANDS = [
|
|
12
12
|
"status",
|
package/dist/_chunks/context.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { logger } from "./utils.mjs";
|
|
|
3
3
|
import { resolveAuth } from "./auth.mjs";
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
import { cancel, isCancel, select } from "@clack/prompts";
|
|
6
|
-
import { googleSearchConsole } from "gscdump
|
|
6
|
+
import { googleSearchConsole } from "gscdump";
|
|
7
7
|
import { createNodeHarness } from "@gscdump/engine/node";
|
|
8
8
|
import { TABLE_DIMS, transformGscRow } from "@gscdump/engine/ingest";
|
|
9
9
|
import { allTables, inferTable } from "@gscdump/engine/schema";
|
package/dist/_chunks/doctor.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import process from "node:process";
|
|
|
8
8
|
import { defineCommand } from "citty";
|
|
9
9
|
import fs from "node:fs/promises";
|
|
10
10
|
import path from "node:path";
|
|
11
|
-
import { googleSearchConsole, hasGscWriteScope, hasIndexingScope } from "gscdump
|
|
11
|
+
import { googleSearchConsole, hasGscWriteScope, hasIndexingScope } from "gscdump";
|
|
12
12
|
import { ofetch } from "ofetch";
|
|
13
13
|
const REQUIRED_SCOPES = [
|
|
14
14
|
"https://www.googleapis.com/auth/webmasters",
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { OUTPUT_ARGS, applyOutputMode, logger, runWithConcurrency } from "./utils.mjs";
|
|
1
|
+
import { OUTPUT_ARGS, applyOutputMode, logger, progressBar, runWithConcurrency } from "./utils.mjs";
|
|
2
2
|
import { createCommandContext } from "./context.mjs";
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
import { readFile } from "node:fs/promises";
|
|
6
6
|
import { Buffer } from "node:buffer";
|
|
7
7
|
import { createIndexingMetadataStore, createInspectionStore, createSitemapStore } from "@gscdump/engine/entities";
|
|
8
|
-
import { progressBar } from "gscdump";
|
|
9
8
|
const INSPECTION_QPD_PER_PROPERTY = 2e3;
|
|
10
9
|
const INDEXING_NOT_FOUND_RE = /\b404\b|NOT_FOUND/i;
|
|
11
10
|
const INSPECTION_HISTORY_LOOKBACK_MONTHS = 24;
|
|
@@ -1,9 +1,28 @@
|
|
|
1
1
|
import { formatAuthProvenance, isAuthError } from "./auth.mjs";
|
|
2
2
|
import process from "node:process";
|
|
3
3
|
import { isQueryError } from "gscdump/query";
|
|
4
|
-
import {
|
|
4
|
+
import { classifyError } from "gscdump";
|
|
5
5
|
import { isAnalysisError } from "@gscdump/analysis/errors";
|
|
6
6
|
import { isEngineError } from "@gscdump/engine/errors";
|
|
7
|
+
const QUOTA_MESSAGE_RE = /quota|rate\s*limit/i;
|
|
8
|
+
function formatErrorForCli(cause) {
|
|
9
|
+
const error = classifyError(cause);
|
|
10
|
+
const lines = [`\x1B[31m${error.message}\x1B[0m`];
|
|
11
|
+
let suggestion = "";
|
|
12
|
+
switch (error.kind) {
|
|
13
|
+
case "auth-expired":
|
|
14
|
+
suggestion = "Run `gscdump auth` to re-authenticate.";
|
|
15
|
+
break;
|
|
16
|
+
case "rate-limited": {
|
|
17
|
+
const retryIn = error.retryAfter ? `${error.retryAfter}s` : "a few minutes";
|
|
18
|
+
if (QUOTA_MESSAGE_RE.test(error.message)) suggestion = error.message.includes("Indexing API") ? "Indexing API quota exhausted (~200/day). Try again tomorrow." : `Quota or rate limit hit (Search Analytics ~25000/day). Try again in ${retryIn}.`;
|
|
19
|
+
else suggestion = `Rate limited. Slow down requests. Try again in ${retryIn}.`;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (suggestion) lines.push("", suggestion);
|
|
24
|
+
return lines.join("\n");
|
|
25
|
+
}
|
|
7
26
|
function extractQueryError(error) {
|
|
8
27
|
if (isQueryError(error)) return error;
|
|
9
28
|
const tagged = error.queryError;
|
|
@@ -3,7 +3,7 @@ import { createCommandContext } from "./context.mjs";
|
|
|
3
3
|
import { gscErrorHandler } from "./error-handler.mjs";
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
import { defineCommand } from "citty";
|
|
6
|
-
import { batchRequestIndexing, fetchSitemapUrls, getIndexingMetadata, requestIndexing, runSequentialBatch } from "gscdump
|
|
6
|
+
import { batchRequestIndexing, fetchSitemapUrls, getIndexingMetadata, requestIndexing, runSequentialBatch } from "gscdump";
|
|
7
7
|
const RETRIES_ARG = { retries: {
|
|
8
8
|
type: "string",
|
|
9
9
|
description: "Override per-call retry count (default: 3)"
|
package/dist/_chunks/init.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { defineCommand } from "citty";
|
|
|
7
7
|
import fs from "node:fs/promises";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import { confirm, isCancel, text } from "@clack/prompts";
|
|
10
|
-
import { googleSearchConsole } from "gscdump
|
|
10
|
+
import { googleSearchConsole } from "gscdump";
|
|
11
11
|
const ENV_LINE_RE = /^([^=]+)=(.*)$/;
|
|
12
12
|
async function promptDataDir(existing) {
|
|
13
13
|
const fallback = existing ?? defaultDataDir();
|
package/dist/_chunks/inspect.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { createCommandContext } from "./context.mjs";
|
|
|
3
3
|
import { gscErrorHandler } from "./error-handler.mjs";
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
import { defineCommand } from "citty";
|
|
6
|
-
import { batchInspectUrls, fetchSitemapUrls } from "gscdump
|
|
6
|
+
import { batchInspectUrls, fetchSitemapUrls } from "gscdump";
|
|
7
7
|
function verdictTone(verdict) {
|
|
8
8
|
if (verdict === "PASS") return "\x1B[32m";
|
|
9
9
|
if (verdict === "NEUTRAL" || verdict === "PARTIAL") return "\x1B[33m";
|
package/dist/_chunks/mcp.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { isQueryError } from "gscdump/query";
|
|
|
7
7
|
import { defaultAnalyzerRegistry } from "@gscdump/analysis/registry";
|
|
8
8
|
import { createGscApiQuerySource } from "@gscdump/engine-gsc-api";
|
|
9
9
|
import { err, ok, unwrapResult } from "gscdump/result";
|
|
10
|
-
import { addSite, batchInspectUrls, batchRequestIndexing, deleteSite, discoverSitemap, fetchSitemap, fetchSitesWithSitemaps, getIndexingMetadata, getVerificationToken, getVerifiedSite, googleSearchConsole, hasGscWriteScope, hasIndexingScope, listVerifiedSites, requestIndexing, runSequentialBatch, unverifySite, verifySite } from "gscdump
|
|
10
|
+
import { addSite, batchInspectUrls, batchRequestIndexing, deleteSite, discoverSitemap, fetchSitemap, fetchSitesWithSitemaps, getIndexingMetadata, getVerificationToken, getVerifiedSite, googleSearchConsole, hasGscWriteScope, hasIndexingScope, listVerifiedSites, requestIndexing, runSequentialBatch, unverifySite, verifySite } from "gscdump";
|
|
11
11
|
import { ofetch } from "ofetch";
|
|
12
12
|
import { isAnalysisError } from "@gscdump/analysis/errors";
|
|
13
13
|
import { isEngineError } from "@gscdump/engine/errors";
|
|
@@ -417,7 +417,7 @@ async function runMcpSearchAnalyticsQuery(client, args) {
|
|
|
417
417
|
const remaining = totalLimit - allRows.length;
|
|
418
418
|
const currentLimit = Math.min(pageSize, remaining);
|
|
419
419
|
if (currentLimit <= 0) break;
|
|
420
|
-
const rows = ((await client.
|
|
420
|
+
const rows = ((await client.searchAnalytics.query(args.siteUrl, {
|
|
421
421
|
startDate: args.startDate,
|
|
422
422
|
endDate: args.endDate,
|
|
423
423
|
dimensions: args.dimensions,
|
package/dist/_chunks/query.mjs
CHANGED
|
@@ -92,7 +92,7 @@ async function runLiveQuery(client, siteUrl, opts) {
|
|
|
92
92
|
const remaining = totalLimit - allRows.length;
|
|
93
93
|
const rowLimit = Math.min(pageSize, remaining);
|
|
94
94
|
if (rowLimit <= 0) break;
|
|
95
|
-
const rows = ((await client.
|
|
95
|
+
const rows = ((await client.searchAnalytics.query(siteUrl, {
|
|
96
96
|
...baseBody,
|
|
97
97
|
rowLimit,
|
|
98
98
|
startRow
|
|
@@ -3,7 +3,7 @@ import { createCommandContext } from "./context.mjs";
|
|
|
3
3
|
import { gscErrorHandler } from "./error-handler.mjs";
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
import { defineCommand } from "citty";
|
|
6
|
-
import { discoverSitemap, fetchSitemap, fetchSitemapUrls } from "gscdump
|
|
6
|
+
import { discoverSitemap, fetchSitemap, fetchSitemapUrls } from "gscdump";
|
|
7
7
|
const listCommand = defineCommand({
|
|
8
8
|
meta: {
|
|
9
9
|
name: "list",
|
package/dist/_chunks/sites.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { gscErrorHandler } from "./error-handler.mjs";
|
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
import { defineCommand } from "citty";
|
|
6
6
|
import { confirm, isCancel } from "@clack/prompts";
|
|
7
|
-
import { addSite, deleteSite, fetchSitesWithSitemaps, getVerificationToken, getVerifiedSite, listVerifiedSites, siteUrlToVerificationSite, unverifySite, verificationMethodsFor, verifySite } from "gscdump
|
|
7
|
+
import { addSite, deleteSite, fetchSitesWithSitemaps, getVerificationToken, getVerifiedSite, listVerifiedSites, siteUrlToVerificationSite, unverifySite, verificationMethodsFor, verifySite } from "gscdump";
|
|
8
8
|
const ALL_METHODS = [
|
|
9
9
|
"META",
|
|
10
10
|
"FILE",
|
package/dist/_chunks/sync.mjs
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { OUTPUT_ARGS, applyOutputMode, clearLine, displayPath, formatAge, logger, runWithConcurrency } from "./utils.mjs";
|
|
1
|
+
import { OUTPUT_ARGS, applyOutputMode, clearLine, displayPath, formatAge, logger, progressBar, runWithConcurrency } from "./utils.mjs";
|
|
2
2
|
import { TABLE_DIMS, allTables, createCommandContext, createLocalStore, transformGscRow } from "./context.mjs";
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
import { defineCommand } from "citty";
|
|
5
5
|
import { SearchTypes } from "gscdump/query";
|
|
6
6
|
import { createEmptyTypesStore } from "@gscdump/engine/entities";
|
|
7
|
-
import { progressBar } from "gscdump";
|
|
8
7
|
import { daysAgoUtc, getDateRange } from "gscdump/dates";
|
|
9
8
|
import { DEFAULT_ROLLUPS, rebuildRollups } from "@gscdump/engine/rollups";
|
|
10
9
|
const DEFAULT_TABLES = [
|
|
@@ -100,7 +99,7 @@ async function runOneDate(store, client, siteUrl, table, searchType, dims, date)
|
|
|
100
99
|
const rows = [];
|
|
101
100
|
let startRow = 0;
|
|
102
101
|
while (true) {
|
|
103
|
-
const batch = (await client.
|
|
102
|
+
const batch = (await client.searchAnalytics.query(siteUrl, {
|
|
104
103
|
startDate: date,
|
|
105
104
|
endDate: date,
|
|
106
105
|
dimensions: dims,
|
package/dist/_chunks/utils.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import fs from "node:fs/promises";
|
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import { Buffer } from "node:buffer";
|
|
6
6
|
import { SearchTypes } from "gscdump/query";
|
|
7
|
-
var version = "0.
|
|
7
|
+
var version = "1.0.0";
|
|
8
8
|
const ALL_SEARCH_TYPES = Object.values(SearchTypes);
|
|
9
9
|
const VERSION = version;
|
|
10
10
|
function noSubcommandSelected(parent, subNames) {
|
|
@@ -90,6 +90,30 @@ async function withConfiguredOutput(run) {
|
|
|
90
90
|
process.stdout.write = original;
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
+
const ANSI = {
|
|
94
|
+
reset: "\x1B[0m",
|
|
95
|
+
bold: "\x1B[1m",
|
|
96
|
+
dim: "\x1B[90m",
|
|
97
|
+
red: "\x1B[31m",
|
|
98
|
+
green: "\x1B[32m",
|
|
99
|
+
yellow: "\x1B[33m",
|
|
100
|
+
cyan: "\x1B[36m"
|
|
101
|
+
};
|
|
102
|
+
function color(c, s) {
|
|
103
|
+
if (!isColorEnabled()) return String(s);
|
|
104
|
+
return `${ANSI[c]}${s}${ANSI.reset}`;
|
|
105
|
+
}
|
|
106
|
+
function dim(s) {
|
|
107
|
+
return color("dim", s);
|
|
108
|
+
}
|
|
109
|
+
function cyan(s) {
|
|
110
|
+
return color("cyan", s);
|
|
111
|
+
}
|
|
112
|
+
function progressBar(current, total, label, width = 30) {
|
|
113
|
+
const percent = total > 0 ? Math.min(current / total, 1) : 0;
|
|
114
|
+
const filled = Math.round(width * percent);
|
|
115
|
+
return ` ${`${cyan("█".repeat(filled))}${dim("░".repeat(width - filled))}`} ${dim(`${current}/${total}`)} ${label}`;
|
|
116
|
+
}
|
|
93
117
|
const gradientColors = [
|
|
94
118
|
(s) => `\x1B[38;2;52;211;153m${s}\x1B[0m`,
|
|
95
119
|
(s) => `\x1B[38;2;45;212;191m${s}\x1B[0m`,
|
|
@@ -188,4 +212,4 @@ function exportToCSV(output) {
|
|
|
188
212
|
])}`);
|
|
189
213
|
return sections.join("\n\n");
|
|
190
214
|
}
|
|
191
|
-
export { ALL_SEARCH_TYPES, OUTPUT_ARGS, VERSION, applyOutputMode, clearLine, configureColor, displayPath, exportToCSV, formatAge, logger, noSubcommandSelected, parseSearchType, readUrlList, runWithConcurrency, showSplash, toCSV, withConfiguredOutput };
|
|
215
|
+
export { ALL_SEARCH_TYPES, OUTPUT_ARGS, VERSION, applyOutputMode, clearLine, configureColor, displayPath, exportToCSV, formatAge, logger, noSubcommandSelected, parseSearchType, progressBar, readUrlList, runWithConcurrency, showSplash, toCSV, withConfiguredOutput };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gscdump/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"description": "CLI for Google Search Console - dump, query, and run MCP server",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"dist"
|
|
45
45
|
],
|
|
46
46
|
"engines": {
|
|
47
|
-
"node": ">=
|
|
47
|
+
"node": ">=22"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@clack/prompts": "^1.7.0",
|
|
@@ -56,10 +56,10 @@
|
|
|
56
56
|
"ofetch": "^1.5.1",
|
|
57
57
|
"open": "^11.0.0",
|
|
58
58
|
"zod": "^4.4.3",
|
|
59
|
-
"@gscdump/analysis": "0.
|
|
60
|
-
"@gscdump/engine": "0.
|
|
61
|
-
"gscdump": "0.
|
|
62
|
-
"
|
|
59
|
+
"@gscdump/analysis": "^1.0.0",
|
|
60
|
+
"@gscdump/engine": "^1.0.0",
|
|
61
|
+
"@gscdump/engine-gsc-api": "^1.0.0",
|
|
62
|
+
"gscdump": "^1.0.0"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"vitest": "^4.1.10"
|