@gscdump/cli 0.37.3 → 0.37.4
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/bin/gscdump.mjs +3 -0
- package/dist/_chunks/analysis-local.mjs +88 -0
- package/dist/_chunks/analyze.mjs +332 -0
- package/dist/_chunks/auth.mjs +476 -0
- package/dist/_chunks/auth2.mjs +293 -0
- package/dist/_chunks/config.mjs +93 -0
- package/dist/_chunks/config2.mjs +232 -0
- package/dist/_chunks/context.mjs +69 -0
- package/dist/_chunks/doctor.mjs +400 -0
- package/dist/_chunks/dump.mjs +193 -0
- package/dist/_chunks/entities.mjs +414 -0
- package/dist/_chunks/env-file.mjs +53 -0
- package/dist/_chunks/environment.mjs +30 -0
- package/dist/_chunks/error-handler.mjs +86 -0
- package/dist/_chunks/indexing.mjs +314 -0
- package/dist/_chunks/init.mjs +190 -0
- package/dist/_chunks/inspect.mjs +203 -0
- package/dist/_chunks/mcp.mjs +867 -0
- package/dist/_chunks/native-duckdb.mjs +46 -0
- package/dist/_chunks/profile.mjs +290 -0
- package/dist/_chunks/query.mjs +537 -0
- package/dist/_chunks/report.mjs +243 -0
- package/dist/_chunks/sitemaps.mjs +274 -0
- package/dist/_chunks/sites.mjs +500 -0
- package/dist/_chunks/store.mjs +652 -0
- package/dist/_chunks/sync.mjs +489 -0
- package/dist/_chunks/utils.mjs +191 -0
- package/dist/cli.d.mts +28 -0
- package/dist/cli.mjs +104 -0
- package/package.json +15 -7
- package/dist/index.d.mts +0 -1
- package/dist/index.mjs +0 -7330
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
import { OUTPUT_ARGS, applyOutputMode, logger } from "./utils.mjs";
|
|
2
|
+
import { createCommandContext } from "./context.mjs";
|
|
3
|
+
import { gscErrorHandler } from "./error-handler.mjs";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { defineCommand } from "citty";
|
|
6
|
+
import { confirm, isCancel } from "@clack/prompts";
|
|
7
|
+
import { addSite, deleteSite, fetchSitesWithSitemaps, getVerificationToken, getVerifiedSite, listVerifiedSites, siteUrlToVerificationSite, unverifySite, verificationMethodsFor, verifySite } from "gscdump/api";
|
|
8
|
+
const ALL_METHODS = [
|
|
9
|
+
"META",
|
|
10
|
+
"FILE",
|
|
11
|
+
"DNS_TXT",
|
|
12
|
+
"DNS_CNAME",
|
|
13
|
+
"ANALYTICS",
|
|
14
|
+
"TAG_MANAGER"
|
|
15
|
+
];
|
|
16
|
+
function pickDefaultMethod(siteUrl) {
|
|
17
|
+
return siteUrl.startsWith("sc-domain:") ? "DNS_TXT" : "META";
|
|
18
|
+
}
|
|
19
|
+
function validateMethod(siteUrl, method) {
|
|
20
|
+
const upper = method.toUpperCase();
|
|
21
|
+
if (!ALL_METHODS.includes(upper)) {
|
|
22
|
+
logger.error(`Invalid --method: ${method}. Valid: ${ALL_METHODS.join(", ")}`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
const site = siteUrlToVerificationSite(siteUrl);
|
|
26
|
+
const allowed = verificationMethodsFor(site);
|
|
27
|
+
if (!allowed.includes(upper)) {
|
|
28
|
+
logger.error(`Method ${upper} not valid for ${site.type === "INET_DOMAIN" ? "domain" : "URL-prefix"} property "${siteUrl}". Valid: ${allowed.join(", ")}`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
return upper;
|
|
32
|
+
}
|
|
33
|
+
function printPlacementInstructions(method, siteUrl, token) {
|
|
34
|
+
console.log();
|
|
35
|
+
console.log(` \x1B[1mPlacement instructions (${method})\x1B[0m`);
|
|
36
|
+
console.log();
|
|
37
|
+
switch (method) {
|
|
38
|
+
case "META":
|
|
39
|
+
console.log(` Add this tag inside the <head> of \x1B[36m${siteUrl}\x1B[0m:`);
|
|
40
|
+
console.log();
|
|
41
|
+
console.log(` \x1B[2m<meta name="google-site-verification" content="${token}" />\x1B[0m`);
|
|
42
|
+
break;
|
|
43
|
+
case "FILE":
|
|
44
|
+
console.log(` Upload a file named \x1B[1m${token}\x1B[0m to the site root, accessible at:`);
|
|
45
|
+
console.log();
|
|
46
|
+
console.log(` \x1B[36m${siteUrl.replace(/\/?$/, "/")}${token}\x1B[0m`);
|
|
47
|
+
break;
|
|
48
|
+
case "DNS_TXT":
|
|
49
|
+
console.log(` Add a TXT record on \x1B[1m${siteUrl.replace(/^sc-domain:/, "")}\x1B[0m with value:`);
|
|
50
|
+
console.log();
|
|
51
|
+
console.log(` \x1B[2m${token}\x1B[0m`);
|
|
52
|
+
break;
|
|
53
|
+
case "DNS_CNAME": {
|
|
54
|
+
const [host, target] = token.split(/\s+/, 2);
|
|
55
|
+
console.log(` Add a CNAME record:`);
|
|
56
|
+
console.log();
|
|
57
|
+
console.log(` \x1B[2mHost: ${host}\x1B[0m`);
|
|
58
|
+
console.log(` \x1B[2mTarget: ${target ?? "(see token)"}\x1B[0m`);
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
case "ANALYTICS":
|
|
62
|
+
console.log(` Make sure the Google Analytics tracking tag is installed on the site.`);
|
|
63
|
+
console.log(` Expected tracking ID:`);
|
|
64
|
+
console.log();
|
|
65
|
+
console.log(` \x1B[2m${token}\x1B[0m`);
|
|
66
|
+
break;
|
|
67
|
+
case "TAG_MANAGER":
|
|
68
|
+
console.log(` Make sure the Google Tag Manager container snippet is installed on the site.`);
|
|
69
|
+
console.log(` Expected container ID:`);
|
|
70
|
+
console.log();
|
|
71
|
+
console.log(` \x1B[2m${token}\x1B[0m`);
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
console.log();
|
|
75
|
+
console.log(` \x1B[90mThen run:\x1B[0m gscdump sites verify ${siteUrl} --method ${method}`);
|
|
76
|
+
console.log();
|
|
77
|
+
}
|
|
78
|
+
const addCommand = defineCommand({
|
|
79
|
+
meta: {
|
|
80
|
+
name: "add",
|
|
81
|
+
description: "Register a property in Search Console (pass --verify to chain token + verify in one call)"
|
|
82
|
+
},
|
|
83
|
+
args: {
|
|
84
|
+
url: {
|
|
85
|
+
type: "positional",
|
|
86
|
+
required: true,
|
|
87
|
+
description: "Property URL (https://example.com/ or sc-domain:example.com)"
|
|
88
|
+
},
|
|
89
|
+
verify: {
|
|
90
|
+
type: "boolean",
|
|
91
|
+
default: false,
|
|
92
|
+
description: "After adding, fetch a verification token and trigger Google's validation"
|
|
93
|
+
},
|
|
94
|
+
method: {
|
|
95
|
+
type: "string",
|
|
96
|
+
alias: "m",
|
|
97
|
+
description: "Verification method (used with --verify; default: META for URL-prefix, DNS_TXT for sc-domain:)"
|
|
98
|
+
},
|
|
99
|
+
...OUTPUT_ARGS
|
|
100
|
+
},
|
|
101
|
+
async run({ args }) {
|
|
102
|
+
applyOutputMode(args);
|
|
103
|
+
const ctx = await createCommandContext({ needsAuth: true });
|
|
104
|
+
await addSite(ctx.client, args.url).catch(gscErrorHandler);
|
|
105
|
+
if (!args.verify) {
|
|
106
|
+
if (args.json) {
|
|
107
|
+
console.log(JSON.stringify({
|
|
108
|
+
siteUrl: args.url,
|
|
109
|
+
status: "added",
|
|
110
|
+
verified: false
|
|
111
|
+
}, null, 2));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
logger.success(`Added: ${args.url}`);
|
|
115
|
+
logger.info(`Property is in unverified state. Verify ownership next:`);
|
|
116
|
+
const method = pickDefaultMethod(args.url);
|
|
117
|
+
console.log(` \x1B[2mgscdump sites verify-token ${args.url} --method ${method}\x1B[0m`);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const method = validateMethod(args.url, args.method ?? pickDefaultMethod(args.url));
|
|
121
|
+
const tokenResult = await getVerificationToken(ctx.client, args.url, method).catch(gscErrorHandler);
|
|
122
|
+
if (args.json) {
|
|
123
|
+
console.log(JSON.stringify({
|
|
124
|
+
siteUrl: args.url,
|
|
125
|
+
status: "added",
|
|
126
|
+
method,
|
|
127
|
+
token: tokenResult.token,
|
|
128
|
+
site: tokenResult.site,
|
|
129
|
+
verified: false,
|
|
130
|
+
next: "Place the token, then run `gscdump sites verify <url> --method <m>`"
|
|
131
|
+
}, null, 2));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
logger.success(`Added: ${args.url}`);
|
|
135
|
+
printPlacementInstructions(method, args.url, tokenResult.token);
|
|
136
|
+
const ok = await confirm({
|
|
137
|
+
message: "Token placed? Trigger Google verification now?",
|
|
138
|
+
initialValue: true
|
|
139
|
+
});
|
|
140
|
+
if (isCancel(ok) || !ok) {
|
|
141
|
+
logger.info("Skipped verification. Run `gscdump sites verify` once the token is live.");
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const resource = await verifySite(ctx.client, args.url, method).catch(gscErrorHandler);
|
|
145
|
+
logger.success(`Verified: ${args.url}`);
|
|
146
|
+
if (resource.owners?.length) {
|
|
147
|
+
console.log();
|
|
148
|
+
console.log(` Owners:`);
|
|
149
|
+
for (const o of resource.owners) console.log(` \x1B[90m└─\x1B[0m ${o}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
const deleteCommand = defineCommand({
|
|
154
|
+
meta: {
|
|
155
|
+
name: "delete",
|
|
156
|
+
description: "Remove a property from Search Console"
|
|
157
|
+
},
|
|
158
|
+
args: {
|
|
159
|
+
url: {
|
|
160
|
+
type: "positional",
|
|
161
|
+
required: true,
|
|
162
|
+
description: "Property URL to remove"
|
|
163
|
+
},
|
|
164
|
+
yes: {
|
|
165
|
+
type: "boolean",
|
|
166
|
+
alias: "y",
|
|
167
|
+
default: false,
|
|
168
|
+
description: "Skip confirmation prompt"
|
|
169
|
+
},
|
|
170
|
+
...OUTPUT_ARGS
|
|
171
|
+
},
|
|
172
|
+
async run({ args }) {
|
|
173
|
+
applyOutputMode(args);
|
|
174
|
+
if (!args.yes && !args.json) {
|
|
175
|
+
const ok = await confirm({
|
|
176
|
+
message: `Remove ${args.url} from Search Console? Local synced data is unaffected.`,
|
|
177
|
+
initialValue: false
|
|
178
|
+
});
|
|
179
|
+
if (isCancel(ok) || !ok) {
|
|
180
|
+
logger.info("Cancelled");
|
|
181
|
+
process.exit(0);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
await deleteSite((await createCommandContext({ needsAuth: true })).client, args.url).catch(gscErrorHandler);
|
|
185
|
+
if (args.json) {
|
|
186
|
+
console.log(JSON.stringify({
|
|
187
|
+
siteUrl: args.url,
|
|
188
|
+
status: "deleted"
|
|
189
|
+
}, null, 2));
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
logger.success(`Removed: ${args.url}`);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
const verifyTokenCommand = defineCommand({
|
|
196
|
+
meta: {
|
|
197
|
+
name: "verify-token",
|
|
198
|
+
description: "Get a verification token to place on the site or in DNS"
|
|
199
|
+
},
|
|
200
|
+
args: {
|
|
201
|
+
url: {
|
|
202
|
+
type: "positional",
|
|
203
|
+
required: true,
|
|
204
|
+
description: "Property URL"
|
|
205
|
+
},
|
|
206
|
+
method: {
|
|
207
|
+
type: "string",
|
|
208
|
+
alias: "m",
|
|
209
|
+
description: "META, FILE, DNS_TXT, DNS_CNAME, ANALYTICS, TAG_MANAGER (default: META for URL-prefix, DNS_TXT for sc-domain:)"
|
|
210
|
+
},
|
|
211
|
+
...OUTPUT_ARGS
|
|
212
|
+
},
|
|
213
|
+
async run({ args }) {
|
|
214
|
+
applyOutputMode(args);
|
|
215
|
+
const method = validateMethod(args.url, args.method ?? pickDefaultMethod(args.url));
|
|
216
|
+
const result = await getVerificationToken((await createCommandContext({ needsAuth: true })).client, args.url, method).catch(gscErrorHandler);
|
|
217
|
+
if (args.json) {
|
|
218
|
+
console.log(JSON.stringify({
|
|
219
|
+
siteUrl: args.url,
|
|
220
|
+
method,
|
|
221
|
+
token: result.token,
|
|
222
|
+
site: result.site
|
|
223
|
+
}, null, 2));
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
printPlacementInstructions(method, args.url, result.token);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
const verifyCommand = defineCommand({
|
|
230
|
+
meta: {
|
|
231
|
+
name: "verify",
|
|
232
|
+
description: "Trigger verification — Google fetches/validates the token you placed"
|
|
233
|
+
},
|
|
234
|
+
args: {
|
|
235
|
+
url: {
|
|
236
|
+
type: "positional",
|
|
237
|
+
required: true,
|
|
238
|
+
description: "Property URL"
|
|
239
|
+
},
|
|
240
|
+
method: {
|
|
241
|
+
type: "string",
|
|
242
|
+
alias: "m",
|
|
243
|
+
description: "Verification method to validate (must match the one used for verify-token)"
|
|
244
|
+
},
|
|
245
|
+
...OUTPUT_ARGS
|
|
246
|
+
},
|
|
247
|
+
async run({ args }) {
|
|
248
|
+
applyOutputMode(args);
|
|
249
|
+
const method = validateMethod(args.url, args.method ?? pickDefaultMethod(args.url));
|
|
250
|
+
const resource = await verifySite((await createCommandContext({ needsAuth: true })).client, args.url, method).catch(gscErrorHandler);
|
|
251
|
+
if (args.json) {
|
|
252
|
+
console.log(JSON.stringify({
|
|
253
|
+
siteUrl: args.url,
|
|
254
|
+
method,
|
|
255
|
+
resource
|
|
256
|
+
}, null, 2));
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
logger.success(`Verified: ${args.url}`);
|
|
260
|
+
if (resource.owners?.length) {
|
|
261
|
+
console.log();
|
|
262
|
+
console.log(` Owners:`);
|
|
263
|
+
for (const o of resource.owners) console.log(` \x1B[90m└─\x1B[0m ${o}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
const verifyGetCommand = defineCommand({
|
|
268
|
+
meta: {
|
|
269
|
+
name: "verify-get",
|
|
270
|
+
description: "Get a single verified WebResource by id"
|
|
271
|
+
},
|
|
272
|
+
args: {
|
|
273
|
+
id: {
|
|
274
|
+
type: "positional",
|
|
275
|
+
required: true,
|
|
276
|
+
description: "WebResource id (from `sites verify-list`)"
|
|
277
|
+
},
|
|
278
|
+
...OUTPUT_ARGS
|
|
279
|
+
},
|
|
280
|
+
async run({ args }) {
|
|
281
|
+
applyOutputMode(args);
|
|
282
|
+
const resource = await getVerifiedSite((await createCommandContext({ needsAuth: true })).client, args.id).catch(gscErrorHandler);
|
|
283
|
+
if (args.json) {
|
|
284
|
+
console.log(JSON.stringify(resource, null, 2));
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const ident = resource.site?.identifier ?? resource.id ?? "?";
|
|
288
|
+
const type = resource.site?.type === "INET_DOMAIN" ? "domain" : "site";
|
|
289
|
+
console.log();
|
|
290
|
+
console.log(` \x1B[1m${ident}\x1B[0m \x1B[90m(${type})\x1B[0m`);
|
|
291
|
+
console.log(` \x1B[90mid:\x1B[0m ${resource.id ?? "?"}`);
|
|
292
|
+
if (resource.owners?.length) {
|
|
293
|
+
console.log(` Owners:`);
|
|
294
|
+
for (const o of resource.owners) console.log(` \x1B[90m└─\x1B[0m ${o}`);
|
|
295
|
+
}
|
|
296
|
+
console.log();
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
const unverifyCommand = defineCommand({
|
|
300
|
+
meta: {
|
|
301
|
+
name: "unverify",
|
|
302
|
+
description: "Drop your verified ownership of a WebResource (remove the placed token first!)"
|
|
303
|
+
},
|
|
304
|
+
args: {
|
|
305
|
+
id: {
|
|
306
|
+
type: "positional",
|
|
307
|
+
required: true,
|
|
308
|
+
description: "WebResource id (from `sites verify-list`)"
|
|
309
|
+
},
|
|
310
|
+
yes: {
|
|
311
|
+
type: "boolean",
|
|
312
|
+
alias: "y",
|
|
313
|
+
default: false,
|
|
314
|
+
description: "Skip confirmation prompt"
|
|
315
|
+
},
|
|
316
|
+
...OUTPUT_ARGS
|
|
317
|
+
},
|
|
318
|
+
async run({ args }) {
|
|
319
|
+
applyOutputMode(args);
|
|
320
|
+
if (!args.yes && !args.json) {
|
|
321
|
+
const ok = await confirm({
|
|
322
|
+
message: `Unverify WebResource ${args.id}? Remove any placed verification token first or Google may re-verify.`,
|
|
323
|
+
initialValue: false
|
|
324
|
+
});
|
|
325
|
+
if (isCancel(ok) || !ok) {
|
|
326
|
+
logger.info("Cancelled");
|
|
327
|
+
process.exit(0);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
await unverifySite((await createCommandContext({ needsAuth: true })).client, args.id).catch(gscErrorHandler);
|
|
331
|
+
if (args.json) {
|
|
332
|
+
console.log(JSON.stringify({
|
|
333
|
+
id: args.id,
|
|
334
|
+
status: "unverified"
|
|
335
|
+
}, null, 2));
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
logger.success(`Unverified: ${args.id}`);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
const verifyListCommand = defineCommand({
|
|
342
|
+
meta: {
|
|
343
|
+
name: "verify-list",
|
|
344
|
+
description: "List verified WebResources from the Site Verification API (distinct from Search Console properties)"
|
|
345
|
+
},
|
|
346
|
+
args: { ...OUTPUT_ARGS },
|
|
347
|
+
async run({ args }) {
|
|
348
|
+
applyOutputMode(args);
|
|
349
|
+
const resources = await listVerifiedSites((await createCommandContext({ needsAuth: true })).client).catch(gscErrorHandler);
|
|
350
|
+
if (args.json) {
|
|
351
|
+
console.log(JSON.stringify(resources, null, 2));
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
if (resources.length === 0) {
|
|
355
|
+
logger.warn("No verified WebResources found");
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
logger.success(`${resources.length} verified WebResources:`);
|
|
359
|
+
console.log();
|
|
360
|
+
for (const r of resources) {
|
|
361
|
+
const id = r.id ?? "?";
|
|
362
|
+
const site = r.site;
|
|
363
|
+
const ident = site?.identifier ?? id;
|
|
364
|
+
const type = site?.type === "INET_DOMAIN" ? "domain" : "site";
|
|
365
|
+
console.log(` \x1B[1m${ident}\x1B[0m \x1B[90m(${type})\x1B[0m`);
|
|
366
|
+
if (r.owners?.length) for (const o of r.owners) console.log(` \x1B[90m└─\x1B[0m ${o}`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
const getCommand = defineCommand({
|
|
371
|
+
meta: {
|
|
372
|
+
name: "get",
|
|
373
|
+
description: "Show a single property's permissionLevel from the sites list"
|
|
374
|
+
},
|
|
375
|
+
args: {
|
|
376
|
+
url: {
|
|
377
|
+
type: "positional",
|
|
378
|
+
required: true,
|
|
379
|
+
description: "Property URL"
|
|
380
|
+
},
|
|
381
|
+
...OUTPUT_ARGS
|
|
382
|
+
},
|
|
383
|
+
async run({ args }) {
|
|
384
|
+
applyOutputMode(args);
|
|
385
|
+
const site = (await (await createCommandContext({ needsAuth: true })).loadSites()).find((s) => s.siteUrl === args.url);
|
|
386
|
+
if (!site) {
|
|
387
|
+
if (args.json) {
|
|
388
|
+
console.log(JSON.stringify(null));
|
|
389
|
+
process.exit(1);
|
|
390
|
+
}
|
|
391
|
+
logger.error(`Not found: ${args.url}`);
|
|
392
|
+
process.exit(1);
|
|
393
|
+
}
|
|
394
|
+
if (args.json) {
|
|
395
|
+
console.log(JSON.stringify(site, null, 2));
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const perm = site.permissionLevel === "siteOwner" ? "\x1B[32m" : "\x1B[90m";
|
|
399
|
+
console.log();
|
|
400
|
+
console.log(` \x1B[1m${site.siteUrl}\x1B[0m`);
|
|
401
|
+
console.log(` Permission: ${perm}${site.permissionLevel}\x1B[0m`);
|
|
402
|
+
console.log();
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
const LIST_ARGS = {
|
|
406
|
+
...OUTPUT_ARGS,
|
|
407
|
+
"with-sitemaps": {
|
|
408
|
+
type: "boolean",
|
|
409
|
+
default: false,
|
|
410
|
+
description: "Include sitemaps for each owned site"
|
|
411
|
+
},
|
|
412
|
+
"owner-only": {
|
|
413
|
+
type: "boolean",
|
|
414
|
+
default: false,
|
|
415
|
+
description: "Filter to permissionLevel=siteOwner"
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
async function runListSites(args) {
|
|
419
|
+
applyOutputMode(args);
|
|
420
|
+
const ctx = await createCommandContext({ needsAuth: true });
|
|
421
|
+
const ownerOnly = Boolean(args["owner-only"]);
|
|
422
|
+
if (args["with-sitemaps"]) {
|
|
423
|
+
const all = await fetchSitesWithSitemaps(ctx.client).catch(gscErrorHandler);
|
|
424
|
+
const sites = ownerOnly ? all.filter((s) => s.permissionLevel === "siteOwner") : all;
|
|
425
|
+
if (args.json) {
|
|
426
|
+
const enriched = sites.map((s) => ({
|
|
427
|
+
...s,
|
|
428
|
+
sitemapCounts: {
|
|
429
|
+
total: s.sitemaps.length,
|
|
430
|
+
pending: s.sitemaps.filter((sm) => sm.isPending).length,
|
|
431
|
+
errored: s.sitemaps.filter((sm) => Number(sm.errors) > 0).length
|
|
432
|
+
}
|
|
433
|
+
}));
|
|
434
|
+
console.log(JSON.stringify(enriched, null, 2));
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
if (sites.length === 0) {
|
|
438
|
+
logger.warn(ownerOnly ? "No owned sites found" : "No verified sites found");
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
logger.success(`Found ${sites.length} ${ownerOnly ? "owned" : "verified"} sites:`);
|
|
442
|
+
console.log();
|
|
443
|
+
for (const site of sites) {
|
|
444
|
+
const perm = site.permissionLevel === "siteOwner" ? "\x1B[32m" : "\x1B[90m";
|
|
445
|
+
console.log(` ${site.siteUrl} ${perm}(${site.permissionLevel})\x1B[0m`);
|
|
446
|
+
for (const sm of site.sitemaps) {
|
|
447
|
+
const pending = sm.isPending ? " \x1B[33m(pending)\x1B[0m" : "";
|
|
448
|
+
console.log(` \x1B[90m└─\x1B[0m ${sm.path}${pending}`);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
const all = await ctx.loadSites();
|
|
454
|
+
const sites = ownerOnly ? all.filter((s) => s.permissionLevel === "siteOwner") : all;
|
|
455
|
+
if (args.json) {
|
|
456
|
+
console.log(JSON.stringify(sites, null, 2));
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
if (sites.length === 0) {
|
|
460
|
+
logger.warn(ownerOnly ? "No owned sites found" : "No verified sites found");
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
logger.success(`Found ${sites.length} ${ownerOnly ? "owned " : ""}sites:`);
|
|
464
|
+
console.log();
|
|
465
|
+
for (const site of sites) {
|
|
466
|
+
const perm = site.permissionLevel === "siteOwner" ? "\x1B[32m" : "\x1B[90m";
|
|
467
|
+
console.log(` ${site.siteUrl} ${perm}(${site.permissionLevel})\x1B[0m`);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
const sitesCommand = defineCommand({
|
|
471
|
+
meta: {
|
|
472
|
+
name: "sites",
|
|
473
|
+
description: "List GSC sites; manage properties (add/delete) and verify ownership"
|
|
474
|
+
},
|
|
475
|
+
args: LIST_ARGS,
|
|
476
|
+
subCommands: {
|
|
477
|
+
"list": defineCommand({
|
|
478
|
+
meta: {
|
|
479
|
+
name: "list",
|
|
480
|
+
description: "List GSC sites (alias of bare `sites`)"
|
|
481
|
+
},
|
|
482
|
+
args: LIST_ARGS,
|
|
483
|
+
async run({ args }) {
|
|
484
|
+
await runListSites(args);
|
|
485
|
+
}
|
|
486
|
+
}),
|
|
487
|
+
"add": addCommand,
|
|
488
|
+
"delete": deleteCommand,
|
|
489
|
+
"get": getCommand,
|
|
490
|
+
"verify-token": verifyTokenCommand,
|
|
491
|
+
"verify": verifyCommand,
|
|
492
|
+
"verify-list": verifyListCommand,
|
|
493
|
+
"verify-get": verifyGetCommand,
|
|
494
|
+
"unverify": unverifyCommand
|
|
495
|
+
},
|
|
496
|
+
async run({ args }) {
|
|
497
|
+
await runListSites(args);
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
export { sitesCommand };
|