@koda-sl/baker-cli 0.532.0 → 0.533.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/dist/chunk-L4LNS54Y.js +138 -0
- package/dist/chunk-L4LNS54Y.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/{gsc-72AFO6B4.js → gsc-GQFI6I2D.js} +4 -4
- package/dist/{query-NDOYOIHL.js → query-JOYRNM4O.js} +4 -20
- package/dist/query-JOYRNM4O.js.map +1 -0
- package/dist/{sitemaps-6A6JFBV4.js → sitemaps-VYLDUI4L.js} +4 -14
- package/dist/sitemaps-VYLDUI4L.js.map +1 -0
- package/dist/{sites-PZLE5FFV.js → sites-HM7ZCGCZ.js} +20 -24
- package/dist/sites-HM7ZCGCZ.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-6OXENBTF.js +0 -74
- package/dist/chunk-6OXENBTF.js.map +0 -1
- package/dist/query-NDOYOIHL.js.map +0 -1
- package/dist/sitemaps-6A6JFBV4.js.map +0 -1
- package/dist/sites-PZLE5FFV.js.map +0 -1
- /package/dist/{gsc-72AFO6B4.js.map → gsc-GQFI6I2D.js.map} +0 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cacheGet,
|
|
3
|
+
cacheSet,
|
|
4
|
+
handleConnectionError,
|
|
5
|
+
needsConnectionFix,
|
|
6
|
+
writeJsonEnvelope
|
|
7
|
+
} from "./chunk-LV7EU6HM.js";
|
|
8
|
+
import {
|
|
9
|
+
ApiError,
|
|
10
|
+
apiGet
|
|
11
|
+
} from "./chunk-CIW3Q7B2.js";
|
|
12
|
+
import {
|
|
13
|
+
getEnv,
|
|
14
|
+
optionalTargetCompany
|
|
15
|
+
} from "./chunk-VPF5A7CM.js";
|
|
16
|
+
|
|
17
|
+
// src/commands/gsc/errors.ts
|
|
18
|
+
var RETRYABLE_CODES = /* @__PURE__ */ new Set(["RATE_LIMITED", "UNAVAILABLE", "INTERNAL_ERROR", "NETWORK_ERROR", "TIMEOUT"]);
|
|
19
|
+
function handleGscError(err) {
|
|
20
|
+
if (!(err instanceof ApiError)) {
|
|
21
|
+
writeJsonEnvelope({
|
|
22
|
+
ok: false,
|
|
23
|
+
error: {
|
|
24
|
+
code: "NETWORK_ERROR",
|
|
25
|
+
message: err instanceof Error ? err.message : "Unexpected error",
|
|
26
|
+
retryable: true
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
if (needsConnectionFix(err.code, err.message)) {
|
|
32
|
+
handleConnectionError("gsc", err.message);
|
|
33
|
+
}
|
|
34
|
+
writeJsonEnvelope({
|
|
35
|
+
ok: false,
|
|
36
|
+
error: { code: err.code, message: err.message, retryable: RETRYABLE_CODES.has(err.code) }
|
|
37
|
+
});
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/commands/gsc/resolve.ts
|
|
42
|
+
function isReadableSite(site) {
|
|
43
|
+
return site.permissionLevel !== "siteUnverifiedUser";
|
|
44
|
+
}
|
|
45
|
+
async function handleGscSiteError(err, refusedSiteUrl) {
|
|
46
|
+
if (!(err instanceof ApiError) || err.code !== "FORBIDDEN" || !/permission/i.test(err.message)) {
|
|
47
|
+
return handleGscError(err);
|
|
48
|
+
}
|
|
49
|
+
let sites;
|
|
50
|
+
try {
|
|
51
|
+
sites = await fetchSites(false);
|
|
52
|
+
} catch {
|
|
53
|
+
return handleGscError(err);
|
|
54
|
+
}
|
|
55
|
+
const readable = sites.filter((site) => isReadableSite(site) && site.siteUrl !== refusedSiteUrl).map((site) => site.siteUrl);
|
|
56
|
+
writeJsonEnvelope({
|
|
57
|
+
ok: false,
|
|
58
|
+
error: {
|
|
59
|
+
code: err.code,
|
|
60
|
+
message: err.message,
|
|
61
|
+
retryable: false,
|
|
62
|
+
fix: readable.length > 0 ? useReadableSiteFix(readable) : noReadableSiteFix()
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
function useReadableSiteFix(readable) {
|
|
68
|
+
return {
|
|
69
|
+
action: "use_readable_site",
|
|
70
|
+
explanation: `The Google account connected to Search Console cannot read this site. Retrying will not help. Run the same read with --site-url set to one of: ${readable.join(", ")}.`,
|
|
71
|
+
validValues: readable
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function noReadableSiteFix() {
|
|
75
|
+
if (optionalTargetCompany()) {
|
|
76
|
+
return {
|
|
77
|
+
action: "continue_without",
|
|
78
|
+
explanation: "The Google account connected to Search Console for that company cannot read any of its sites. It can only be reconnected in that company's own workspace, never with `request_connection` from here. Show that company's Search Console as unavailable and carry on with the others."
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
action: "request_connection",
|
|
83
|
+
explanation: 'The Google account connected to Search Console cannot read any of this company\'s sites. Call the `request_connection` tool with { platform: "google-search-console", reason } so the user reconnects with a Google account that has access to the site, then carry on with the rest of the task.'
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async function fetchSites(useCache = true) {
|
|
87
|
+
if (useCache) {
|
|
88
|
+
const cached = cacheGet("gsc-sites", "list");
|
|
89
|
+
if (cached) return cached.data;
|
|
90
|
+
}
|
|
91
|
+
const params = !useCache ? { "skip-cache": "true" } : void 0;
|
|
92
|
+
const data = await apiGet("/api/gsc/sites", params);
|
|
93
|
+
if (useCache) {
|
|
94
|
+
cacheSet("gsc-sites", "list", data, 60 * 60 * 1e3);
|
|
95
|
+
}
|
|
96
|
+
return data;
|
|
97
|
+
}
|
|
98
|
+
async function resolveSiteUrl(args) {
|
|
99
|
+
const fromArgs = args["site-url"];
|
|
100
|
+
const fromEnv = getEnv().BAKER_GSC_SITE_URL;
|
|
101
|
+
const siteUrl = fromArgs || fromEnv;
|
|
102
|
+
if (siteUrl) return siteUrl;
|
|
103
|
+
const useCache = !args["no-cache"];
|
|
104
|
+
try {
|
|
105
|
+
const listed = await fetchSites(useCache);
|
|
106
|
+
const readable = listed.filter(isReadableSite);
|
|
107
|
+
const sites = readable.length > 0 ? readable : listed;
|
|
108
|
+
const [single] = sites;
|
|
109
|
+
if (sites.length === 1 && single) {
|
|
110
|
+
process.stderr.write(`Using site "${single.siteUrl}"
|
|
111
|
+
`);
|
|
112
|
+
return single.siteUrl;
|
|
113
|
+
}
|
|
114
|
+
if (sites.length === 0) {
|
|
115
|
+
handleConnectionError("gsc");
|
|
116
|
+
}
|
|
117
|
+
const list = sites.map((s) => ` ${s.siteUrl} (${s.permissionLevel})`).join("\n");
|
|
118
|
+
writeJsonEnvelope({
|
|
119
|
+
ok: false,
|
|
120
|
+
error: {
|
|
121
|
+
code: "MULTIPLE_SITES",
|
|
122
|
+
message: `Multiple sites found. Pass --site-url or set BAKER_GSC_SITE_URL:
|
|
123
|
+
${list}`
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
process.exit(1);
|
|
127
|
+
} catch (err) {
|
|
128
|
+
handleGscError(err);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export {
|
|
133
|
+
handleGscError,
|
|
134
|
+
isReadableSite,
|
|
135
|
+
handleGscSiteError,
|
|
136
|
+
resolveSiteUrl
|
|
137
|
+
};
|
|
138
|
+
//# sourceMappingURL=chunk-L4LNS54Y.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/gsc/errors.ts","../src/commands/gsc/resolve.ts"],"sourcesContent":["import { ApiError } from \"../../client.ts\";\nimport { handleConnectionError, needsConnectionFix } from \"../../error-handler.ts\";\nimport { writeJsonEnvelope } from \"../ads/output.ts\";\n\nconst RETRYABLE_CODES = new Set([\"RATE_LIMITED\", \"UNAVAILABLE\", \"INTERNAL_ERROR\", \"NETWORK_ERROR\", \"TIMEOUT\"]);\n\n/**\n * The one error shape for every Search Console read. A dead sign-in gets the\n * in-chat reconnect whatever its wording, and every other failure says whether\n * asking again can help, so an outage is never read as a broken connection.\n */\nexport function handleGscError(err: unknown): never {\n if (!(err instanceof ApiError)) {\n writeJsonEnvelope({\n ok: false,\n error: {\n code: \"NETWORK_ERROR\",\n message: err instanceof Error ? err.message : \"Unexpected error\",\n retryable: true,\n },\n });\n process.exit(1);\n }\n if (needsConnectionFix(err.code, err.message)) {\n handleConnectionError(\"gsc\", err.message);\n }\n writeJsonEnvelope({\n ok: false,\n error: { code: err.code, message: err.message, retryable: RETRYABLE_CODES.has(err.code) },\n });\n process.exit(1);\n}\n","import { ApiError, apiGet } from \"../../client.ts\";\nimport { getEnv, optionalTargetCompany } from \"../../env.ts\";\nimport { handleConnectionError } from \"../../error-handler.ts\";\nimport { cacheGet, cacheSet } from \"../ads/cache.ts\";\nimport { writeJsonEnvelope } from \"../ads/output.ts\";\nimport { handleGscError } from \"./errors.ts\";\n\ninterface GscSite {\n siteUrl: string;\n permissionLevel: string;\n}\n\n/** Search Console lists a site to an unverified user but answers every read of it with a 403. */\nexport function isReadableSite(site: GscSite): boolean {\n return site.permissionLevel !== \"siteUnverifiedUser\";\n}\n\n/**\n * A query or sitemap read refused because the signed-in Google account cannot\n * read that site: name the connected sites it can read now, or ask for a\n * reconnect with an account that has access when there are none.\n */\nexport async function handleGscSiteError(err: unknown, refusedSiteUrl: string): Promise<never> {\n if (!(err instanceof ApiError) || err.code !== \"FORBIDDEN\" || !/permission/i.test(err.message)) {\n return handleGscError(err);\n }\n // Permissions change under a cached listing: ask Search Console again, past both caches.\n let sites: GscSite[];\n try {\n sites = await fetchSites(false);\n } catch {\n return handleGscError(err);\n }\n const readable = sites\n .filter((site) => isReadableSite(site) && site.siteUrl !== refusedSiteUrl)\n .map((site) => site.siteUrl);\n writeJsonEnvelope({\n ok: false,\n error: {\n code: err.code,\n message: err.message,\n retryable: false,\n fix: readable.length > 0 ? useReadableSiteFix(readable) : noReadableSiteFix(),\n },\n });\n process.exit(1);\n}\n\nfunction useReadableSiteFix(readable: string[]) {\n return {\n action: \"use_readable_site\",\n explanation:\n \"The Google account connected to Search Console cannot read this site. Retrying will not help. \" +\n `Run the same read with --site-url set to one of: ${readable.join(\", \")}.`,\n validValues: readable,\n };\n}\n\nfunction noReadableSiteFix() {\n // Read with `--company` from the organization workspace: reconnecting from here\n // would connect the workspace, not the company the read named.\n if (optionalTargetCompany()) {\n return {\n action: \"continue_without\",\n explanation:\n \"The Google account connected to Search Console for that company cannot read any of its sites. It can only \" +\n \"be reconnected in that company's own workspace, never with `request_connection` from here. Show that \" +\n \"company's Search Console as unavailable and carry on with the others.\",\n };\n }\n return {\n action: \"request_connection\",\n explanation:\n \"The Google account connected to Search Console cannot read any of this company's sites. Call the \" +\n '`request_connection` tool with { platform: \"google-search-console\", reason } so the user reconnects ' +\n \"with a Google account that has access to the site, then carry on with the rest of the task.\",\n };\n}\n\nasync function fetchSites(useCache = true): Promise<GscSite[]> {\n if (useCache) {\n const cached = cacheGet<GscSite[]>(\"gsc-sites\", \"list\");\n if (cached) return cached.data;\n }\n const params = !useCache ? { \"skip-cache\": \"true\" } : undefined;\n const data = await apiGet<GscSite[]>(\"/api/gsc/sites\", params);\n if (useCache) {\n cacheSet(\"gsc-sites\", \"list\", data, 60 * 60 * 1000);\n }\n return data;\n}\n\nexport async function resolveSiteUrl(args: Record<string, unknown>): Promise<string> {\n const fromArgs = args[\"site-url\"] as string | undefined;\n const fromEnv = getEnv().BAKER_GSC_SITE_URL;\n const siteUrl = fromArgs || fromEnv;\n\n if (siteUrl) return siteUrl;\n\n const useCache = !args[\"no-cache\"];\n\n try {\n const listed = await fetchSites(useCache);\n const readable = listed.filter(isReadableSite);\n // A site the account cannot read is never picked, matching what `gsc sites` promises.\n const sites = readable.length > 0 ? readable : listed;\n const [single] = sites;\n if (sites.length === 1 && single) {\n process.stderr.write(`Using site \"${single.siteUrl}\"\\n`);\n return single.siteUrl;\n }\n if (sites.length === 0) {\n handleConnectionError(\"gsc\");\n }\n const list = sites.map((s) => ` ${s.siteUrl} (${s.permissionLevel})`).join(\"\\n\");\n writeJsonEnvelope({\n ok: false,\n error: {\n code: \"MULTIPLE_SITES\",\n message: `Multiple sites found. Pass --site-url or set BAKER_GSC_SITE_URL:\\n${list}`,\n },\n });\n process.exit(1);\n } catch (err) {\n handleGscError(err);\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -219,7 +219,7 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
|
|
|
219
219
|
analytics: () => import("./analytics-ANG42PKM.js").then((m) => m.analyticsCommand),
|
|
220
220
|
experiment: () => import("./experiment-2XR6MBE2.js").then((m) => m.experimentCommand),
|
|
221
221
|
ga4: () => import("./ga4-ULHKTF23.js").then((m) => m.ga4Command),
|
|
222
|
-
gsc: () => import("./gsc-
|
|
222
|
+
gsc: () => import("./gsc-GQFI6I2D.js").then((m) => m.gscCommand),
|
|
223
223
|
research: () => import("./research-LZBPCXIW.js").then((m) => m.researchCommand),
|
|
224
224
|
decide: () => import("./decide-OPCCKAIT.js").then((m) => m.decideCommand),
|
|
225
225
|
knowledge: () => import("./knowledge-L3VLOVLG.js").then((m) => m.knowledgeCommand),
|
|
@@ -19,12 +19,12 @@ Examples:
|
|
|
19
19
|
Full guide: __tooling__/docs/tools/baker/gsc.md`
|
|
20
20
|
},
|
|
21
21
|
subCommands: {
|
|
22
|
-
sites: () => import("./sites-
|
|
23
|
-
query: () => import("./query-
|
|
24
|
-
sitemaps: () => import("./sitemaps-
|
|
22
|
+
sites: () => import("./sites-HM7ZCGCZ.js").then((m) => m.sitesCommand),
|
|
23
|
+
query: () => import("./query-JOYRNM4O.js").then((m) => m.queryCommand),
|
|
24
|
+
sitemaps: () => import("./sitemaps-VYLDUI4L.js").then((m) => m.sitemapsCommand)
|
|
25
25
|
}
|
|
26
26
|
});
|
|
27
27
|
export {
|
|
28
28
|
gscCommand
|
|
29
29
|
};
|
|
30
|
-
//# sourceMappingURL=gsc-
|
|
30
|
+
//# sourceMappingURL=gsc-GQFI6I2D.js.map
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
|
+
handleGscSiteError,
|
|
2
3
|
resolveSiteUrl
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-L4LNS54Y.js";
|
|
4
5
|
import {
|
|
5
6
|
buildQueryCacheKey,
|
|
6
7
|
cacheGet,
|
|
7
8
|
cacheSet,
|
|
8
9
|
getQueryTtl,
|
|
9
|
-
handleConnectionError,
|
|
10
|
-
isNotConnectedError,
|
|
11
10
|
toCsvRow,
|
|
12
11
|
writeAdsOutput,
|
|
13
12
|
writeJsonEnvelope
|
|
14
13
|
} from "./chunk-LV7EU6HM.js";
|
|
15
14
|
import {
|
|
16
|
-
ApiError,
|
|
17
15
|
apiPost
|
|
18
16
|
} from "./chunk-CIW3Q7B2.js";
|
|
19
17
|
import "./chunk-O7AMKMII.js";
|
|
@@ -151,20 +149,6 @@ function buildRequestBody(args, siteUrl, useCache) {
|
|
|
151
149
|
if (!useCache) body.skipCache = true;
|
|
152
150
|
return body;
|
|
153
151
|
}
|
|
154
|
-
function handleError(err) {
|
|
155
|
-
if (err instanceof ApiError) {
|
|
156
|
-
if (isNotConnectedError(err.code, err.message)) {
|
|
157
|
-
handleConnectionError("gsc", err.message);
|
|
158
|
-
}
|
|
159
|
-
writeJsonEnvelope({ ok: false, error: { code: err.code, message: err.message } });
|
|
160
|
-
process.exit(1);
|
|
161
|
-
}
|
|
162
|
-
writeJsonEnvelope({
|
|
163
|
-
ok: false,
|
|
164
|
-
error: { code: "NETWORK_ERROR", message: err instanceof Error ? err.message : "Unexpected error" }
|
|
165
|
-
});
|
|
166
|
-
process.exit(1);
|
|
167
|
-
}
|
|
168
152
|
var queryCommand = defineCommand({
|
|
169
153
|
meta: {
|
|
170
154
|
name: "query",
|
|
@@ -237,11 +221,11 @@ Free-form (escape hatch):
|
|
|
237
221
|
}
|
|
238
222
|
outputRows(response.data ?? [], args, response, false);
|
|
239
223
|
} catch (err) {
|
|
240
|
-
|
|
224
|
+
await handleGscSiteError(err, siteUrl);
|
|
241
225
|
}
|
|
242
226
|
}
|
|
243
227
|
});
|
|
244
228
|
export {
|
|
245
229
|
queryCommand
|
|
246
230
|
};
|
|
247
|
-
//# sourceMappingURL=query-
|
|
231
|
+
//# sourceMappingURL=query-JOYRNM4O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/gsc/query.ts","../src/commands/gsc/presets.ts"],"sourcesContent":["import { appendFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { defineCommand } from \"citty\";\nimport { apiPost } from \"../../client.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { buildQueryCacheKey, cacheGet, cacheSet, getQueryTtl } from \"../ads/cache.ts\";\nimport { toCsvRow, writeAdsOutput, writeJsonEnvelope } from \"../ads/output.ts\";\nimport { GSC_PRESETS } from \"./presets.ts\";\nimport { handleGscSiteError, resolveSiteUrl } from \"./resolve.ts\";\n\nregisterSchema({\n command: \"gsc.query\",\n description:\n \"Run GSC Search Analytics queries. Use --preset for playbook-aligned queries (primary usage) or --dimensions for free-form queries.\",\n args: {\n \"site-url\": { type: \"string\", description: \"Site URL (auto-resolved if not provided)\", required: false },\n preset: {\n type: \"string\",\n description:\n \"Named preset (cannibalization, missed-revenue, brand-halo, negative-keywords, top-pages, top-queries)\",\n required: false,\n },\n brand: { type: \"string\", description: \"Brand name (required for brand-halo preset)\", required: false },\n dimensions: {\n type: \"string\",\n description: \"Comma-separated dimensions (escape hatch: query, page, country, device, date)\",\n required: false,\n },\n days: { type: \"string\", description: \"Lookback window in days (default: 28)\", required: false },\n \"start-date\": { type: \"string\", description: \"Explicit start date (YYYY-MM-DD)\", required: false },\n \"end-date\": { type: \"string\", description: \"Explicit end date (YYYY-MM-DD)\", required: false },\n \"row-limit\": { type: \"string\", description: \"Max rows (default: 1000, max: 25000)\", required: false },\n type: { type: \"string\", description: \"Search type: web|image|video|news|discover (default: web)\", required: false },\n filter: { type: \"string\", description: \"Dimension filter groups as JSON string\", required: false },\n \"list-presets\": { type: \"boolean\", description: \"List available presets\", required: false },\n out: { type: \"string\", description: \"Write data to file (.csv, .jsonl, .json)\", required: false },\n append: { type: \"boolean\", description: \"Append to existing file\", required: false },\n output: { type: \"string\", description: \"Format: json|csv|jsonl|md\", required: false, default: \"json\" },\n \"no-cache\": { type: \"boolean\", description: \"Skip cache\", required: false },\n },\n});\n\ninterface QueryApiResponse {\n ok: boolean;\n data?: Array<Record<string, unknown>>;\n preset?: string;\n error?: { code: string; message: string };\n}\n\nfunction extractFields(rows: Array<Record<string, unknown>>): string[] {\n const first = rows[0];\n return first ? Object.keys(first) : [];\n}\n\nfunction writeRowsToFile(filePath: string, rows: Array<Record<string, unknown>>, append: boolean): void {\n const fields = extractFields(rows);\n const ext = filePath.split(\".\").pop()?.toLowerCase();\n if (ext === \"csv\") {\n if (!append || !existsSync(filePath)) {\n writeFileSync(filePath, `${toCsvRow(fields)}\\n`, \"utf-8\");\n }\n const csvRows = rows.map((row) => toCsvRow(fields.map((f) => String(row[f] ?? \"\"))));\n appendFileSync(filePath, `${csvRows.join(\"\\n\")}\\n`, \"utf-8\");\n } else if (ext === \"jsonl\") {\n const content = `${rows.map((row) => JSON.stringify(row)).join(\"\\n\")}\\n`;\n if (append && existsSync(filePath)) {\n appendFileSync(filePath, content, \"utf-8\");\n } else {\n writeFileSync(filePath, content, \"utf-8\");\n }\n } else if (append && existsSync(filePath)) {\n const existing = JSON.parse(readFileSync(filePath, \"utf-8\")) as unknown[];\n writeFileSync(filePath, JSON.stringify([...existing, ...rows], null, 2), \"utf-8\");\n } else {\n writeFileSync(filePath, JSON.stringify(rows, null, 2), \"utf-8\");\n }\n}\n\nfunction outputRows(\n rows: Array<Record<string, unknown>>,\n args: Record<string, unknown>,\n response: QueryApiResponse,\n cached: boolean,\n): void {\n if (args.out) {\n const filePath = resolve(args.out as string);\n writeRowsToFile(filePath, rows, !!args.append);\n writeJsonEnvelope({ ok: true, file: filePath, rows: rows.length, ...(cached && { cached: true }) });\n return;\n }\n const format = (args.output as string) || \"json\";\n if (format !== \"json\") {\n writeAdsOutput(rows, format);\n return;\n }\n writeJsonEnvelope({ ...response, ...(cached && { cached: true }) });\n}\n\nfunction buildRequestBody(args: Record<string, unknown>, siteUrl: string, useCache: boolean): Record<string, unknown> {\n const body: Record<string, unknown> = { siteUrl };\n if (args.preset) body.preset = args.preset;\n if (args.brand) body.brand = args.brand;\n if (args.dimensions) body.dimensions = (args.dimensions as string).split(\",\").map((d) => d.trim());\n if (args.days) body.days = Number(args.days);\n if (args[\"start-date\"]) body.startDate = args[\"start-date\"];\n if (args[\"end-date\"]) body.endDate = args[\"end-date\"];\n if (args[\"row-limit\"]) body.rowLimit = Number(args[\"row-limit\"]);\n if (args.type) body.type = args.type;\n if (args.filter) body.filter = args.filter;\n if (!useCache) body.skipCache = true;\n return body;\n}\n\nexport const queryCommand = defineCommand({\n meta: {\n name: \"query\",\n description: `Run GSC Search Analytics queries. Preset-first with free-form escape hatch.\n\nPresets (primary usage):\n baker gsc query --preset cannibalization\n baker gsc query --preset brand-halo --brand \"Acme\" --days 90\n baker gsc query --list-presets\n\nFree-form (escape hatch):\n baker gsc query --dimensions \"query,page\" --days 28\n baker gsc query --dimensions \"query\" --row-limit 25000 --out keywords.csv`,\n },\n args: {\n \"site-url\": { type: \"string\", description: \"Site URL\", required: false },\n preset: { type: \"string\", description: \"Named preset\", required: false },\n brand: { type: \"string\", description: \"Brand name for brand-halo preset\", required: false },\n dimensions: { type: \"string\", description: \"Comma-separated dimensions\", required: false },\n days: { type: \"string\", description: \"Lookback days (default: 28)\", required: false },\n \"start-date\": { type: \"string\", description: \"Start date override\", required: false },\n \"end-date\": { type: \"string\", description: \"End date override\", required: false },\n \"row-limit\": { type: \"string\", description: \"Max rows (default: 1000)\", required: false },\n type: { type: \"string\", description: \"Search type (default: web)\", required: false },\n filter: { type: \"string\", description: \"Filter JSON\", required: false },\n \"list-presets\": { type: \"boolean\", description: \"List presets\", required: false },\n out: { type: \"string\", description: \"Output file path\", required: false },\n append: { type: \"boolean\", description: \"Append to file\", required: false },\n output: { type: \"string\", description: \"Format: json|csv|jsonl|md\", required: false, default: \"json\" },\n \"no-cache\": { type: \"boolean\", description: \"Skip cache\", required: false },\n },\n run: async ({ args }) => {\n if (args[\"list-presets\"]) {\n writeJsonEnvelope({\n ok: true,\n data: GSC_PRESETS.map((p) => ({\n name: p.name,\n description: p.description,\n playbook: p.playbook,\n ...(p.requiresBrand && { requiresBrand: true }),\n })),\n });\n return;\n }\n\n if (!args.preset && !args.dimensions) {\n writeJsonEnvelope({\n ok: false,\n error: {\n code: \"VALIDATION_ERROR\",\n message: \"Provide --preset or --dimensions. Run --list-presets to see options.\",\n },\n });\n process.exit(1);\n }\n\n const siteUrl = await resolveSiteUrl(args);\n const useCache = !args[\"no-cache\"];\n const body = buildRequestBody(args, siteUrl, useCache);\n const cacheKey = buildQueryCacheKey(siteUrl, JSON.stringify(body));\n\n if (useCache) {\n const cached = cacheGet<QueryApiResponse>(\"gsc-queries\", cacheKey);\n if (cached) {\n outputRows(cached.data.data ?? [], args, cached.data, true);\n return;\n }\n }\n\n try {\n const response = await apiPost<QueryApiResponse>(\"/api/gsc/query\", body);\n if (useCache) {\n cacheSet(\"gsc-queries\", cacheKey, response, getQueryTtl(JSON.stringify(body)));\n }\n outputRows(response.data ?? [], args, response, false);\n } catch (err) {\n await handleGscSiteError(err, siteUrl);\n }\n },\n});\n","interface GscPreset {\n name: string;\n description: string;\n playbook: string;\n requiresBrand?: boolean;\n}\n\nexport const GSC_PRESETS: GscPreset[] = [\n {\n name: \"cannibalization\",\n description: \"PPC-SEO arbitrage — find queries ranking #1-2 organically where you also pay for ads\",\n playbook: \"[05] PPC-SEO Arbitrage\",\n },\n {\n name: \"missed-revenue\",\n description: \"High-impression queries with no PPC coverage (position > 10)\",\n playbook: \"[05] Opportunity Finder\",\n },\n {\n name: \"brand-halo\",\n description: \"Brand search volume trends — proves upper-funnel awareness lift\",\n playbook: \"[21] YouTube/DG ROI\",\n requiresBrand: true,\n },\n {\n name: \"negative-keywords\",\n description: \"Discover negative keyword candidates (login, support, cancel queries)\",\n playbook: \"Negative Keyword Discovery\",\n },\n {\n name: \"top-pages\",\n description: \"Top performing pages by clicks\",\n playbook: \"General\",\n },\n {\n name: \"top-queries\",\n description: \"Top search queries by clicks\",\n playbook: \"General\",\n },\n];\n"],"mappings":"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","names":[]}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
+
handleGscSiteError,
|
|
2
3
|
resolveSiteUrl
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-L4LNS54Y.js";
|
|
4
5
|
import {
|
|
5
6
|
cacheGet,
|
|
6
7
|
cacheSet,
|
|
7
|
-
handleConnectionError,
|
|
8
|
-
isNotConnectedError,
|
|
9
8
|
writeAdsOutput,
|
|
10
9
|
writeJsonEnvelope
|
|
11
10
|
} from "./chunk-LV7EU6HM.js";
|
|
12
11
|
import {
|
|
13
|
-
ApiError,
|
|
14
12
|
apiGet
|
|
15
13
|
} from "./chunk-CIW3Q7B2.js";
|
|
16
14
|
import "./chunk-O7AMKMII.js";
|
|
@@ -69,19 +67,11 @@ Examples:
|
|
|
69
67
|
}
|
|
70
68
|
writeJsonEnvelope({ ok: true, data });
|
|
71
69
|
} catch (err) {
|
|
72
|
-
|
|
73
|
-
if (isNotConnectedError(err.code, err.message)) {
|
|
74
|
-
handleConnectionError("gsc", err.message);
|
|
75
|
-
}
|
|
76
|
-
writeJsonEnvelope({ ok: false, error: { code: err.code, message: err.message } });
|
|
77
|
-
process.exit(1);
|
|
78
|
-
}
|
|
79
|
-
writeJsonEnvelope({ ok: false, error: { code: "NETWORK_ERROR", message: "Unexpected error" } });
|
|
80
|
-
process.exit(1);
|
|
70
|
+
await handleGscSiteError(err, siteUrl);
|
|
81
71
|
}
|
|
82
72
|
}
|
|
83
73
|
});
|
|
84
74
|
export {
|
|
85
75
|
sitemapsCommand
|
|
86
76
|
};
|
|
87
|
-
//# sourceMappingURL=sitemaps-
|
|
77
|
+
//# sourceMappingURL=sitemaps-VYLDUI4L.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/gsc/sitemaps.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { apiGet } from \"../../client.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { cacheGet, cacheSet } from \"../ads/cache.ts\";\nimport { writeAdsOutput, writeJsonEnvelope } from \"../ads/output.ts\";\nimport { handleGscSiteError, resolveSiteUrl } from \"./resolve.ts\";\n\nregisterSchema({\n command: \"gsc.sitemaps\",\n description: \"List sitemaps for a Search Console site. Check sitemap health and errors.\",\n args: {\n \"site-url\": { type: \"string\", description: \"Site URL (auto-resolved if not provided)\", required: false },\n \"no-cache\": { type: \"boolean\", description: \"Skip cache, hit API directly\", required: false },\n },\n});\n\ninterface SitemapInfo {\n path: string;\n lastSubmitted?: string;\n isPending?: boolean;\n isSitemapsIndex?: boolean;\n type?: string;\n lastDownloaded?: string;\n warnings?: string;\n errors?: string;\n}\n\nexport const sitemapsCommand = defineCommand({\n meta: {\n name: \"sitemaps\",\n description: `List sitemaps for a site. Check health and errors.\n\nExamples:\n baker gsc sitemaps\n baker gsc sitemaps --site-url \"https://example.com/\"`,\n },\n args: {\n \"site-url\": { type: \"string\", description: \"Site URL\", required: false },\n \"no-cache\": { type: \"boolean\", description: \"Skip cache\", required: false },\n output: { type: \"string\", description: \"Format: json|csv|md\", required: false, default: \"json\" },\n },\n run: async ({ args }) => {\n const siteUrl = await resolveSiteUrl(args);\n const useCache = !args[\"no-cache\"];\n const cacheKey = `sitemaps:${siteUrl}`;\n\n if (useCache) {\n const cached = cacheGet<SitemapInfo[]>(\"gsc-sitemaps\", cacheKey);\n if (cached) {\n writeJsonEnvelope({ ok: true, data: cached.data, cached: true });\n return;\n }\n }\n\n try {\n const params: Record<string, string> = { \"site-url\": siteUrl };\n if (!useCache) params[\"skip-cache\"] = \"true\";\n const data = await apiGet<SitemapInfo[]>(\"/api/gsc/sitemaps\", params);\n if (useCache) {\n cacheSet(\"gsc-sitemaps\", cacheKey, data, 6 * 60 * 60 * 1000);\n }\n const format = (args.output as string) || \"json\";\n if (format !== \"json\") {\n writeAdsOutput(data as unknown as Array<Record<string, unknown>>, format);\n return;\n }\n writeJsonEnvelope({ ok: true, data });\n } catch (err) {\n await handleGscSiteError(err, siteUrl);\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,qBAAqB;AAO9B,eAAe;AAAA,EACb,SAAS;AAAA,EACT,aAAa;AAAA,EACb,MAAM;AAAA,IACJ,YAAY,EAAE,MAAM,UAAU,aAAa,4CAA4C,UAAU,MAAM;AAAA,IACvG,YAAY,EAAE,MAAM,WAAW,aAAa,gCAAgC,UAAU,MAAM;AAAA,EAC9F;AACF,CAAC;AAaM,IAAM,kBAAkB,cAAc;AAAA,EAC3C,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,EAKf;AAAA,EACA,MAAM;AAAA,IACJ,YAAY,EAAE,MAAM,UAAU,aAAa,YAAY,UAAU,MAAM;AAAA,IACvE,YAAY,EAAE,MAAM,WAAW,aAAa,cAAc,UAAU,MAAM;AAAA,IAC1E,QAAQ,EAAE,MAAM,UAAU,aAAa,uBAAuB,UAAU,OAAO,SAAS,OAAO;AAAA,EACjG;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,UAAM,UAAU,MAAM,eAAe,IAAI;AACzC,UAAM,WAAW,CAAC,KAAK,UAAU;AACjC,UAAM,WAAW,YAAY,OAAO;AAEpC,QAAI,UAAU;AACZ,YAAM,SAAS,SAAwB,gBAAgB,QAAQ;AAC/D,UAAI,QAAQ;AACV,0BAAkB,EAAE,IAAI,MAAM,MAAM,OAAO,MAAM,QAAQ,KAAK,CAAC;AAC/D;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAiC,EAAE,YAAY,QAAQ;AAC7D,UAAI,CAAC,SAAU,QAAO,YAAY,IAAI;AACtC,YAAM,OAAO,MAAM,OAAsB,qBAAqB,MAAM;AACpE,UAAI,UAAU;AACZ,iBAAS,gBAAgB,UAAU,MAAM,IAAI,KAAK,KAAK,GAAI;AAAA,MAC7D;AACA,YAAM,SAAU,KAAK,UAAqB;AAC1C,UAAI,WAAW,QAAQ;AACrB,uBAAe,MAAmD,MAAM;AACxE;AAAA,MACF;AACA,wBAAkB,EAAE,IAAI,MAAM,KAAK,CAAC;AAAA,IACtC,SAAS,KAAK;AACZ,YAAM,mBAAmB,KAAK,OAAO;AAAA,IACvC;AAAA,EACF;AACF,CAAC;","names":[]}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
handleGscError,
|
|
3
|
+
isReadableSite
|
|
4
|
+
} from "./chunk-L4LNS54Y.js";
|
|
1
5
|
import {
|
|
2
6
|
connectedResourceHints
|
|
3
7
|
} from "./chunk-P4NSJS54.js";
|
|
@@ -8,13 +12,10 @@ import {
|
|
|
8
12
|
import {
|
|
9
13
|
cacheGet,
|
|
10
14
|
cacheSet,
|
|
11
|
-
handleConnectionError,
|
|
12
|
-
needsConnectionFix,
|
|
13
15
|
writeAdsOutput,
|
|
14
16
|
writeJsonEnvelope
|
|
15
17
|
} from "./chunk-LV7EU6HM.js";
|
|
16
18
|
import {
|
|
17
|
-
ApiError,
|
|
18
19
|
apiGet
|
|
19
20
|
} from "./chunk-CIW3Q7B2.js";
|
|
20
21
|
import "./chunk-O7AMKMII.js";
|
|
@@ -28,7 +29,7 @@ import "./chunk-YQSBHWOI.js";
|
|
|
28
29
|
import { defineCommand } from "citty";
|
|
29
30
|
registerSchema({
|
|
30
31
|
command: "gsc.sites",
|
|
31
|
-
description: "List the Search Console sites this company connected \u2014 there can be several, and every one
|
|
32
|
+
description: "List the Search Console sites this company connected \u2014 there can be several, and every one the connected account can read is yours to query. Returns the site URLs the query and sitemaps commands take.",
|
|
32
33
|
args: {
|
|
33
34
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false },
|
|
34
35
|
output: { type: "string", description: "Format: json|csv|md", required: false, default: "json" },
|
|
@@ -36,23 +37,18 @@ registerSchema({
|
|
|
36
37
|
}
|
|
37
38
|
});
|
|
38
39
|
function siteHints(sites) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
writeJsonEnvelope({ ok: false, error: { code: err.code, message: err.message } });
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
writeJsonEnvelope({ ok: false, error: { code: "NETWORK_ERROR", message: "Unexpected error" } });
|
|
55
|
-
process.exit(1);
|
|
40
|
+
const unreadable = sites.filter((site) => !isReadableSite(site)).map(
|
|
41
|
+
(site) => `${site.siteUrl} cannot be read: the connected Google account is only an unverified user there (${site.permissionLevel}), so every query and sitemap read of it is refused. Leave it out, or ask the user to reconnect Search Console with a Google account that has access to it if its data is needed.`
|
|
42
|
+
);
|
|
43
|
+
return [
|
|
44
|
+
...connectedResourceHints({
|
|
45
|
+
plural: "Search Console sites",
|
|
46
|
+
singular: "Search Console site",
|
|
47
|
+
flag: "--site-url",
|
|
48
|
+
resources: sites.filter(isReadableSite).map((site) => ({ id: site.siteUrl, label: site.permissionLevel }))
|
|
49
|
+
}),
|
|
50
|
+
...unreadable
|
|
51
|
+
];
|
|
56
52
|
}
|
|
57
53
|
var sitesCommand = defineCommand({
|
|
58
54
|
meta: {
|
|
@@ -69,7 +65,7 @@ Examples:
|
|
|
69
65
|
available: AVAILABLE_ARG
|
|
70
66
|
},
|
|
71
67
|
run: async ({ args }) => {
|
|
72
|
-
if (args.available) return writeAvailableAccounts("google-search-console",
|
|
68
|
+
if (args.available) return writeAvailableAccounts("google-search-console", handleGscError);
|
|
73
69
|
const useCache = !args["no-cache"];
|
|
74
70
|
if (useCache) {
|
|
75
71
|
const cached = cacheGet("gsc-sites", "list");
|
|
@@ -91,11 +87,11 @@ Examples:
|
|
|
91
87
|
}
|
|
92
88
|
writeJsonEnvelope({ ok: true, data, hints: siteHints(data) });
|
|
93
89
|
} catch (err) {
|
|
94
|
-
|
|
90
|
+
handleGscError(err);
|
|
95
91
|
}
|
|
96
92
|
}
|
|
97
93
|
});
|
|
98
94
|
export {
|
|
99
95
|
sitesCommand
|
|
100
96
|
};
|
|
101
|
-
//# sourceMappingURL=sites-
|
|
97
|
+
//# sourceMappingURL=sites-HM7ZCGCZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/gsc/sites.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { AVAILABLE_ARG, writeAvailableAccounts } from \"../../available-accounts.ts\";\nimport { apiGet } from \"../../client.ts\";\nimport { connectedResourceHints } from \"../../connected-resources.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { cacheGet, cacheSet } from \"../ads/cache.ts\";\nimport { writeAdsOutput, writeJsonEnvelope } from \"../ads/output.ts\";\nimport { handleGscError } from \"./errors.ts\";\nimport { isReadableSite } from \"./resolve.ts\";\n\nregisterSchema({\n command: \"gsc.sites\",\n description:\n \"List the Search Console sites this company connected — there can be several, and every one the connected account can read is yours to query. Returns the site URLs the query and sitemaps commands take.\",\n args: {\n \"no-cache\": { type: \"boolean\", description: \"Skip cache, hit API directly\", required: false },\n output: { type: \"string\", description: \"Format: json|csv|md\", required: false, default: \"json\" },\n available: AVAILABLE_ARG,\n },\n});\n\ninterface SiteInfo {\n siteUrl: string;\n permissionLevel: string;\n}\n\nfunction siteHints(sites: SiteInfo[]): string[] {\n const unreadable = sites\n .filter((site) => !isReadableSite(site))\n .map(\n (site) =>\n `${site.siteUrl} cannot be read: the connected Google account is only an unverified user there ` +\n `(${site.permissionLevel}), so every query and sitemap read of it is refused. Leave it out, or ask the user ` +\n \"to reconnect Search Console with a Google account that has access to it if its data is needed.\",\n );\n return [\n ...connectedResourceHints({\n plural: \"Search Console sites\",\n singular: \"Search Console site\",\n flag: \"--site-url\",\n resources: sites.filter(isReadableSite).map((site) => ({ id: site.siteUrl, label: site.permissionLevel })),\n }),\n ...unreadable,\n ];\n}\n\nexport const sitesCommand = defineCommand({\n meta: {\n name: \"sites\",\n description: `List verified Search Console sites.\n\nExamples:\n baker gsc sites\n baker gsc sites --available # everything the login reaches, selected or not`,\n },\n args: {\n \"no-cache\": { type: \"boolean\", description: \"Skip cache\", required: false },\n output: { type: \"string\", description: \"Format: json|csv|md\", required: false, default: \"json\" },\n available: AVAILABLE_ARG,\n },\n run: async ({ args }) => {\n if (args.available) return writeAvailableAccounts(\"google-search-console\", handleGscError);\n const useCache = !args[\"no-cache\"];\n\n if (useCache) {\n const cached = cacheGet<SiteInfo[]>(\"gsc-sites\", \"list\");\n if (cached) {\n writeJsonEnvelope({ ok: true, data: cached.data, cached: true, hints: siteHints(cached.data) });\n return;\n }\n }\n\n try {\n const params = !useCache ? { \"skip-cache\": \"true\" } : undefined;\n const data = await apiGet<SiteInfo[]>(\"/api/gsc/sites\", params);\n if (useCache) {\n cacheSet(\"gsc-sites\", \"list\", data, 60 * 60 * 1000);\n }\n const format = (args.output as string) || \"json\";\n if (format !== \"json\") {\n writeAdsOutput(data as unknown as Array<Record<string, unknown>>, format);\n return;\n }\n writeJsonEnvelope({ ok: true, data, hints: siteHints(data) });\n } catch (err) {\n handleGscError(err);\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,qBAAqB;AAU9B,eAAe;AAAA,EACb,SAAS;AAAA,EACT,aACE;AAAA,EACF,MAAM;AAAA,IACJ,YAAY,EAAE,MAAM,WAAW,aAAa,gCAAgC,UAAU,MAAM;AAAA,IAC5F,QAAQ,EAAE,MAAM,UAAU,aAAa,uBAAuB,UAAU,OAAO,SAAS,OAAO;AAAA,IAC/F,WAAW;AAAA,EACb;AACF,CAAC;AAOD,SAAS,UAAU,OAA6B;AAC9C,QAAM,aAAa,MAChB,OAAO,CAAC,SAAS,CAAC,eAAe,IAAI,CAAC,EACtC;AAAA,IACC,CAAC,SACC,GAAG,KAAK,OAAO,mFACX,KAAK,eAAe;AAAA,EAE5B;AACF,SAAO;AAAA,IACL,GAAG,uBAAuB;AAAA,MACxB,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,MAAM;AAAA,MACN,WAAW,MAAM,OAAO,cAAc,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,KAAK,SAAS,OAAO,KAAK,gBAAgB,EAAE;AAAA,IAC3G,CAAC;AAAA,IACD,GAAG;AAAA,EACL;AACF;AAEO,IAAM,eAAe,cAAc;AAAA,EACxC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,EAKf;AAAA,EACA,MAAM;AAAA,IACJ,YAAY,EAAE,MAAM,WAAW,aAAa,cAAc,UAAU,MAAM;AAAA,IAC1E,QAAQ,EAAE,MAAM,UAAU,aAAa,uBAAuB,UAAU,OAAO,SAAS,OAAO;AAAA,IAC/F,WAAW;AAAA,EACb;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,QAAI,KAAK,UAAW,QAAO,uBAAuB,yBAAyB,cAAc;AACzF,UAAM,WAAW,CAAC,KAAK,UAAU;AAEjC,QAAI,UAAU;AACZ,YAAM,SAAS,SAAqB,aAAa,MAAM;AACvD,UAAI,QAAQ;AACV,0BAAkB,EAAE,IAAI,MAAM,MAAM,OAAO,MAAM,QAAQ,MAAM,OAAO,UAAU,OAAO,IAAI,EAAE,CAAC;AAC9F;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,CAAC,WAAW,EAAE,cAAc,OAAO,IAAI;AACtD,YAAM,OAAO,MAAM,OAAmB,kBAAkB,MAAM;AAC9D,UAAI,UAAU;AACZ,iBAAS,aAAa,QAAQ,MAAM,KAAK,KAAK,GAAI;AAAA,MACpD;AACA,YAAM,SAAU,KAAK,UAAqB;AAC1C,UAAI,WAAW,QAAQ;AACrB,uBAAe,MAAmD,MAAM;AACxE;AAAA,MACF;AACA,wBAAkB,EAAE,IAAI,MAAM,MAAM,OAAO,UAAU,IAAI,EAAE,CAAC;AAAA,IAC9D,SAAS,KAAK;AACZ,qBAAe,GAAG;AAAA,IACpB;AAAA,EACF;AACF,CAAC;","names":[]}
|
package/package.json
CHANGED
package/dist/chunk-6OXENBTF.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
cacheGet,
|
|
3
|
-
cacheSet,
|
|
4
|
-
handleConnectionError,
|
|
5
|
-
needsConnectionFix,
|
|
6
|
-
writeJsonEnvelope
|
|
7
|
-
} from "./chunk-LV7EU6HM.js";
|
|
8
|
-
import {
|
|
9
|
-
ApiError,
|
|
10
|
-
apiGet
|
|
11
|
-
} from "./chunk-CIW3Q7B2.js";
|
|
12
|
-
import {
|
|
13
|
-
getEnv
|
|
14
|
-
} from "./chunk-VPF5A7CM.js";
|
|
15
|
-
|
|
16
|
-
// src/commands/gsc/resolve.ts
|
|
17
|
-
async function fetchSites(useCache = true) {
|
|
18
|
-
if (useCache) {
|
|
19
|
-
const cached = cacheGet("gsc-sites", "list");
|
|
20
|
-
if (cached) return cached.data;
|
|
21
|
-
}
|
|
22
|
-
const params = !useCache ? { "skip-cache": "true" } : void 0;
|
|
23
|
-
const data = await apiGet("/api/gsc/sites", params);
|
|
24
|
-
if (useCache) {
|
|
25
|
-
cacheSet("gsc-sites", "list", data, 60 * 60 * 1e3);
|
|
26
|
-
}
|
|
27
|
-
return data;
|
|
28
|
-
}
|
|
29
|
-
async function resolveSiteUrl(args) {
|
|
30
|
-
const fromArgs = args["site-url"];
|
|
31
|
-
const fromEnv = getEnv().BAKER_GSC_SITE_URL;
|
|
32
|
-
const siteUrl = fromArgs || fromEnv;
|
|
33
|
-
if (siteUrl) return siteUrl;
|
|
34
|
-
const useCache = !args["no-cache"];
|
|
35
|
-
try {
|
|
36
|
-
const sites = await fetchSites(useCache);
|
|
37
|
-
const [single] = sites;
|
|
38
|
-
if (sites.length === 1 && single) {
|
|
39
|
-
process.stderr.write(`Using site "${single.siteUrl}"
|
|
40
|
-
`);
|
|
41
|
-
return single.siteUrl;
|
|
42
|
-
}
|
|
43
|
-
if (sites.length === 0) {
|
|
44
|
-
handleConnectionError("gsc");
|
|
45
|
-
}
|
|
46
|
-
const list = sites.map((s) => ` ${s.siteUrl} (${s.permissionLevel})`).join("\n");
|
|
47
|
-
writeJsonEnvelope({
|
|
48
|
-
ok: false,
|
|
49
|
-
error: {
|
|
50
|
-
code: "MULTIPLE_SITES",
|
|
51
|
-
message: `Multiple sites found. Pass --site-url or set BAKER_GSC_SITE_URL:
|
|
52
|
-
${list}`
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
process.exit(1);
|
|
56
|
-
} catch (err) {
|
|
57
|
-
if (err instanceof ApiError && needsConnectionFix(err.code, err.message)) {
|
|
58
|
-
handleConnectionError("gsc", err.message);
|
|
59
|
-
}
|
|
60
|
-
writeJsonEnvelope({
|
|
61
|
-
ok: false,
|
|
62
|
-
error: {
|
|
63
|
-
code: "RESOLUTION_ERROR",
|
|
64
|
-
message: "Could not auto-detect site. Pass --site-url or set BAKER_GSC_SITE_URL."
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
process.exit(1);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export {
|
|
72
|
-
resolveSiteUrl
|
|
73
|
-
};
|
|
74
|
-
//# sourceMappingURL=chunk-6OXENBTF.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/gsc/resolve.ts"],"sourcesContent":["import { ApiError, apiGet } from \"../../client.ts\";\nimport { getEnv } from \"../../env.ts\";\nimport { handleConnectionError, needsConnectionFix } from \"../../error-handler.ts\";\nimport { cacheGet, cacheSet } from \"../ads/cache.ts\";\nimport { writeJsonEnvelope } from \"../ads/output.ts\";\n\ninterface GscSite {\n siteUrl: string;\n permissionLevel: string;\n}\n\nasync function fetchSites(useCache = true): Promise<GscSite[]> {\n if (useCache) {\n const cached = cacheGet<GscSite[]>(\"gsc-sites\", \"list\");\n if (cached) return cached.data;\n }\n const params = !useCache ? { \"skip-cache\": \"true\" } : undefined;\n const data = await apiGet<GscSite[]>(\"/api/gsc/sites\", params);\n if (useCache) {\n cacheSet(\"gsc-sites\", \"list\", data, 60 * 60 * 1000);\n }\n return data;\n}\n\nexport async function resolveSiteUrl(args: Record<string, unknown>): Promise<string> {\n const fromArgs = args[\"site-url\"] as string | undefined;\n const fromEnv = getEnv().BAKER_GSC_SITE_URL;\n const siteUrl = fromArgs || fromEnv;\n\n if (siteUrl) return siteUrl;\n\n const useCache = !args[\"no-cache\"];\n\n try {\n const sites = await fetchSites(useCache);\n const [single] = sites;\n if (sites.length === 1 && single) {\n process.stderr.write(`Using site \"${single.siteUrl}\"\\n`);\n return single.siteUrl;\n }\n if (sites.length === 0) {\n handleConnectionError(\"gsc\");\n }\n const list = sites.map((s) => ` ${s.siteUrl} (${s.permissionLevel})`).join(\"\\n\");\n writeJsonEnvelope({\n ok: false,\n error: {\n code: \"MULTIPLE_SITES\",\n message: `Multiple sites found. Pass --site-url or set BAKER_GSC_SITE_URL:\\n${list}`,\n },\n });\n process.exit(1);\n } catch (err) {\n // The listing call is the only thing that can throw here, so a 401/404 from\n // it means the connection is missing — not that resolution is ambiguous.\n if (err instanceof ApiError && needsConnectionFix(err.code, err.message)) {\n handleConnectionError(\"gsc\", err.message);\n }\n writeJsonEnvelope({\n ok: false,\n error: {\n code: \"RESOLUTION_ERROR\",\n message: \"Could not auto-detect site. Pass --site-url or set BAKER_GSC_SITE_URL.\",\n },\n });\n process.exit(1);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAWA,eAAe,WAAW,WAAW,MAA0B;AAC7D,MAAI,UAAU;AACZ,UAAM,SAAS,SAAoB,aAAa,MAAM;AACtD,QAAI,OAAQ,QAAO,OAAO;AAAA,EAC5B;AACA,QAAM,SAAS,CAAC,WAAW,EAAE,cAAc,OAAO,IAAI;AACtD,QAAM,OAAO,MAAM,OAAkB,kBAAkB,MAAM;AAC7D,MAAI,UAAU;AACZ,aAAS,aAAa,QAAQ,MAAM,KAAK,KAAK,GAAI;AAAA,EACpD;AACA,SAAO;AACT;AAEA,eAAsB,eAAe,MAAgD;AACnF,QAAM,WAAW,KAAK,UAAU;AAChC,QAAM,UAAU,OAAO,EAAE;AACzB,QAAM,UAAU,YAAY;AAE5B,MAAI,QAAS,QAAO;AAEpB,QAAM,WAAW,CAAC,KAAK,UAAU;AAEjC,MAAI;AACF,UAAM,QAAQ,MAAM,WAAW,QAAQ;AACvC,UAAM,CAAC,MAAM,IAAI;AACjB,QAAI,MAAM,WAAW,KAAK,QAAQ;AAChC,cAAQ,OAAO,MAAM,eAAe,OAAO,OAAO;AAAA,CAAK;AACvD,aAAO,OAAO;AAAA,IAChB;AACA,QAAI,MAAM,WAAW,GAAG;AACtB,4BAAsB,KAAK;AAAA,IAC7B;AACA,UAAM,OAAO,MAAM,IAAI,CAAC,MAAM,KAAK,EAAE,OAAO,MAAM,EAAE,eAAe,GAAG,EAAE,KAAK,IAAI;AACjF,sBAAkB;AAAA,MAChB,IAAI;AAAA,MACJ,OAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS;AAAA,EAAqE,IAAI;AAAA,MACpF;AAAA,IACF,CAAC;AACD,YAAQ,KAAK,CAAC;AAAA,EAChB,SAAS,KAAK;AAGZ,QAAI,eAAe,YAAY,mBAAmB,IAAI,MAAM,IAAI,OAAO,GAAG;AACxE,4BAAsB,OAAO,IAAI,OAAO;AAAA,IAC1C;AACA,sBAAkB;AAAA,MAChB,IAAI;AAAA,MACJ,OAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,IACF,CAAC;AACD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/gsc/query.ts","../src/commands/gsc/presets.ts"],"sourcesContent":["import { appendFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { defineCommand } from \"citty\";\nimport { ApiError, apiPost } from \"../../client.ts\";\nimport { handleConnectionError, isNotConnectedError } from \"../../error-handler.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { buildQueryCacheKey, cacheGet, cacheSet, getQueryTtl } from \"../ads/cache.ts\";\nimport { toCsvRow, writeAdsOutput, writeJsonEnvelope } from \"../ads/output.ts\";\nimport { GSC_PRESETS } from \"./presets.ts\";\nimport { resolveSiteUrl } from \"./resolve.ts\";\n\nregisterSchema({\n command: \"gsc.query\",\n description:\n \"Run GSC Search Analytics queries. Use --preset for playbook-aligned queries (primary usage) or --dimensions for free-form queries.\",\n args: {\n \"site-url\": { type: \"string\", description: \"Site URL (auto-resolved if not provided)\", required: false },\n preset: {\n type: \"string\",\n description:\n \"Named preset (cannibalization, missed-revenue, brand-halo, negative-keywords, top-pages, top-queries)\",\n required: false,\n },\n brand: { type: \"string\", description: \"Brand name (required for brand-halo preset)\", required: false },\n dimensions: {\n type: \"string\",\n description: \"Comma-separated dimensions (escape hatch: query, page, country, device, date)\",\n required: false,\n },\n days: { type: \"string\", description: \"Lookback window in days (default: 28)\", required: false },\n \"start-date\": { type: \"string\", description: \"Explicit start date (YYYY-MM-DD)\", required: false },\n \"end-date\": { type: \"string\", description: \"Explicit end date (YYYY-MM-DD)\", required: false },\n \"row-limit\": { type: \"string\", description: \"Max rows (default: 1000, max: 25000)\", required: false },\n type: { type: \"string\", description: \"Search type: web|image|video|news|discover (default: web)\", required: false },\n filter: { type: \"string\", description: \"Dimension filter groups as JSON string\", required: false },\n \"list-presets\": { type: \"boolean\", description: \"List available presets\", required: false },\n out: { type: \"string\", description: \"Write data to file (.csv, .jsonl, .json)\", required: false },\n append: { type: \"boolean\", description: \"Append to existing file\", required: false },\n output: { type: \"string\", description: \"Format: json|csv|jsonl|md\", required: false, default: \"json\" },\n \"no-cache\": { type: \"boolean\", description: \"Skip cache\", required: false },\n },\n});\n\ninterface QueryApiResponse {\n ok: boolean;\n data?: Array<Record<string, unknown>>;\n preset?: string;\n error?: { code: string; message: string };\n}\n\nfunction extractFields(rows: Array<Record<string, unknown>>): string[] {\n const first = rows[0];\n return first ? Object.keys(first) : [];\n}\n\nfunction writeRowsToFile(filePath: string, rows: Array<Record<string, unknown>>, append: boolean): void {\n const fields = extractFields(rows);\n const ext = filePath.split(\".\").pop()?.toLowerCase();\n if (ext === \"csv\") {\n if (!append || !existsSync(filePath)) {\n writeFileSync(filePath, `${toCsvRow(fields)}\\n`, \"utf-8\");\n }\n const csvRows = rows.map((row) => toCsvRow(fields.map((f) => String(row[f] ?? \"\"))));\n appendFileSync(filePath, `${csvRows.join(\"\\n\")}\\n`, \"utf-8\");\n } else if (ext === \"jsonl\") {\n const content = `${rows.map((row) => JSON.stringify(row)).join(\"\\n\")}\\n`;\n if (append && existsSync(filePath)) {\n appendFileSync(filePath, content, \"utf-8\");\n } else {\n writeFileSync(filePath, content, \"utf-8\");\n }\n } else if (append && existsSync(filePath)) {\n const existing = JSON.parse(readFileSync(filePath, \"utf-8\")) as unknown[];\n writeFileSync(filePath, JSON.stringify([...existing, ...rows], null, 2), \"utf-8\");\n } else {\n writeFileSync(filePath, JSON.stringify(rows, null, 2), \"utf-8\");\n }\n}\n\nfunction outputRows(\n rows: Array<Record<string, unknown>>,\n args: Record<string, unknown>,\n response: QueryApiResponse,\n cached: boolean,\n): void {\n if (args.out) {\n const filePath = resolve(args.out as string);\n writeRowsToFile(filePath, rows, !!args.append);\n writeJsonEnvelope({ ok: true, file: filePath, rows: rows.length, ...(cached && { cached: true }) });\n return;\n }\n const format = (args.output as string) || \"json\";\n if (format !== \"json\") {\n writeAdsOutput(rows, format);\n return;\n }\n writeJsonEnvelope({ ...response, ...(cached && { cached: true }) });\n}\n\nfunction buildRequestBody(args: Record<string, unknown>, siteUrl: string, useCache: boolean): Record<string, unknown> {\n const body: Record<string, unknown> = { siteUrl };\n if (args.preset) body.preset = args.preset;\n if (args.brand) body.brand = args.brand;\n if (args.dimensions) body.dimensions = (args.dimensions as string).split(\",\").map((d) => d.trim());\n if (args.days) body.days = Number(args.days);\n if (args[\"start-date\"]) body.startDate = args[\"start-date\"];\n if (args[\"end-date\"]) body.endDate = args[\"end-date\"];\n if (args[\"row-limit\"]) body.rowLimit = Number(args[\"row-limit\"]);\n if (args.type) body.type = args.type;\n if (args.filter) body.filter = args.filter;\n if (!useCache) body.skipCache = true;\n return body;\n}\n\nfunction handleError(err: unknown): never {\n if (err instanceof ApiError) {\n if (isNotConnectedError(err.code, err.message)) {\n handleConnectionError(\"gsc\", err.message);\n }\n writeJsonEnvelope({ ok: false, error: { code: err.code, message: err.message } });\n process.exit(1);\n }\n writeJsonEnvelope({\n ok: false,\n error: { code: \"NETWORK_ERROR\", message: err instanceof Error ? err.message : \"Unexpected error\" },\n });\n process.exit(1);\n}\n\nexport const queryCommand = defineCommand({\n meta: {\n name: \"query\",\n description: `Run GSC Search Analytics queries. Preset-first with free-form escape hatch.\n\nPresets (primary usage):\n baker gsc query --preset cannibalization\n baker gsc query --preset brand-halo --brand \"Acme\" --days 90\n baker gsc query --list-presets\n\nFree-form (escape hatch):\n baker gsc query --dimensions \"query,page\" --days 28\n baker gsc query --dimensions \"query\" --row-limit 25000 --out keywords.csv`,\n },\n args: {\n \"site-url\": { type: \"string\", description: \"Site URL\", required: false },\n preset: { type: \"string\", description: \"Named preset\", required: false },\n brand: { type: \"string\", description: \"Brand name for brand-halo preset\", required: false },\n dimensions: { type: \"string\", description: \"Comma-separated dimensions\", required: false },\n days: { type: \"string\", description: \"Lookback days (default: 28)\", required: false },\n \"start-date\": { type: \"string\", description: \"Start date override\", required: false },\n \"end-date\": { type: \"string\", description: \"End date override\", required: false },\n \"row-limit\": { type: \"string\", description: \"Max rows (default: 1000)\", required: false },\n type: { type: \"string\", description: \"Search type (default: web)\", required: false },\n filter: { type: \"string\", description: \"Filter JSON\", required: false },\n \"list-presets\": { type: \"boolean\", description: \"List presets\", required: false },\n out: { type: \"string\", description: \"Output file path\", required: false },\n append: { type: \"boolean\", description: \"Append to file\", required: false },\n output: { type: \"string\", description: \"Format: json|csv|jsonl|md\", required: false, default: \"json\" },\n \"no-cache\": { type: \"boolean\", description: \"Skip cache\", required: false },\n },\n run: async ({ args }) => {\n if (args[\"list-presets\"]) {\n writeJsonEnvelope({\n ok: true,\n data: GSC_PRESETS.map((p) => ({\n name: p.name,\n description: p.description,\n playbook: p.playbook,\n ...(p.requiresBrand && { requiresBrand: true }),\n })),\n });\n return;\n }\n\n if (!args.preset && !args.dimensions) {\n writeJsonEnvelope({\n ok: false,\n error: {\n code: \"VALIDATION_ERROR\",\n message: \"Provide --preset or --dimensions. Run --list-presets to see options.\",\n },\n });\n process.exit(1);\n }\n\n const siteUrl = await resolveSiteUrl(args);\n const useCache = !args[\"no-cache\"];\n const body = buildRequestBody(args, siteUrl, useCache);\n const cacheKey = buildQueryCacheKey(siteUrl, JSON.stringify(body));\n\n if (useCache) {\n const cached = cacheGet<QueryApiResponse>(\"gsc-queries\", cacheKey);\n if (cached) {\n outputRows(cached.data.data ?? [], args, cached.data, true);\n return;\n }\n }\n\n try {\n const response = await apiPost<QueryApiResponse>(\"/api/gsc/query\", body);\n if (useCache) {\n cacheSet(\"gsc-queries\", cacheKey, response, getQueryTtl(JSON.stringify(body)));\n }\n outputRows(response.data ?? [], args, response, false);\n } catch (err) {\n handleError(err);\n }\n },\n});\n","interface GscPreset {\n name: string;\n description: string;\n playbook: string;\n requiresBrand?: boolean;\n}\n\nexport const GSC_PRESETS: GscPreset[] = [\n {\n name: \"cannibalization\",\n description: \"PPC-SEO arbitrage — find queries ranking #1-2 organically where you also pay for ads\",\n playbook: \"[05] PPC-SEO Arbitrage\",\n },\n {\n name: \"missed-revenue\",\n description: \"High-impression queries with no PPC coverage (position > 10)\",\n playbook: \"[05] Opportunity Finder\",\n },\n {\n name: \"brand-halo\",\n description: \"Brand search volume trends — proves upper-funnel awareness lift\",\n playbook: \"[21] YouTube/DG ROI\",\n requiresBrand: true,\n },\n {\n name: \"negative-keywords\",\n description: \"Discover negative keyword candidates (login, support, cancel queries)\",\n playbook: \"Negative Keyword Discovery\",\n },\n {\n name: \"top-pages\",\n description: \"Top performing pages by clicks\",\n playbook: \"General\",\n },\n {\n name: \"top-queries\",\n description: \"Top search queries by clicks\",\n playbook: \"General\",\n },\n];\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/gsc/sitemaps.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { ApiError, apiGet } from \"../../client.ts\";\nimport { handleConnectionError, isNotConnectedError } from \"../../error-handler.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { cacheGet, cacheSet } from \"../ads/cache.ts\";\nimport { writeAdsOutput, writeJsonEnvelope } from \"../ads/output.ts\";\nimport { resolveSiteUrl } from \"./resolve.ts\";\n\nregisterSchema({\n command: \"gsc.sitemaps\",\n description: \"List sitemaps for a Search Console site. Check sitemap health and errors.\",\n args: {\n \"site-url\": { type: \"string\", description: \"Site URL (auto-resolved if not provided)\", required: false },\n \"no-cache\": { type: \"boolean\", description: \"Skip cache, hit API directly\", required: false },\n },\n});\n\ninterface SitemapInfo {\n path: string;\n lastSubmitted?: string;\n isPending?: boolean;\n isSitemapsIndex?: boolean;\n type?: string;\n lastDownloaded?: string;\n warnings?: string;\n errors?: string;\n}\n\nexport const sitemapsCommand = defineCommand({\n meta: {\n name: \"sitemaps\",\n description: `List sitemaps for a site. Check health and errors.\n\nExamples:\n baker gsc sitemaps\n baker gsc sitemaps --site-url \"https://example.com/\"`,\n },\n args: {\n \"site-url\": { type: \"string\", description: \"Site URL\", required: false },\n \"no-cache\": { type: \"boolean\", description: \"Skip cache\", required: false },\n output: { type: \"string\", description: \"Format: json|csv|md\", required: false, default: \"json\" },\n },\n run: async ({ args }) => {\n const siteUrl = await resolveSiteUrl(args);\n const useCache = !args[\"no-cache\"];\n const cacheKey = `sitemaps:${siteUrl}`;\n\n if (useCache) {\n const cached = cacheGet<SitemapInfo[]>(\"gsc-sitemaps\", cacheKey);\n if (cached) {\n writeJsonEnvelope({ ok: true, data: cached.data, cached: true });\n return;\n }\n }\n\n try {\n const params: Record<string, string> = { \"site-url\": siteUrl };\n if (!useCache) params[\"skip-cache\"] = \"true\";\n const data = await apiGet<SitemapInfo[]>(\"/api/gsc/sitemaps\", params);\n if (useCache) {\n cacheSet(\"gsc-sitemaps\", cacheKey, data, 6 * 60 * 60 * 1000);\n }\n const format = (args.output as string) || \"json\";\n if (format !== \"json\") {\n writeAdsOutput(data as unknown as Array<Record<string, unknown>>, format);\n return;\n }\n writeJsonEnvelope({ ok: true, data });\n } catch (err) {\n if (err instanceof ApiError) {\n if (isNotConnectedError(err.code, err.message)) {\n handleConnectionError(\"gsc\", err.message);\n }\n writeJsonEnvelope({ ok: false, error: { code: err.code, message: err.message } });\n process.exit(1);\n }\n writeJsonEnvelope({ ok: false, error: { code: \"NETWORK_ERROR\", message: \"Unexpected error\" } });\n process.exit(1);\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,qBAAqB;AAQ9B,eAAe;AAAA,EACb,SAAS;AAAA,EACT,aAAa;AAAA,EACb,MAAM;AAAA,IACJ,YAAY,EAAE,MAAM,UAAU,aAAa,4CAA4C,UAAU,MAAM;AAAA,IACvG,YAAY,EAAE,MAAM,WAAW,aAAa,gCAAgC,UAAU,MAAM;AAAA,EAC9F;AACF,CAAC;AAaM,IAAM,kBAAkB,cAAc;AAAA,EAC3C,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,EAKf;AAAA,EACA,MAAM;AAAA,IACJ,YAAY,EAAE,MAAM,UAAU,aAAa,YAAY,UAAU,MAAM;AAAA,IACvE,YAAY,EAAE,MAAM,WAAW,aAAa,cAAc,UAAU,MAAM;AAAA,IAC1E,QAAQ,EAAE,MAAM,UAAU,aAAa,uBAAuB,UAAU,OAAO,SAAS,OAAO;AAAA,EACjG;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,UAAM,UAAU,MAAM,eAAe,IAAI;AACzC,UAAM,WAAW,CAAC,KAAK,UAAU;AACjC,UAAM,WAAW,YAAY,OAAO;AAEpC,QAAI,UAAU;AACZ,YAAM,SAAS,SAAwB,gBAAgB,QAAQ;AAC/D,UAAI,QAAQ;AACV,0BAAkB,EAAE,IAAI,MAAM,MAAM,OAAO,MAAM,QAAQ,KAAK,CAAC;AAC/D;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAiC,EAAE,YAAY,QAAQ;AAC7D,UAAI,CAAC,SAAU,QAAO,YAAY,IAAI;AACtC,YAAM,OAAO,MAAM,OAAsB,qBAAqB,MAAM;AACpE,UAAI,UAAU;AACZ,iBAAS,gBAAgB,UAAU,MAAM,IAAI,KAAK,KAAK,GAAI;AAAA,MAC7D;AACA,YAAM,SAAU,KAAK,UAAqB;AAC1C,UAAI,WAAW,QAAQ;AACrB,uBAAe,MAAmD,MAAM;AACxE;AAAA,MACF;AACA,wBAAkB,EAAE,IAAI,MAAM,KAAK,CAAC;AAAA,IACtC,SAAS,KAAK;AACZ,UAAI,eAAe,UAAU;AAC3B,YAAI,oBAAoB,IAAI,MAAM,IAAI,OAAO,GAAG;AAC9C,gCAAsB,OAAO,IAAI,OAAO;AAAA,QAC1C;AACA,0BAAkB,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,IAAI,MAAM,SAAS,IAAI,QAAQ,EAAE,CAAC;AAChF,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,wBAAkB,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,iBAAiB,SAAS,mBAAmB,EAAE,CAAC;AAC9F,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AACF,CAAC;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/gsc/sites.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport { AVAILABLE_ARG, writeAvailableAccounts } from \"../../available-accounts.ts\";\nimport { ApiError, apiGet } from \"../../client.ts\";\nimport { connectedResourceHints } from \"../../connected-resources.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport { cacheGet, cacheSet } from \"../ads/cache.ts\";\nimport { writeAdsOutput, writeJsonEnvelope } from \"../ads/output.ts\";\n\nregisterSchema({\n command: \"gsc.sites\",\n description:\n \"List the Search Console sites this company connected — there can be several, and every one of them is yours to query. Returns the site URLs the query and sitemaps commands take.\",\n args: {\n \"no-cache\": { type: \"boolean\", description: \"Skip cache, hit API directly\", required: false },\n output: { type: \"string\", description: \"Format: json|csv|md\", required: false, default: \"json\" },\n available: AVAILABLE_ARG,\n },\n});\n\ninterface SiteInfo {\n siteUrl: string;\n permissionLevel: string;\n}\n\nimport { handleConnectionError, needsConnectionFix } from \"../../error-handler.ts\";\n\nfunction siteHints(sites: SiteInfo[]): string[] {\n return connectedResourceHints({\n plural: \"Search Console sites\",\n singular: \"Search Console site\",\n flag: \"--site-url\",\n resources: sites.map((site) => ({ id: site.siteUrl, label: site.permissionLevel })),\n });\n}\n\nfunction handleListError(err: unknown): never {\n if (err instanceof ApiError) {\n if (needsConnectionFix(err.code, err.message)) {\n handleConnectionError(\"gsc\", err.message);\n }\n writeJsonEnvelope({ ok: false, error: { code: err.code, message: err.message } });\n process.exit(1);\n }\n writeJsonEnvelope({ ok: false, error: { code: \"NETWORK_ERROR\", message: \"Unexpected error\" } });\n process.exit(1);\n}\n\nexport const sitesCommand = defineCommand({\n meta: {\n name: \"sites\",\n description: `List verified Search Console sites.\n\nExamples:\n baker gsc sites\n baker gsc sites --available # everything the login reaches, selected or not`,\n },\n args: {\n \"no-cache\": { type: \"boolean\", description: \"Skip cache\", required: false },\n output: { type: \"string\", description: \"Format: json|csv|md\", required: false, default: \"json\" },\n available: AVAILABLE_ARG,\n },\n run: async ({ args }) => {\n if (args.available) return writeAvailableAccounts(\"google-search-console\", handleListError);\n const useCache = !args[\"no-cache\"];\n\n if (useCache) {\n const cached = cacheGet<SiteInfo[]>(\"gsc-sites\", \"list\");\n if (cached) {\n writeJsonEnvelope({ ok: true, data: cached.data, cached: true, hints: siteHints(cached.data) });\n return;\n }\n }\n\n try {\n const params = !useCache ? { \"skip-cache\": \"true\" } : undefined;\n const data = await apiGet<SiteInfo[]>(\"/api/gsc/sites\", params);\n if (useCache) {\n cacheSet(\"gsc-sites\", \"list\", data, 60 * 60 * 1000);\n }\n const format = (args.output as string) || \"json\";\n if (format !== \"json\") {\n writeAdsOutput(data as unknown as Array<Record<string, unknown>>, format);\n return;\n }\n writeJsonEnvelope({ ok: true, data, hints: siteHints(data) });\n } catch (err) {\n handleListError(err);\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,qBAAqB;AAQ9B,eAAe;AAAA,EACb,SAAS;AAAA,EACT,aACE;AAAA,EACF,MAAM;AAAA,IACJ,YAAY,EAAE,MAAM,WAAW,aAAa,gCAAgC,UAAU,MAAM;AAAA,IAC5F,QAAQ,EAAE,MAAM,UAAU,aAAa,uBAAuB,UAAU,OAAO,SAAS,OAAO;AAAA,IAC/F,WAAW;AAAA,EACb;AACF,CAAC;AASD,SAAS,UAAU,OAA6B;AAC9C,SAAO,uBAAuB;AAAA,IAC5B,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,MAAM;AAAA,IACN,WAAW,MAAM,IAAI,CAAC,UAAU,EAAE,IAAI,KAAK,SAAS,OAAO,KAAK,gBAAgB,EAAE;AAAA,EACpF,CAAC;AACH;AAEA,SAAS,gBAAgB,KAAqB;AAC5C,MAAI,eAAe,UAAU;AAC3B,QAAI,mBAAmB,IAAI,MAAM,IAAI,OAAO,GAAG;AAC7C,4BAAsB,OAAO,IAAI,OAAO;AAAA,IAC1C;AACA,sBAAkB,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,IAAI,MAAM,SAAS,IAAI,QAAQ,EAAE,CAAC;AAChF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,oBAAkB,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,iBAAiB,SAAS,mBAAmB,EAAE,CAAC;AAC9F,UAAQ,KAAK,CAAC;AAChB;AAEO,IAAM,eAAe,cAAc;AAAA,EACxC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,EAKf;AAAA,EACA,MAAM;AAAA,IACJ,YAAY,EAAE,MAAM,WAAW,aAAa,cAAc,UAAU,MAAM;AAAA,IAC1E,QAAQ,EAAE,MAAM,UAAU,aAAa,uBAAuB,UAAU,OAAO,SAAS,OAAO;AAAA,IAC/F,WAAW;AAAA,EACb;AAAA,EACA,KAAK,OAAO,EAAE,KAAK,MAAM;AACvB,QAAI,KAAK,UAAW,QAAO,uBAAuB,yBAAyB,eAAe;AAC1F,UAAM,WAAW,CAAC,KAAK,UAAU;AAEjC,QAAI,UAAU;AACZ,YAAM,SAAS,SAAqB,aAAa,MAAM;AACvD,UAAI,QAAQ;AACV,0BAAkB,EAAE,IAAI,MAAM,MAAM,OAAO,MAAM,QAAQ,MAAM,OAAO,UAAU,OAAO,IAAI,EAAE,CAAC;AAC9F;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,CAAC,WAAW,EAAE,cAAc,OAAO,IAAI;AACtD,YAAM,OAAO,MAAM,OAAmB,kBAAkB,MAAM;AAC9D,UAAI,UAAU;AACZ,iBAAS,aAAa,QAAQ,MAAM,KAAK,KAAK,GAAI;AAAA,MACpD;AACA,YAAM,SAAU,KAAK,UAAqB;AAC1C,UAAI,WAAW,QAAQ;AACrB,uBAAe,MAAmD,MAAM;AACxE;AAAA,MACF;AACA,wBAAkB,EAAE,IAAI,MAAM,MAAM,OAAO,UAAU,IAAI,EAAE,CAAC;AAAA,IAC9D,SAAS,KAAK;AACZ,sBAAgB,GAAG;AAAA,IACrB;AAAA,EACF;AACF,CAAC;","names":[]}
|
|
File without changes
|