@gscdump/cli 4.2.3 → 4.3.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.
@@ -1,12 +1,12 @@
1
1
  ---
2
2
  name: gscdump
3
- description: Drive the `gscdump` CLI for Google Search Console and Bing with cloud or local authentication. Sync Google rows to a local Store, export Bing datasets, run SEO Analyzers and Reports, inspect Indexing Evidence, and manage sitemaps. Use when the user mentions gscdump, Search Console data, Bing Webmaster data, or GSC automation.
3
+ description: Drive the `gscdump` CLI for Google Search Console and Bing in Local or Hosted mode. Sync Google rows to a local Store, export Bing datasets, run SEO Analyzers and Reports, inspect Indexing Evidence, and manage sitemaps. Use when the user mentions gscdump, Search Console data, Bing Webmaster data, or GSC automation.
4
4
  ---
5
5
 
6
6
  # gscdump CLI
7
7
 
8
- `gscdump` reads Google Search Console and Bing with hosted or local authentication.
9
- It keeps a local Parquet Store for Google rows. Every command has `--help`.
8
+ `gscdump` reads Google Search Console and Bing in one of 2 access modes: Local or Hosted.
9
+ In Local mode it keeps a local Parquet Store for Google rows. Every command has `--help`.
10
10
  For `query`, `-s` means `--site`, `-d` means `--dimensions`, and `-f` means `--format`.
11
11
  Use `--start` and `--end` for dates. `--site=SITE` also works.
12
12
  Use each option once, with either its short or long spelling.
@@ -18,73 +18,88 @@ Example: `gscdump query --site=SITE --start=DATE --end=DATE -d page -f json`.
18
18
 
19
19
  1. Before reading traffic, run `gscdump auth status --json`. Do this even when the user says authentication works.
20
20
  2. Keep the requested Site, dates, dimensions, and task scope. A request for pages does not need query dimensions.
21
- 3. Before local queries, check coverage with `gscdump store stats --site SITE --json`.
21
+ 3. In Hosted mode, skip steps 3 to 5. `gscdump query` reads the hosted record, and `sync` needs Local mode.
22
+ Before Local queries, check coverage with `gscdump store stats --site SITE --json`.
22
23
  Use `gscdump sync --site SITE --status --json` when you need coverage, gaps, or sync-state details.
23
24
  On a fresh Store, `store stats` exits 1 and says it has no data. Continue with the bounded sync.
24
25
  4. Read the table dimensions and watermarks. Sync only missing tables and the requested dates, once per task.
25
26
  5. Use `sync --json`. Read its completion result before deciding what to do next. Never repeat a successful sync.
26
- 6. If the user asks for saved rows, check `meta.source: "local"` in the query result. A successful query can answer live when its table has no synced data.
27
+ 6. If the user asks for saved rows, check `meta.source` in the query result: `local` (the Store) or `hosted` (the hosted record). In Local mode, a successful query can answer `live` when its table has no synced data.
27
28
 
28
29
  If the task only asks about deletion, explain the scope and ask for consent.
29
30
  You may read Store metadata with `store stats` and `sync --status`.
30
31
  Do not query traffic, sync rows, or delete data to explain deletion.
31
32
  Call the local data directory the Store in your answer.
32
33
 
33
- ## Authentication mode
34
+ ## Access mode
34
35
 
35
- Check `gscdump auth status --json` before queries. Reuse the user's selected mode.
36
- In local mode, `googleAuthenticated: true` means Google accepted the credentials. When it is false, `googleError` says why.
37
- In cloud mode, `hostedSync` lists each gscdump.com Site with `syncStatus` and `syncProgress`. `gscdump sites` shows the same progress. The CLI does not read the hosted Store: cloud mode queries go to the live API through gscdump.com.
36
+ gscdump has 2 access modes. Check `gscdump auth status --json` before queries. Reuse the user's selected mode.
38
37
 
39
- | Mode | Credentials | Query path |
38
+ | Mode | Credentials | What it reads |
40
39
  | --- | --- | --- |
41
- | `cloud` | Browser-approved CLI session; optional user API key for automation | `https://gscdump.com/api` uses saved Search Engine connections |
42
- | `local` | Google OAuth/service account or Bing API key/OAuth | Calls the Search Engine directly |
40
+ | `local` | The user's own Google credentials: a service account (recommended) or an OAuth client. Bing API key or OAuth | Calls Google and Bing directly. Keeps a local Store |
41
+ | `hosted` | A browser-approved gscdump.com CLI session, or a gscdump user API key (`GSCDUMP_API_KEY`) | Reads the hosted record on gscdump.com. Never calls Google |
43
42
 
