@gscdump/cli 0.25.14 → 0.26.1
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/dist/index.mjs +234 -41
- package/package.json +7 -7
package/dist/index.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import path, { join } from "node:path";
|
|
|
7
7
|
import { AnalyzerCapabilityError, createEngineQuerySource, runAnalyzerFromSource } from "@gscdump/analysis";
|
|
8
8
|
import { createGscApiQuerySource } from "@gscdump/engine-gsc-api";
|
|
9
9
|
import { addSite, batchInspectUrls, batchRequestIndexing, createAuth, daysAgo, decodeSiteId, deleteSite, discoverSitemap, fetchSitemap, fetchSitemapUrls, fetchSitesWithSitemaps, formatErrorForCli, getDateRange, getIndexingMetadata, getVerificationToken, getVerifiedSite, googleSearchConsole, listVerifiedSites, normalizeSiteUrl, progressBar, requestIndexing, runSequentialBatch, siteUrlToVerificationSite, unverifySite, verificationMethodsFor, verifySite } from "gscdump";
|
|
10
|
+
import { err, ok, unwrapResult } from "gscdump/result";
|
|
10
11
|
import os from "node:os";
|
|
11
12
|
import { cancel, confirm, isCancel, multiselect, select, text } from "@clack/prompts";
|
|
12
13
|
import { createServer } from "node:http";
|
|
@@ -15,10 +16,12 @@ import { ofetch } from "ofetch";
|
|
|
15
16
|
import fs$1 from "node:fs";
|
|
16
17
|
import { Buffer as Buffer$1 } from "node:buffer";
|
|
17
18
|
import { createConsola } from "consola";
|
|
18
|
-
import { SearchTypes, and, between, contains, country, date, device, eq, gsc, hour, notRegex, page, query, regex, searchAppearance } from "gscdump/query";
|
|
19
|
+
import { SearchTypes, and, between, contains, country, date, device, eq, gsc, hour, isQueryError, notRegex, page, query, regex, searchAppearance } from "gscdump/query";
|
|
19
20
|
import { createNodeHarness } from "@gscdump/engine/node";
|
|
20
21
|
import { TABLE_DIMS, transformGscRow } from "@gscdump/engine/ingest";
|
|
21
22
|
import { allTables, inferTable } from "@gscdump/engine/schema";
|
|
23
|
+
import { isAnalysisError } from "@gscdump/analysis/errors";
|
|
24
|
+
import { isEngineError } from "@gscdump/engine/errors";
|
|
22
25
|
import { DuckDBInstance } from "@duckdb/node-api";
|
|
23
26
|
import { sqlEscape } from "@gscdump/engine/sql";
|
|
24
27
|
import { createEmptyTypesStore, createIndexingMetadataStore, createInspectionStore, createSitemapStore } from "@gscdump/engine/entities";
|
|
@@ -122,7 +125,7 @@ function loadEnvFromCwd() {
|
|
|
122
125
|
}
|
|
123
126
|
return applied;
|
|
124
127
|
}
|
|
125
|
-
var version = "0.
|
|
128
|
+
var version = "0.26.1";
|
|
126
129
|
const ALL_SEARCH_TYPES$1 = Object.values(SearchTypes);
|
|
127
130
|
const VERSION = version;
|
|
128
131
|
function noSubcommandSelected(parent, subNames) {
|
|
@@ -293,20 +296,34 @@ function exportToCSV(output) {
|
|
|
293
296
|
])}`);
|
|
294
297
|
return sections.join("\n\n");
|
|
295
298
|
}
|
|
299
|
+
function authErrorToException(error) {
|
|
300
|
+
const exception = new Error(error.message);
|
|
301
|
+
if ("cause" in error && error.cause !== void 0) exception.cause = error.cause;
|
|
302
|
+
exception.authError = error;
|
|
303
|
+
return exception;
|
|
304
|
+
}
|
|
296
305
|
const SCOPES = [
|
|
297
306
|
"https://www.googleapis.com/auth/webmasters",
|
|
298
307
|
"https://www.googleapis.com/auth/indexing",
|
|
299
308
|
"https://www.googleapis.com/auth/siteverification"
|
|
300
309
|
];
|
|
301
|
-
async function
|
|
310
|
+
async function loadServiceAccountResult(jsonPath) {
|
|
302
311
|
const raw = await fs.readFile(jsonPath, "utf-8");
|
|
303
312
|
const key = JSON.parse(raw);
|
|
304
|
-
if (key.type !== "service_account")
|
|
305
|
-
|
|
313
|
+
if (key.type !== "service_account") return err({
|
|
314
|
+
kind: "not-service-account",
|
|
315
|
+
path: jsonPath,
|
|
316
|
+
accountType: key.type,
|
|
317
|
+
message: `${jsonPath} is not a service-account key (type=${key.type})`
|
|
318
|
+
});
|
|
319
|
+
return ok(new JWT({
|
|
306
320
|
email: key.client_email,
|
|
307
321
|
key: key.private_key,
|
|
308
322
|
scopes: SCOPES
|
|
309
|
-
});
|
|
323
|
+
}));
|
|
324
|
+
}
|
|
325
|
+
async function loadServiceAccount(jsonPath) {
|
|
326
|
+
return unwrapResult(await loadServiceAccountResult(jsonPath), authErrorToException);
|
|
310
327
|
}
|
|
311
328
|
async function resolveServiceAccount(opts = {}) {
|
|
312
329
|
let p = opts.path || process.env.GSC_SERVICE_ACCOUNT_JSON || process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
@@ -315,15 +332,24 @@ async function resolveServiceAccount(opts = {}) {
|
|
|
315
332
|
return loadServiceAccount(p);
|
|
316
333
|
}
|
|
317
334
|
async function authenticateDeviceCode(credentials) {
|
|
335
|
+
return unwrapResult(await authenticateDeviceCodeResult(credentials), authErrorToException);
|
|
336
|
+
}
|
|
337
|
+
async function authenticateDeviceCodeResult(credentials) {
|
|
318
338
|
const init = await ofetch("https://oauth2.googleapis.com/device/code", {
|
|
319
339
|
method: "POST",
|
|
320
340
|
body: new URLSearchParams({
|
|
321
341
|
client_id: credentials.clientId,
|
|
322
342
|
scope: SCOPES.join(" ")
|
|
323
343
|
})
|
|
324
|
-
}).catch((e) => {
|
|
325
|
-
|
|
326
|
-
|
|
344
|
+
}).then(ok).catch((e) => err({
|
|
345
|
+
kind: "device-code-request-failed",
|
|
346
|
+
message: `Device-code request failed: ${e.message}`,
|
|
347
|
+
cause: e
|
|
348
|
+
}));
|
|
349
|
+
if (!init.ok) return init;
|
|
350
|
+
return pollDeviceCode(credentials, init.value);
|
|
351
|
+
}
|
|
352
|
+
async function pollDeviceCode(credentials, init) {
|
|
327
353
|
console.log();
|
|
328
354
|
console.log(` \x1B[1mDevice-code OAuth\x1B[0m`);
|
|
329
355
|
console.log(` 1. On any device, open: \x1B[36m${init.verification_url}\x1B[0m`);
|
|
@@ -344,17 +370,30 @@ async function authenticateDeviceCode(credentials) {
|
|
|
344
370
|
grant_type: "urn:ietf:params:oauth:grant-type:device_code"
|
|
345
371
|
})
|
|
346
372
|
}).catch((e) => e?.data ?? { error: "request_failed" });
|
|
347
|
-
if (res.access_token) return {
|
|
373
|
+
if (res.access_token) return ok({
|
|
348
374
|
access_token: res.access_token,
|
|
349
375
|
refresh_token: res.refresh_token,
|
|
350
376
|
expiry_date: res.expires_in ? Date.now() + res.expires_in * 1e3 : void 0
|
|
351
|
-
};
|
|
377
|
+
});
|
|
352
378
|
if (res.error === "authorization_pending" || res.error === "slow_down") continue;
|
|
353
|
-
if (res.error === "access_denied")
|
|
354
|
-
|
|
355
|
-
|
|
379
|
+
if (res.error === "access_denied") return err({
|
|
380
|
+
kind: "device-code-denied",
|
|
381
|
+
message: "User denied authorization."
|
|
382
|
+
});
|
|
383
|
+
if (res.error === "expired_token") return err({
|
|
384
|
+
kind: "device-code-expired",
|
|
385
|
+
message: "Device code expired. Re-run `gscdump auth login --no-browser`."
|
|
386
|
+
});
|
|
387
|
+
if (res.error) return err({
|
|
388
|
+
kind: "device-code-failed",
|
|
389
|
+
reason: res.error,
|
|
390
|
+
message: `Device-code poll failed: ${res.error_description || res.error}`
|
|
391
|
+
});
|
|
356
392
|
}
|
|
357
|
-
|
|
393
|
+
return err({
|
|
394
|
+
kind: "device-code-timed-out",
|
|
395
|
+
message: "Device-code flow timed out."
|
|
396
|
+
});
|
|
358
397
|
}
|
|
359
398
|
function resolveBYOK(opts = {}) {
|
|
360
399
|
const accessToken = opts.accessToken || process.env.GSC_ACCESS_TOKEN || process.env.GOOGLE_ACCESS_TOKEN;
|
|
@@ -780,6 +819,54 @@ async function createCommandContext(opts = {}) {
|
|
|
780
819
|
resolveSite
|
|
781
820
|
};
|
|
782
821
|
}
|
|
822
|
+
function extractQueryError(error) {
|
|
823
|
+
if (isQueryError(error)) return error;
|
|
824
|
+
const tagged = error.queryError;
|
|
825
|
+
return isQueryError(tagged) ? tagged : null;
|
|
826
|
+
}
|
|
827
|
+
function extractEngineError(error) {
|
|
828
|
+
if (isEngineError(error)) return error;
|
|
829
|
+
const tagged = error.engineError;
|
|
830
|
+
return isEngineError(tagged) ? tagged : null;
|
|
831
|
+
}
|
|
832
|
+
function extractAnalysisError(error) {
|
|
833
|
+
if (isAnalysisError(error)) return error;
|
|
834
|
+
const tagged = error.analysisError;
|
|
835
|
+
return isAnalysisError(tagged) ? tagged : null;
|
|
836
|
+
}
|
|
837
|
+
function suggestionForTypedError(error) {
|
|
838
|
+
const query = extractQueryError(error);
|
|
839
|
+
if (query) switch (query.kind) {
|
|
840
|
+
case "unresolvable-dataset": return "This breakdown spans separate stored tables. Re-run with --live to compute it from the GSC API.";
|
|
841
|
+
case "unsupported-capability": return `The local engine lacks the "${query.capability}" capability for ${query.context}. Re-run with --live.`;
|
|
842
|
+
case "missing-date-range": return "Add a date range, e.g. --start YYYY-MM-DD --end YYYY-MM-DD.";
|
|
843
|
+
case "invalid-row-limit":
|
|
844
|
+
case "invalid-start-row":
|
|
845
|
+
case "invalid-data-state":
|
|
846
|
+
case "invalid-aggregation-type":
|
|
847
|
+
case "invalid-builder-state": return "";
|
|
848
|
+
}
|
|
849
|
+
const analysis = extractAnalysisError(error);
|
|
850
|
+
if (analysis) switch (analysis.kind) {
|
|
851
|
+
case "missing-report-param": return `Report "${analysis.report}" needs --${analysis.param}.`;
|
|
852
|
+
case "missing-comparison-window": return `Report "${analysis.report}" is a comparison report; pass --vs prev-period (or --vs yoy).`;
|
|
853
|
+
case "missing-brand-terms": return "Pass --brand-terms to segment branded vs non-branded queries.";
|
|
854
|
+
case "unknown-report": return `Unknown report. Available: ${analysis.available.join(", ")}.`;
|
|
855
|
+
case "unknown-analyzer": return "Run `gscdump report list` to see available reports/analyzers.";
|
|
856
|
+
case "required-step-failed": return suggestionForTypedError(analysis.cause);
|
|
857
|
+
}
|
|
858
|
+
const engine = extractEngineError(error);
|
|
859
|
+
if (engine) switch (engine.kind) {
|
|
860
|
+
case "attached-table-missing": return `Local store is missing table(s): ${engine.missing.join(", ")}. Run \`gscdump sync\` first, or pass --live.`;
|
|
861
|
+
case "analyzer-not-found":
|
|
862
|
+
case "analyzer-capability-missing": return "This analysis is not available for the chosen source. Re-run with --live.";
|
|
863
|
+
case "invalid-year-month":
|
|
864
|
+
case "invalid-snapshot-filename":
|
|
865
|
+
case "invalid-schema-identifier": return "The local store appears corrupt. Re-run `gscdump sync` to rebuild it.";
|
|
866
|
+
default: return "";
|
|
867
|
+
}
|
|
868
|
+
return "";
|
|
869
|
+
}
|
|
783
870
|
var LocalStoreUnsupportedError = class extends Error {
|
|
784
871
|
tool;
|
|
785
872
|
mode;
|
|
@@ -799,6 +886,11 @@ async function gscErrorHandler(error) {
|
|
|
799
886
|
process.exit(1);
|
|
800
887
|
}
|
|
801
888
|
console.error(formatErrorForCli(error));
|
|
889
|
+
const typedHint = suggestionForTypedError(error);
|
|
890
|
+
if (typedHint) {
|
|
891
|
+
console.error();
|
|
892
|
+
console.error(typedHint);
|
|
893
|
+
}
|
|
802
894
|
if (isAuthError(error)) {
|
|
803
895
|
console.error();
|
|
804
896
|
console.error(await formatAuthProvenance());
|
|
@@ -823,12 +915,15 @@ function pickLocalSite(siteUrls, hint) {
|
|
|
823
915
|
if (exact) return exact;
|
|
824
916
|
return siteUrls.find((s) => s.includes(hint) || hint.includes(s)) ?? null;
|
|
825
917
|
}
|
|
826
|
-
function
|
|
827
|
-
return
|
|
828
|
-
if (e instanceof AnalyzerCapabilityError)
|
|
918
|
+
async function runAnalysisResult(source, params, mode) {
|
|
919
|
+
return runAnalyzerFromSource(source, params, defaultAnalyzerRegistry).then(ok).catch((e) => {
|
|
920
|
+
if (e instanceof AnalyzerCapabilityError) return err(new LocalStoreUnsupportedError(params.type, mode));
|
|
829
921
|
throw e;
|
|
830
922
|
});
|
|
831
923
|
}
|
|
924
|
+
function makeRunAnalysis(source, mode) {
|
|
925
|
+
return async (params) => unwrapResult(await runAnalysisResult(source, params, mode), (e) => e);
|
|
926
|
+
}
|
|
832
927
|
async function resolveAnalysisSource(args) {
|
|
833
928
|
const isLive = !!args.live;
|
|
834
929
|
const format = args.json ? "json" : args.format ? String(args.format) : "table";
|
|
@@ -3748,17 +3843,10 @@ async function probeReachable(url) {
|
|
|
3748
3843
|
}).then(() => true).catch(() => false);
|
|
3749
3844
|
}
|
|
3750
3845
|
async function requestIndexing$1(input, ctx) {
|
|
3751
|
-
return requestIndexing(ctx.client, input.url, { type: input.type || "URL_UPDATED" })
|
|
3752
|
-
url: input.url,
|
|
3753
|
-
type: input.type || "URL_UPDATED",
|
|
3754
|
-
error: e.message
|
|
3755
|
-
}));
|
|
3846
|
+
return requestIndexing(ctx.client, input.url, { type: input.type || "URL_UPDATED" });
|
|
3756
3847
|
}
|
|
3757
3848
|
async function getIndexingStatus(input, ctx) {
|
|
3758
|
-
return getIndexingMetadata(ctx.client, input.url)
|
|
3759
|
-
url: input.url,
|
|
3760
|
-
error: e.message
|
|
3761
|
-
}));
|
|
3849
|
+
return getIndexingMetadata(ctx.client, input.url);
|
|
3762
3850
|
}
|
|
3763
3851
|
async function batchRequestIndexing$1(input, ctx) {
|
|
3764
3852
|
const results = await batchRequestIndexing(ctx.client, input.urls, {
|
|
@@ -3779,6 +3867,87 @@ async function batchInspectUrls$1(input, ctx) {
|
|
|
3779
3867
|
notIndexed: results.filter((r) => !r.isIndexed).length
|
|
3780
3868
|
};
|
|
3781
3869
|
}
|
|
3870
|
+
const PERIODS = [
|
|
3871
|
+
"7d",
|
|
3872
|
+
"28d",
|
|
3873
|
+
"30d",
|
|
3874
|
+
"90d",
|
|
3875
|
+
"180d",
|
|
3876
|
+
"365d",
|
|
3877
|
+
"mtd",
|
|
3878
|
+
"ytd",
|
|
3879
|
+
"custom"
|
|
3880
|
+
];
|
|
3881
|
+
const COMPARISONS = [
|
|
3882
|
+
"none",
|
|
3883
|
+
"prev-period",
|
|
3884
|
+
"yoy"
|
|
3885
|
+
];
|
|
3886
|
+
const mcpHandlerErrors = {
|
|
3887
|
+
unknownReport(id, available) {
|
|
3888
|
+
return {
|
|
3889
|
+
kind: "unknown-report",
|
|
3890
|
+
id,
|
|
3891
|
+
available,
|
|
3892
|
+
message: `Unknown report id "${id}". Available: ${available.join(", ")}`
|
|
3893
|
+
};
|
|
3894
|
+
},
|
|
3895
|
+
unknownPeriod(value) {
|
|
3896
|
+
return {
|
|
3897
|
+
kind: "unknown-period",
|
|
3898
|
+
value,
|
|
3899
|
+
supported: PERIODS,
|
|
3900
|
+
message: `Unknown period "${value}". Supported: ${PERIODS.join(", ")}.`
|
|
3901
|
+
};
|
|
3902
|
+
},
|
|
3903
|
+
unknownComparison(value) {
|
|
3904
|
+
return {
|
|
3905
|
+
kind: "unknown-comparison",
|
|
3906
|
+
value,
|
|
3907
|
+
supported: COMPARISONS,
|
|
3908
|
+
message: `Unknown comparison "${value}". Supported: ${COMPARISONS.join(", ")}.`
|
|
3909
|
+
};
|
|
3910
|
+
},
|
|
3911
|
+
noValidDimension() {
|
|
3912
|
+
return {
|
|
3913
|
+
kind: "no-valid-dimension",
|
|
3914
|
+
message: "At least one valid dimension required"
|
|
3915
|
+
};
|
|
3916
|
+
}
|
|
3917
|
+
};
|
|
3918
|
+
function mcpHandlerErrorToException(error) {
|
|
3919
|
+
const exception = new Error(error.message);
|
|
3920
|
+
exception.mcpHandlerError = error;
|
|
3921
|
+
return exception;
|
|
3922
|
+
}
|
|
3923
|
+
function enrichToolError(error) {
|
|
3924
|
+
const query = asQueryError(error);
|
|
3925
|
+
if (query) return /* @__PURE__ */ new Error(`[query:${query.kind}] ${query.message}`);
|
|
3926
|
+
const analysis = asAnalysisError(error);
|
|
3927
|
+
if (analysis) {
|
|
3928
|
+
const cause = analysis.kind === "required-step-failed" ? asEngineError(analysis.cause) : null;
|
|
3929
|
+
const tail = cause ? ` (engine:${cause.kind})` : "";
|
|
3930
|
+
return /* @__PURE__ */ new Error(`[analysis:${analysis.kind}]${tail} ${analysis.message}`);
|
|
3931
|
+
}
|
|
3932
|
+
const engine = asEngineError(error);
|
|
3933
|
+
if (engine) return /* @__PURE__ */ new Error(`[engine:${engine.kind}] ${engine.message}`);
|
|
3934
|
+
return null;
|
|
3935
|
+
}
|
|
3936
|
+
function asQueryError(error) {
|
|
3937
|
+
if (isQueryError(error)) return error;
|
|
3938
|
+
const tagged = error?.queryError;
|
|
3939
|
+
return isQueryError(tagged) ? tagged : null;
|
|
3940
|
+
}
|
|
3941
|
+
function asEngineError(error) {
|
|
3942
|
+
if (isEngineError(error)) return error;
|
|
3943
|
+
const tagged = error?.engineError;
|
|
3944
|
+
return isEngineError(tagged) ? tagged : null;
|
|
3945
|
+
}
|
|
3946
|
+
function asAnalysisError(error) {
|
|
3947
|
+
if (isAnalysisError(error)) return error;
|
|
3948
|
+
const tagged = error?.analysisError;
|
|
3949
|
+
return isAnalysisError(tagged) ? tagged : null;
|
|
3950
|
+
}
|
|
3782
3951
|
const PERIOD_ALIASES$1 = {
|
|
3783
3952
|
"7d": "last-7d",
|
|
3784
3953
|
"28d": "last-28d",
|
|
@@ -3806,13 +3975,13 @@ function listReports() {
|
|
|
3806
3975
|
argsSpec: r.argsSpec
|
|
3807
3976
|
}));
|
|
3808
3977
|
}
|
|
3809
|
-
async function
|
|
3978
|
+
async function runReportHandlerResult(input, ctx) {
|
|
3810
3979
|
const report = defaultReportRegistry.getReport(input.id);
|
|
3811
|
-
if (!report)
|
|
3980
|
+
if (!report) return err(mcpHandlerErrors.unknownReport(input.id, defaultReportRegistry.listReportIds()));
|
|
3812
3981
|
const preset = input.period ? PERIOD_ALIASES$1[input.period.toLowerCase()] ?? null : report.defaultPeriod;
|
|
3813
|
-
if (!preset)
|
|
3982
|
+
if (!preset) return err(mcpHandlerErrors.unknownPeriod(input.period ?? ""));
|
|
3814
3983
|
const comparison = input.comparison ? COMPARISON_ALIASES$1[input.comparison.toLowerCase()] ?? null : report.defaultComparison;
|
|
3815
|
-
if (!comparison)
|
|
3984
|
+
if (!comparison) return err(mcpHandlerErrors.unknownComparison(input.comparison ?? ""));
|
|
3816
3985
|
const window = resolveWindow({
|
|
3817
3986
|
preset,
|
|
3818
3987
|
comparison,
|
|
@@ -3825,7 +3994,7 @@ async function runReportHandler(input, ctx) {
|
|
|
3825
3994
|
};
|
|
3826
3995
|
const params = {};
|
|
3827
3996
|
if (input.maxFindings != null) params.maxFindings = input.maxFindings;
|
|
3828
|
-
return runReport(report, {
|
|
3997
|
+
return ok(await runReport(report, {
|
|
3829
3998
|
source: createGscApiQuerySource({
|
|
3830
3999
|
client: ctx.client,
|
|
3831
4000
|
siteUrl: input.siteUrl
|
|
@@ -3837,7 +4006,12 @@ async function runReportHandler(input, ctx) {
|
|
|
3837
4006
|
params,
|
|
3838
4007
|
registryVersion: defaultReportRegistry.version
|
|
3839
4008
|
}
|
|
3840
|
-
});
|
|
4009
|
+
}));
|
|
4010
|
+
}
|
|
4011
|
+
async function runReportHandler(input, ctx) {
|
|
4012
|
+
return unwrapResult(await runReportHandlerResult(input, ctx).catch((thrown) => {
|
|
4013
|
+
throw enrichToolError(thrown) ?? thrown;
|
|
4014
|
+
}), mcpHandlerErrorToException);
|
|
3841
4015
|
}
|
|
3842
4016
|
async function listSitesWithSitemaps(_input, ctx) {
|
|
3843
4017
|
return fetchSitesWithSitemaps(ctx.client);
|
|
@@ -4867,6 +5041,11 @@ async function writeOutput(opts) {
|
|
|
4867
5041
|
function isKnownTable$1(name) {
|
|
4868
5042
|
return allTables().includes(name);
|
|
4869
5043
|
}
|
|
5044
|
+
function reportFlagErrorToException(error) {
|
|
5045
|
+
const exception = new Error(error.message);
|
|
5046
|
+
exception.reportFlagError = error;
|
|
5047
|
+
return exception;
|
|
5048
|
+
}
|
|
4870
5049
|
const REPORT_IDS = defaultReportRegistry.listReportIds();
|
|
4871
5050
|
const PERIOD_ALIASES = {
|
|
4872
5051
|
"7d": "last-7d",
|
|
@@ -4893,17 +5072,31 @@ const COMPARISON_ALIASES = {
|
|
|
4893
5072
|
"prior-period": "prev-period",
|
|
4894
5073
|
"yoy": "yoy"
|
|
4895
5074
|
};
|
|
4896
|
-
function
|
|
4897
|
-
if (!input) return fallback;
|
|
5075
|
+
function resolvePeriodResult(input, fallback) {
|
|
5076
|
+
if (!input) return ok(fallback);
|
|
4898
5077
|
const preset = PERIOD_ALIASES[input.toLowerCase()];
|
|
4899
|
-
if (!preset)
|
|
4900
|
-
|
|
5078
|
+
if (!preset) return err({
|
|
5079
|
+
kind: "unknown-period",
|
|
5080
|
+
value: input,
|
|
5081
|
+
message: `Unknown --period "${input}". Supported: 7d, 28d, 30d, 90d, 180d, 365d, mtd, ytd, custom.`
|
|
5082
|
+
});
|
|
5083
|
+
return ok(preset);
|
|
4901
5084
|
}
|
|
4902
|
-
function
|
|
4903
|
-
|
|
5085
|
+
function resolvePeriod(input, fallback) {
|
|
5086
|
+
return unwrapResult(resolvePeriodResult(input, fallback), reportFlagErrorToException);
|
|
5087
|
+
}
|
|
5088
|
+
function resolveComparisonResult(input, fallback) {
|
|
5089
|
+
if (!input) return ok(fallback);
|
|
4904
5090
|
const mode = COMPARISON_ALIASES[input.toLowerCase()];
|
|
4905
|
-
if (!mode)
|
|
4906
|
-
|
|
5091
|
+
if (!mode) return err({
|
|
5092
|
+
kind: "unknown-comparison",
|
|
5093
|
+
value: input,
|
|
5094
|
+
message: `Unknown --vs "${input}". Supported: none, prev-period, yoy.`
|
|
5095
|
+
});
|
|
5096
|
+
return ok(mode);
|
|
5097
|
+
}
|
|
5098
|
+
function resolveComparison(input, fallback) {
|
|
5099
|
+
return unwrapResult(resolveComparisonResult(input, fallback), reportFlagErrorToException);
|
|
4907
5100
|
}
|
|
4908
5101
|
function reportArgsToCitty(spec) {
|
|
4909
5102
|
const out = {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gscdump/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.26.1",
|
|
5
5
|
"description": "CLI for Google Search Console - dump, query, and run MCP server",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -35,18 +35,18 @@
|
|
|
35
35
|
"dist"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@clack/prompts": "^1.5.
|
|
38
|
+
"@clack/prompts": "^1.5.1",
|
|
39
39
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
40
40
|
"citty": "^0.2.2",
|
|
41
41
|
"consola": "^3.4.2",
|
|
42
|
-
"google-auth-library": "^10.
|
|
42
|
+
"google-auth-library": "^10.7.0",
|
|
43
43
|
"ofetch": "^1.5.1",
|
|
44
44
|
"open": "^11.0.0",
|
|
45
45
|
"zod": "^4.4.3",
|
|
46
|
-
"
|
|
47
|
-
"@gscdump/engine": "0.
|
|
48
|
-
"@gscdump/
|
|
49
|
-
"gscdump": "0.
|
|
46
|
+
"gscdump": "0.26.1",
|
|
47
|
+
"@gscdump/engine-gsc-api": "0.26.1",
|
|
48
|
+
"@gscdump/analysis": "0.26.1",
|
|
49
|
+
"@gscdump/engine": "0.26.1"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@duckdb/node-api": "1.5.1-r.2",
|