44
- `--mode cloud|local` overrides one invocation. `GSCDUMP_AUTH_MODE` also overrides the saved mode.
43
+ In Local mode, `googleAuthenticated: true` means Google accepted the credentials. When it is false, `googleError` says why.
44
+ In Hosted mode, `hostedSync` lists each hosted Site with `syncStatus` and `syncProgress`, and `commands` lists what Hosted mode can run.
45
+ `gscdump sites` shows the same Sites and progress.
46
+
47
+ `--mode local|hosted` overrides one invocation. `GSCDUMP_AUTH_MODE` also overrides the saved mode.
45
48
  A successful login saves the mode per profile.
46
- If no mode is saved, `GSCDUMP_API_KEY` selects cloud mode.
47
- With neither source, the CLI defaults to local mode.
49
+ If no mode is saved, `GSCDUMP_API_KEY` selects Hosted mode.
50
+ With neither source, the CLI uses Local mode.
48
51
  When a saved mode exists, it remains selected unless an explicit override applies.
49
52
  Never switch modes to bypass an authentication failure.
50
53
  `GSCDUMP_API_ROOT` defaults to `https://gscdump.com/api`. Browser login uses this root. Supply an API key explicitly for a custom root.
51
54
 
52
55
  ```sh
53
- # Open gscdump.com in a browser and approve the CLI session.
54
- gscdump auth login --mode cloud
55
- gscdump bing sites --json
56
- gscdump bing login --site s_SITE_ID
57
- gscdump bing dump --site s_SITE_ID --out ./bing-export --format json
56
+ # Local mode, recommended: a service account never expires.
57
+ gscdump auth login --mode local --service-account ./key.json
58
58
 
59
- # Local Google login uses gscdump.com for OAuth by default.
60
- # Google data requests go directly from the CLI to Google.
59
+ # Local mode with your own OAuth client.
60
+ export GSC_CLIENT_ID=your-client-id GSC_CLIENT_SECRET=your-client-secret
61
61
  gscdump auth login --mode local
62
- gscdump bing login --mode local
63
- gscdump bing dump --site https://example.com/ --out ./bing-export
62
+
63
+ # Hosted mode: open gscdump.com in a browser and approve the CLI session.
64
+ gscdump auth login --mode hosted
65
+ gscdump sites --json
66
+ gscdump query --site example.com -d page -f json
64
67
  ```
65
68
 
66
- For a fully local Google login, set `GSC_CLIENT_ID` and `GSC_CLIENT_SECRET` before `auth login --mode local`.
67
- The CLI then opens Google directly. A service account can use `--service-account` instead.
69
+ Hosted mode can run only these commands: `sites`, `query`, `sitemaps current`, `sitemaps history`, `sitemaps membership`,
70
+ `sitemaps lastmod`, `sitemaps export`, `indexing urls`, and the `bing` commands `login --site`, `sites`, `status`, `dump`, `inspect`, and `verify`.
71
+ Every other command calls Google, so it needs Local mode: `sync`, `inspect`, `query --live`, `analyze --live`, `report --live`,
72
+ `sites add|get|delete|verify*`, `sitemaps list|get|submit|delete`, `indexing submit|remove|status|batch`, `entities`, and `mcp`.
73
+ In Hosted mode these commands stop with this error: `This command calls Google, so it needs Local mode.`
74
+ Tell the user. Do not switch modes for them.
75
+ For an MCP client in Hosted mode, use the gscdump.com MCP server at `https://gscdump.com/mcp`.
68
76
 
69
77
  Hosted Bing login opens the existing connection flow on gscdump.com.
70
78
  Local Bing login uses `BING_API_KEY` or a password prompt.
71
79
  Local `--oauth` uses `BING_CLIENT_ID`, `BING_CLIENT_SECRET`, and a registered loopback callback.
72
80
  The default callback is `http://127.0.0.1:53683/oauth/bing`. `BING_ACCESS_TOKEN` accepts an existing OAuth access token.
73
- After cloud Bing login opens a browser, use `bing status --site s_SITE_ID` to confirm the connection.
81
+ After Hosted Bing login opens a browser, use `bing status --site s_SITE_ID` to confirm the connection.
82
+
83
+ ```sh
84
+ gscdump bing sites --json
85
+ gscdump bing login --site s_SITE_ID
86
+ gscdump bing dump --site s_SITE_ID --out ./bing-export --format json
87
+ gscdump bing login --mode local
88
+ gscdump bing dump --site https://example.com/ --out ./bing-export
89
+ ```
74
90
 
75
- `auth logout` revokes a saved cloud CLI session and removes saved mode and Google and Bing credentials.
91
+ `auth logout` revokes a saved Hosted CLI session and removes saved mode and Google and Bing credentials.
76
92
  `bing logout --mode local` removes only saved Bing credentials. Environment credentials remain active until unset.
77
93
 
78
- Hosted Bing commands use the API's plan and preview access rules.
94
+ Hosted Bing commands use the API's access rules.
79
95
  Hosted connection verification uses `bing verify --site s_SITE_ID`.
80
- Google Indexing API and Site Verification commands require local mode.
81
- Hosted sitemap reads and `indexing urls` require hosted credentials. Their `--site` takes a Site URL, such as `example.com`.
96
+ Hosted sitemap reads and `indexing urls` need Hosted mode. Their `--site` takes a Site URL, such as `example.com`.
82
97
 
83
98
  ## Data boundaries
84
99
 
85
- - `sync`, `query --live`, `analyze --live`, `report --live`, `sites`,
86
- `sitemaps`, and `inspect` use the selected authentication mode.
87
- - Google Indexing API requests require local credentials. `indexing quota` only prints documented limits and needs no authentication.
100
+ - `sync`, `query --live`, `analyze --live`, `report --live`, `inspect`, and Google sitemap and Site changes call Google. They need Local mode.
101
+ - In Hosted mode, `sites` and `query` read the hosted record. They never call Google.
102
+ - Google Indexing API requests need Local mode. `indexing quota` only prints documented limits and needs no authentication.
88
103
  - `dump` and `store` read the local Store only.
89
104
  - `query`, `analyze`, and `report` pick a source for each run. See [Routing](#routing).
90
105
  - Google returns a 2 to 3 day data delay. Default windows end three days ago.
@@ -95,7 +110,9 @@ Hosted sitemap reads and `indexing urls` require hosted credentials. Their `--si
95
110
 
96
111
  ## Routing
97
112
 
98
- Login is optional. A user logs in (Google or hosted) or syncs a local Store.
113
+ This section covers Local mode. In Hosted mode, `query` always reads the hosted record, and JSON has `meta.source: "hosted"`.
114
+ `analyze` and `report` read the Store only in Hosted mode. When the Store cannot answer, they stop with the Local mode command.
115
+
99
116
  `query`, `analyze`, and `report` choose one source for each run. One run never
100
117
  mixes Store rows and live rows.
101
118
 
@@ -107,9 +124,9 @@ mixes Store rows and live rows.
107
124
  | Some dates missing | yes | Stops with the exact `gscdump sync` command, or pass `--live` |
108
125
  | Some dates missing, a sync is running | yes | Stops with `Sync running: 41 of 90 days done.` Run again later, or pass `--live` |
109
126
 
110
- - `--live` always asks Search Console. It needs Google auth.
127
+ - `--live` always asks Search Console. It needs Local mode with Google credentials.
111
128
  - `query --sql` reads the Store only. It stops when no table it names has data.
112
- - JSON output carries `meta.source`: `local` or `live`.
129
+ - JSON output carries `meta.source`: `local`, `live`, or `hosted`.
113
130
  - A stop with `--format json` or `--json` prints `{ "error": { "code", "message", "nextCommand" } }` on stdout and exits 1.
114
131
  Codes: `NOT_CONNECTED`, `STORE_RANGE_NOT_COVERED` (with `missingDates`), `SYNC_RUNNING` (with `sync.done` and `sync.total`), `NO_SYNCED_DATA`, `STORE_ONLY`, `LIVE_ONLY`.
115
132
  Partial coverage and a running sync are normal progress. Run `nextCommand`, or tell the user to.
@@ -138,7 +155,7 @@ After upgrading the CLI, run this command again to update the installed skill.
138
155
  The command prints where it wrote the skill. Clients without a skill
139
156
  directory can read `gscdump --help` and `gscdump <command> --help` instead.
140
157
 
141
- ## Local Google authentication
158
+ ## Local mode setup
142
159
 
143
160
  Check first. Never run `init` when credentials already work.
144
161
 
@@ -147,26 +164,24 @@ gscdump auth status
147
164
  gscdump doctor --json
148
165
  ```
149
166
 
150
- If local Google credentials are missing, use one of these paths:
167
+ If Google credentials are missing, the CLI prints both setup paths. Use one of these:
151
168
 
152
169
  | Path | When | Command |
153
170
  | --- | --- | --- |
154
- | Environment token | The user already has an OAuth access token | `export GSC_ACCESS_TOKEN=ya29...` |
155
- | Refresh token | CI or a headless machine with OAuth client credentials | `export GSC_CLIENT_ID=... GSC_CLIENT_SECRET=... GSC_REFRESH_TOKEN=...` |
156
- | Service account | CI with a service-account key that has Site access | `export GOOGLE_APPLICATION_CREDENTIALS=/abs/path/key.json` |
157
- | Interactive OAuth | A person is present | `gscdump init --mode local` |
158
-
159
- Default local login opens gscdump.com for free Google login and token refresh.
160
- Data queries call Google directly. No Google Cloud project or hosted activation is required.
161
- For a fully local connection, set `GSC_CLIENT_ID` and `GSC_CLIENT_SECRET` before login.
162
- The CLI then opens Google directly and uses a loopback callback.
171
+ | Service account (recommended) | Any machine. The key never expires | `gscdump auth login --mode local --service-account ./key.json`, or `export GOOGLE_APPLICATION_CREDENTIALS=/abs/path/key.json` |
172
+ | OAuth client | A person is present and has a Google Cloud OAuth client | `export GSC_CLIENT_ID=... GSC_CLIENT_SECRET=...`, then `gscdump auth login --mode local` |
173
+ | Refresh token | CI with OAuth client credentials | `export GSC_CLIENT_ID=... GSC_CLIENT_SECRET=... GSC_REFRESH_TOKEN=...` |
174
+ | Access token | The user already has an OAuth access token | `export GSC_ACCESS_TOKEN=ya29...` |
175
+ | Hosted mode | The user has a gscdump.com account and wants the hosted record | `gscdump auth login --mode hosted` |
176
+
177
+ A service account needs Search Console access. Add its email as a user of the Site in Search Console, under Settings > Users and permissions.
178
+ An OAuth client in the Google "Testing" publishing status gets refresh tokens that expire after 7 days.
179
+ To avoid this, set the OAuth consent screen to "In production". A service account has no such limit.
180
+ Local mode never uses gscdump.com for Google login or token refresh.
163
181
  Use `gscdump auth login --mode local --no-browser` when a browser runs on another host.
164
- The default grant is read-only Search Console access.
165
- For Google write operations, use your own OAuth client with the required scopes.
166
- Set `GSC_CLIENT_ID` and `GSC_CLIENT_SECRET` to use a Desktop app OAuth client.
167
- Cloud mode requires hosted access. Pro is free during beta, then paid after launch.
182
+ A service account or an OAuth client with the required scopes also enables Google write operations.
168
183
 
169
- `--profile <name>` or `GSCDUMP_PROFILE` isolates the selected mode and Google, Bing, and cloud credentials.
184
+ `--profile <name>` or `GSCDUMP_PROFILE` isolates the selected mode and its Google, Bing, and Hosted credentials.
170
185
 
171
186
  ## Site identifiers
172
187
 
@@ -183,7 +198,7 @@ Do not add `sc-domain:`.
183
198
  - Without `--site` and `defaultSite`, a command in a terminal shows a picker.
184
199
  Without a terminal, the command fails with `Pass --site. Sites: ...`, unless only one Site is available.
185
200
 
186
- For cloud Bing commands, use a Site ID from `gscdump bing sites`, such as `s_SITE_ID`.
201
+ For Hosted Bing commands, use a Site ID from `gscdump bing sites`, such as `s_SITE_ID`.
187
202
  For local Bing commands, use the full verified Site URL from `gscdump bing sites --mode local`.
188
203
  Bing commands require their own explicit `--site`; the Google `defaultSite` setting does not select a Bing Site.
189
204
 
@@ -208,14 +223,14 @@ Do not rewrite rows, estimate metrics, or add manually calculated totals.
208
223
 
209
224
  | Command | Use it for |
210
225
  | --- | --- |
211
- | `gscdump sites` | List Google Sites and permission levels |
226
+ | `gscdump sites` | Local mode: list Google Sites and permission levels. Hosted mode: list hosted Sites and sync state |
212
227
  | `gscdump bing login`, `status`, `logout` | Manage Bing authentication and check connections |
213
228
  | `gscdump bing sites` | List Bing Sites and connection details |
214
229
  | `gscdump bing dump` | Export Bing traffic, pages, keywords, and crawl data |
215
230
  | `gscdump bing inspect` | Read Bing Indexing Evidence for one URL |
216
- | `gscdump bing verify` | Check and activate a cloud Bing connection |
231
+ | `gscdump bing verify` | Check and activate a Hosted Bing connection |
217
232
  | `gscdump sync` | Copy Search Console rows into the local Store |
218
- | `gscdump query` | Rows by page, query, date, country, or device |
233
+ | `gscdump query` | Rows by page, query, date, country, or device, from the Store or the hosted record |
219
234
  | `gscdump analyze <id>` | One Analyzer over the Store or live rows |
220
235
  | `gscdump report <id>` | A Report that composes several Analyzers |
221
236
  | `gscdump inspect <url...>` | URL Inspection with Indexing Evidence, saved to the Store |
@@ -228,8 +243,8 @@ Do not rewrite rows, estimate metrics, or add manually calculated totals.
228
243
  | `gscdump profile` | Separate credential and config directories |
229
244
  | `gscdump auth` | `status`, `login`, `logout`, `refresh` |
230
245
  | `gscdump doctor` | Health checks for auth, scopes, Store, and reachability |
231
- | `gscdump init` | First-time setup. Without a terminal it never prompts: it uses BYOK env credentials or fails with the auth command |
232
- | `gscdump mcp` | Start Google MCP tools with the selected authentication |
246
+ | `gscdump init` | First-time setup. Without a terminal it never prompts: it uses a service account or environment credentials, or fails with both setup paths |
247
+ | `gscdump mcp` | Start Google MCP tools in Local mode. Hosted mode uses `https://gscdump.com/mcp` |
233
248
  | `gscdump skill install` | Copy this skill into an agent skill directory |
234
249
  | `gscdump papercut` | Report a CLI problem to gscdump.com |
235
250
 
@@ -294,7 +309,7 @@ gscdump query --site example.com --dimensions page,query \
294
309
  contains, `re:` regex, `!re:` not regex, `!` not equals.
295
310
  - `--page` takes a path or a full URL. The Store compares paths.
296
311
  - Without dates, `query` reads the 28 days ending on the newest synced day.
297
- - `--live` bypasses the Store. `--type` selects a search type. The default is `web`.
312
+ - `--live` bypasses the Store and needs Local mode. `--type` selects a search type. The default is `web`.
298
313
  `--data-state` and `--aggregation-type` apply to live mode only.
299
314
  - Metrics already include clicks, impressions, CTR, and position. There is no `--metrics` option.
300
315
  - If Store coverage is missing, read the JSON error and run its `nextCommand`. It syncs only the missing dates and tables.
@@ -460,8 +475,8 @@ Do not treat Bing crawl evidence as proof that a URL is indexed.
460
475
  ## Before the next command
461
476
 
462
477
  For a traffic task, run `gscdump auth status --json` now, before any `query` command.
463
- The user saying credentials work does not replace this check. It identifies the selected authentication mode.
464
- Then check Store metadata, keep the requested dimensions, and read or sync only the requested dates.
478
+ The user saying credentials work does not replace this check. It identifies the selected access mode.
479
+ In Local mode, check Store metadata next, keep the requested dimensions, and read or sync only the requested dates.
465
480
  If the user requests JSON, return the command's JSON unchanged, without a table or a separate totals summary.
466
481
  Include that JSON in your final response. Tool output alone is not a final answer.
467
482
  Include every returned row. Do not refer the user to results "above".
@@ -1,99 +0,0 @@
1
- import { HOSTED_KEY_REJECTED } from "./error-handler.mjs";
2
- import { HOSTED_SESSION_REJECTED, cloudRequest } from "./auth-state.mjs";
3
- import { googleSearchConsole } from "gscdump/client";
4
- import { ofetch } from "ofetch";
5
- function createCloudGoogleClient(state, fetchOptions) {
6
- const request = async (input, init) => {
7
- const url = new URL(String(input));
8
- if (url.origin !== "https://searchconsole.googleapis.com") throw new Error("Google indexing and Site Verification require local authentication. Use --mode local.");
9
- const method = init?.method ?? "GET";
10
- const signal = init?.signal;
11
- const body = typeof init?.body === "string" ? JSON.parse(init.body) : {};
12
- const post = (route, data) => cloudRequest(state, `/cli/gsc/${route}`, {
13
- method: "POST",
14
- body: JSON.stringify(data),
15
- signal
16
- });
17
- let result;
18
- if (url.pathname === "/webmasters/v3/sites" && method === "GET") result = { siteEntry: await cloudRequest(state, "/cli/gsc/sites", { signal }) };
19
- else if (url.pathname === "/v1/urlInspection/index:inspect" && method === "POST") result = await post("inspect", {
20
- siteUrl: body.siteUrl,
21
- urls: [body.inspectionUrl],
22
- languageCode: body.languageCode,
23
- raw: true
24
- });
25
- else {
26
- const match = url.pathname.match(/^\/webmasters\/v3\/sites\/([^/]+)(?:\/(searchAnalytics\/query|sitemaps)(?:\/([^/]+))?)?$/);
27
- if (!match) throw new Error("This Google operation requires local authentication. Use --mode local.");
28
- const siteUrl = decodeURIComponent(match[1]);
29
- if (match[2] === "searchAnalytics/query" && method === "POST") {
30
- const { type, ...query } = body;
31
- result = await post("query", {
32
- ...query,
33
- siteUrl,
34
- searchType: type,
35
- raw: true
36
- });
37
- } else if (match[2] === "sitemaps") {
38
- if (match[3]) {
39
- const action = method === "GET" ? "get" : method === "PUT" ? "submit" : method === "DELETE" ? "delete" : null;
40
- if (!action) throw new Error("This sitemap operation requires local authentication. Use --mode local.");
41
- const response = await post("sitemaps", {
42
- siteUrl,
43
- sitemapUrl: decodeURIComponent(match[3]),
44
- action
45
- });
46
- result = action === "get" ? response : void 0;
47
- } else if (method === "GET") {
48
- const query = new URLSearchParams({
49
- siteUrl,
50
- raw: "true"
51
- });
52
- const sitemapIndex = url.searchParams.get("sitemapIndex");
53
- if (sitemapIndex) query.set("sitemapIndex", sitemapIndex);
54
- result = { sitemap: (await cloudRequest(state, `/cli/gsc/sitemaps?${query}`, { signal })).sitemaps };
55
- } else throw new Error("This sitemap operation requires local authentication. Use --mode local.");
56
- } else if (!match[2]) {
57
- const action = method === "GET" ? "get" : method === "PUT" ? "add" : method === "DELETE" ? "remove" : null;
58
- if (!action) throw new Error("This Site operation requires local authentication. Use --mode local.");
59
- const response = await post("sites", {
60
- siteUrl,
61
- action
62
- });
63
- result = action === "get" ? response : void 0;
64
- } else throw new Error("This Google operation requires local authentication. Use --mode local.");
65
- }
66
- return result === void 0 ? new Response(null, { status: 204 }) : Response.json(result);
67
- };
68
- const fetchHosted = (input, init) => request(input, init).catch((error) => {
69
- if (error && typeof error === "object" && "response" in error && error.response instanceof Response) {
70
- if (error.response.status === 401) return Response.json({ error: {
71
- code: 401,
72
- message: "sessionId" in state ? HOSTED_SESSION_REJECTED : HOSTED_KEY_REJECTED
73
- } }, { status: 401 });
74
- return error.response;
75
- }
76
- throw error;
77
- });
78
- return googleSearchConsole("", { fetch: ofetch.create({
79
- ...fetchOptions,
80
- retry: fetchOptions?.retry ?? 3,
81
- timeout: fetchOptions?.timeout ?? 3e4,
82
- async onRequest(context) {
83
- if (new URL(String(context.request)).origin !== "https://searchconsole.googleapis.com") throw new Error("Google indexing and Site Verification require local authentication. Use --mode local.");
84
- const hooks = fetchOptions?.onRequest;
85
- for (const hook of hooks ? Array.isArray(hooks) ? hooks : [hooks] : []) await hook(context);
86
- },
87
- retryDelay: fetchOptions?.retryDelay ?? (({ response }) => {
88
- const header = response?.headers.get("retry-after");
89
- if (header) {
90
- const seconds = Number(header);
91
- if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
92
- const date = Date.parse(header);
93
- if (Number.isFinite(date)) return Math.max(0, date - Date.now());
94
- }
95
- return 1e3;
96
- })
97
- }, { fetch: fetchHosted }) });
98
- }
99
- export { createCloudGoogleClient };