gscdump 0.26.10 → 0.27.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.
@@ -0,0 +1,725 @@
1
+ import { $Fetch, FetchOptions } from "ofetch";
2
+ import { indexing_v3 } from "@googleapis/indexing/build/v3";
3
+ import { searchconsole_v1 } from "@googleapis/searchconsole/build/v1";
4
+ type GscSearchAnalyticsDimension = 'page' | 'query' | 'country' | 'device' | 'date' | 'hour' | 'searchAppearance';
5
+ type GscDataState = 'final' | 'all' | 'hourly_all';
6
+ interface GscSearchAnalyticsMetadata {
7
+ /** First date (YYYY-MM-DD, PT) still being collected. Populated when dataState=`all` and grouped by `date`. */
8
+ first_incomplete_date?: string;
9
+ /** First hour (YYYY-MM-DDThh:mm:ss±hh:mm, PT) still being collected. Populated when dataState=`hourly_all` and grouped by `hour`. */
10
+ first_incomplete_hour?: string;
11
+ }
12
+ type GscSearchAnalyticsFilterOperator = 'equals' | 'notEquals' | 'contains' | 'notContains' | 'includingRegex' | 'excludingRegex';
13
+ interface GscSearchAnalyticsFilter {
14
+ dimension: GscSearchAnalyticsDimension;
15
+ expression: string;
16
+ operator?: GscSearchAnalyticsFilterOperator;
17
+ }
18
+ interface GscSearchAnalyticsFilterGroup {
19
+ groupType?: 'and' | 'or';
20
+ filters: GscSearchAnalyticsFilter[];
21
+ }
22
+ type GscSearchType = 'web' | 'image' | 'video' | 'news' | 'discover' | 'googleNews';
23
+ type GscAggregationType = 'auto' | 'byPage' | 'byProperty' | 'byNewsShowcasePanel';
24
+ type GscResponseAggregationType = 'auto' | 'byPage' | 'byProperty' | 'byNewsShowcasePanel';
25
+ interface GscSearchAnalyticsRequest {
26
+ startDate: string;
27
+ endDate: string;
28
+ dimensions?: GscSearchAnalyticsDimension[];
29
+ dimensionFilterGroups?: GscSearchAnalyticsFilterGroup[];
30
+ rowLimit?: number;
31
+ startRow?: number;
32
+ /** GSC search corpus. Maps to wire field `type` (the API still accepts the deprecated `searchType` alias). */
33
+ type?: GscSearchType;
34
+ dataState?: GscDataState;
35
+ aggregationType?: GscAggregationType;
36
+ }
37
+ declare const _default: {
38
+ name: string;
39
+ 'alpha-2': string;
40
+ 'alpha-3': string;
41
+ 'country-code': string;
42
+ }[];
43
+ declare const Devices: {
44
+ readonly MOBILE: "MOBILE";
45
+ readonly DESKTOP: "DESKTOP";
46
+ readonly TABLET: "TABLET";
47
+ };
48
+ type Device = typeof Devices[keyof typeof Devices];
49
+ declare const SearchTypes: {
50
+ readonly WEB: "web";
51
+ readonly IMAGE: "image";
52
+ readonly VIDEO: "video";
53
+ readonly NEWS: "news";
54
+ readonly DISCOVER: "discover";
55
+ readonly GOOGLE_NEWS: "googleNews";
56
+ };
57
+ type SearchType = typeof SearchTypes[keyof typeof SearchTypes];
58
+ declare const Countries: { [K in (typeof _default)[number]["alpha-3"]]: Lowercase<K> };
59
+ type Country = typeof Countries[keyof typeof Countries];
60
+ interface DimensionValueMap {
61
+ query: string;
62
+ queryCanonical: string;
63
+ page: string;
64
+ country: Country;
65
+ device: Device;
66
+ searchAppearance: string;
67
+ date: string;
68
+ /** Hour bucket — ISO-8601 with PT offset, e.g. `2025-07-14T13:00:00-07:00`. Use with `dataState: 'hourly_all'`. */
69
+ hour: string;
70
+ }
71
+ type Dimension = keyof DimensionValueMap;
72
+ interface QueryParamValueMap {
73
+ searchType: SearchType;
74
+ }
75
+ type QueryParamName = keyof QueryParamValueMap;
76
+ interface Column<D extends Dimension> {
77
+ readonly __columnBrand: 'gscdump.Column';
78
+ readonly dimension: D;
79
+ }
80
+ type FilterOperator = 'equals' | 'notEquals' | 'contains' | 'notContains' | 'includingRegex' | 'excludingRegex';
81
+ type DateOperator = 'gte' | 'gt' | 'lte' | 'lt' | 'between';
82
+ type MetricOperator = 'metricGte' | 'metricGt' | 'metricLte' | 'metricLt' | 'metricBetween';
83
+ type SpecialOperator = 'topLevel';
84
+ interface InternalFilter {
85
+ dimension: Dimension | QueryParamName | Metric;
86
+ operator: FilterOperator | DateOperator | MetricOperator | SpecialOperator;
87
+ expression: string;
88
+ expression2?: string;
89
+ }
90
+ interface Filter<C = object> {
91
+ readonly __filterBrand: 'gscdump.Filter';
92
+ readonly _constraints: C;
93
+ readonly _filters: InternalFilter[];
94
+ readonly _nestedGroups?: Filter<any>[];
95
+ readonly _groupType?: 'and' | 'or';
96
+ }
97
+ type GSCRow<D extends Dimension[], C> = { [K in D[number]]: K extends keyof C ? C[K] : DimensionValueMap[K] } & {
98
+ clicks: number;
99
+ impressions: number;
100
+ ctr: number;
101
+ position: number;
102
+ };
103
+ type Metric = 'clicks' | 'impressions' | 'ctr' | 'position';
104
+ interface MetricColumn<M extends Metric> {
105
+ readonly __metricColumnBrand: 'gscdump.MetricColumn';
106
+ readonly metric: M;
107
+ }
108
+ interface BuilderState {
109
+ dimensions: Dimension[];
110
+ metrics?: Metric[];
111
+ filter?: Filter<any>;
112
+ prefilter?: Filter<any>;
113
+ orderBy?: {
114
+ column: Metric | 'date';
115
+ dir: 'asc' | 'desc';
116
+ };
117
+ rowLimit?: number;
118
+ startRow?: number;
119
+ /** GSC `dataState`. `'hourly_all'` is required when grouping by `hour`. */
120
+ dataState?: GscDataState;
121
+ /** GSC `aggregationType`. `'byNewsShowcasePanel'` requires `type=discover|googleNews` with NEWS_SHOWCASE searchAppearance. */
122
+ aggregationType?: GscAggregationType;
123
+ /** GSC search corpus. Wins over any `searchType` filter when both are set. */
124
+ searchType?: SearchType;
125
+ }
126
+ type SelectableColumn = Column<Dimension> | MetricColumn<Metric>;
127
+ type OrderableColumn = MetricColumn<Metric> | Column<'date'>;
128
+ type ExtractDimensions<T extends SelectableColumn[]> = { [K in keyof T]: T[K] extends Column<infer D> ? D : never }[number] extends infer U ? Exclude<U, never>[] : never;
129
+ interface GSCQueryBuilder<D extends Dimension[] = [], C = object> {
130
+ select: {
131
+ <T extends Dimension[]>(...dims: T): GSCQueryBuilder<T, C>;
132
+ <T extends SelectableColumn[]>(...cols: T): GSCQueryBuilder<ExtractDimensions<T> & Dimension[], C>;
133
+ };
134
+ where: <F extends Filter<any>>(filter: F) => GSCQueryBuilder<D, C & F['_constraints']>;
135
+ prefilter: <F extends Filter<any>>(filter: F) => GSCQueryBuilder<D, C>;
136
+ orderBy: (col: OrderableColumn, dir: 'asc' | 'desc') => GSCQueryBuilder<D, C>;
137
+ limit: (n: number) => GSCQueryBuilder<D, C>;
138
+ offset: (n: number) => GSCQueryBuilder<D, C>;
139
+ dataState: (state: GscDataState) => GSCQueryBuilder<D, C>;
140
+ aggregationType: (type: GscAggregationType) => GSCQueryBuilder<D, C>;
141
+ /** GSC search corpus (`type` on the wire). Equivalent to filtering by `searchType`. */
142
+ type: (t: GscSearchType) => GSCQueryBuilder<D, C>;
143
+ toBody: () => GscSearchAnalyticsRequest;
144
+ getState: () => BuilderState;
145
+ }
146
+ type ApiSite = searchconsole_v1.Schema$WmxSite;
147
+ type ApiSitemap = searchconsole_v1.Schema$WmxSitemap;
148
+ type ApiSitemapContent = searchconsole_v1.Schema$WmxSitemapContent;
149
+ type SearchAnalyticsQuery = searchconsole_v1.Schema$SearchAnalyticsQueryRequest;
150
+ type SearchAnalyticsResponse = searchconsole_v1.Schema$SearchAnalyticsQueryResponse;
151
+ type DataRow = searchconsole_v1.Schema$ApiDataRow;
152
+ type DimensionFilter = searchconsole_v1.Schema$ApiDimensionFilter;
153
+ type DimensionFilterGroup = searchconsole_v1.Schema$ApiDimensionFilterGroup;
154
+ type UrlInspectionResult = searchconsole_v1.Schema$UrlInspectionResult;
155
+ type IndexStatusResult = searchconsole_v1.Schema$IndexStatusInspectionResult;
156
+ type MobileUsabilityResult = searchconsole_v1.Schema$MobileUsabilityInspectionResult;
157
+ type RichResultsResult = searchconsole_v1.Schema$RichResultsInspectionResult;
158
+ type InspectUrlIndexResponse = searchconsole_v1.Schema$InspectUrlIndexResponse;
159
+ type UrlNotificationMetadata = indexing_v3.Schema$UrlNotificationMetadata;
160
+ type PublishUrlNotificationResponse = indexing_v3.Schema$PublishUrlNotificationResponse;
161
+ type RequiredNonNullable<T> = Required<Exclude<T, null | undefined>>;
162
+ interface Site extends Required<Omit<ApiSite, 'siteUrl'>> {
163
+ siteUrl: string;
164
+ }
165
+ interface Period {
166
+ start: Date | string;
167
+ end: Date | string;
168
+ }
169
+ interface ResolvedAnalyticsRange {
170
+ period: Period;
171
+ prevPeriod?: Period;
172
+ }
173
+ interface SiteAnalytics {
174
+ analytics: {
175
+ period: {
176
+ totalClicks: number;
177
+ totalImpressions: number;
178
+ };
179
+ prevPeriod: {
180
+ totalClicks: number;
181
+ totalImpressions: number;
182
+ };
183
+ };
184
+ sitemaps: ApiSitemap[];
185
+ indexedUrls: string[];
186
+ period: {
187
+ url: string;
188
+ clicks: number;
189
+ clicksPercent: number;
190
+ prevClicks: number;
191
+ impressions: number;
192
+ impressionsPercent: number;
193
+ prevImpressions: number;
194
+ }[];
195
+ keywords: {
196
+ keyword: string;
197
+ position: number;
198
+ prevPosition: number;
199
+ positionPercent: number;
200
+ ctr: number;
201
+ ctrPercent: number;
202
+ prevCtr: number;
203
+ clicks: number;
204
+ }[];
205
+ graph: {
206
+ keys?: undefined;
207
+ time: string;
208
+ clicks: number;
209
+ impressions: number;
210
+ }[];
211
+ }
212
+ type VerificationMethod = 'META' | 'FILE' | 'DNS_TXT' | 'DNS_CNAME' | 'ANALYTICS' | 'TAG_MANAGER';
213
+ type VerificationSiteType = 'SITE' | 'INET_DOMAIN' | 'ANDROID_APP';
214
+ interface VerificationSite {
215
+ type: VerificationSiteType;
216
+ identifier: string;
217
+ }
218
+ interface VerificationToken {
219
+ method: string;
220
+ token: string;
221
+ }
222
+ interface VerificationWebResource {
223
+ id?: string;
224
+ site: VerificationSite;
225
+ owners?: string[];
226
+ }
227
+ /**
228
+ * Compatible interface with OAuth2Client from google-auth-library
229
+ */
230
+ interface AuthClient {
231
+ credentials?: {
232
+ access_token?: string | null;
233
+ refresh_token?: string | null;
234
+ expiry_date?: number | null;
235
+ };
236
+ getAccessToken: () => Promise<{
237
+ token?: string | null;
238
+ }>;
239
+ }
240
+ interface AuthOptions {
241
+ clientId: string;
242
+ clientSecret: string;
243
+ refreshToken: string;
244
+ }
245
+ declare function createAuth(options: AuthOptions): AuthClient;
246
+ /** Auth can be a token string, object with accessToken, or OAuth2Client-like object with credentials */
247
+ type Auth = string | {
248
+ accessToken: string;
249
+ } | AuthClient | AuthOptions;
250
+ declare function createFetch(auth: Auth, options?: FetchOptions): $Fetch;
251
+ /** Per-call options. `signal` cancels the in-flight request (and, for `query`, the next page too). */
252
+ interface CallOptions {
253
+ signal?: AbortSignal;
254
+ }
255
+ /** Generator return value for `client.query` — exposes API response metadata plus the resolved aggregation type Google actually used (may differ from the requested `aggregationType: 'auto'`). */
256
+ interface QueryReturn {
257
+ metadata?: GscSearchAnalyticsMetadata;
258
+ /** Aggregation type Google actually used. Useful when requesting `auto` to know if rows were aggregated `byPage` vs `byProperty`. */
259
+ responseAggregationType?: GscResponseAggregationType;
260
+ }
261
+ interface GoogleSearchConsoleClient {
262
+ /** Query search analytics with builder, returns async generator yielding typed row batches */
263
+ query: <D extends Dimension[], C>(siteUrl: string, builder: GSCQueryBuilder<D, C>, opts?: CallOptions) => AsyncGenerator<GSCRow<D, C>[], QueryReturn>;
264
+ /**
265
+ * List all sites. Also exposes write ops as `client.sites.add(siteUrl)` and
266
+ * `client.sites.delete(siteUrl)`. Calling `client.sites()` is equivalent to
267
+ * `client.sites.list()`.
268
+ */
269
+ sites: ((opts?: CallOptions) => Promise<ApiSite[]>) & {
270
+ list: (opts?: CallOptions) => Promise<ApiSite[]>; /** Retrieve a single property (with permission level). 404 if not in the user's account. */
271
+ get: (siteUrl: string, opts?: CallOptions) => Promise<ApiSite>; /** Add a property in unverified state. Caller must verify ownership separately. */
272
+ add: (siteUrl: string, opts?: CallOptions) => Promise<void>; /** Remove a property from the user's account. */
273
+ delete: (siteUrl: string, opts?: CallOptions) => Promise<void>;
274
+ };
275
+ /** Site Verification API (siteverification.googleapis.com). Required to flip a property from unverified to verified. */
276
+ verification: {
277
+ /** Returns the token to place on the site/DNS, plus the resolved method. */getToken: (params: {
278
+ site: VerificationSite;
279
+ verificationMethod: VerificationMethod;
280
+ }, opts?: CallOptions) => Promise<VerificationToken>; /** Triggers Google to fetch + validate; returns the verified WebResource. */
281
+ insert: (params: {
282
+ site: VerificationSite;
283
+ verificationMethod: VerificationMethod;
284
+ }, opts?: CallOptions) => Promise<VerificationWebResource>;
285
+ list: (opts?: CallOptions) => Promise<VerificationWebResource[]>;
286
+ get: (id: string, opts?: CallOptions) => Promise<VerificationWebResource>;
287
+ delete: (id: string, opts?: CallOptions) => Promise<void>;
288
+ };
289
+ /** Inspect a URL. `languageCode` is a BCP-47 tag for translating result strings; omit to let Google pick. */
290
+ inspect: (siteUrl: string, url: string, opts?: CallOptions & {
291
+ languageCode?: string;
292
+ }) => Promise<InspectUrlIndexResponse>;
293
+ /** Sitemap operations */
294
+ sitemaps: {
295
+ /** List sitemaps. Pass `sitemapIndex` to list children of a sitemap-index file. */list: (siteUrl: string, opts?: CallOptions & {
296
+ sitemapIndex?: string;
297
+ }) => Promise<ApiSitemap[]>;
298
+ get: (siteUrl: string, feedpath: string, opts?: CallOptions) => Promise<ApiSitemap>;
299
+ submit: (siteUrl: string, feedpath: string, opts?: CallOptions) => Promise<void>;
300
+ delete: (siteUrl: string, feedpath: string, opts?: CallOptions) => Promise<void>;
301
+ };
302
+ /** Indexing API operations */
303
+ indexing: {
304
+ publish: (url: string, type: 'URL_UPDATED' | 'URL_DELETED', opts?: CallOptions) => Promise<PublishUrlNotificationResponse>;
305
+ getMetadata: (url: string, opts?: CallOptions) => Promise<UrlNotificationMetadata>;
306
+ };
307
+ /** @internal */
308
+ _rawQuery: (siteUrl: string, body: SearchAnalyticsQuery, opts?: CallOptions) => Promise<SearchAnalyticsResponse>;
309
+ }
310
+ interface GoogleSearchConsoleClientOptions {
311
+ fetchOptions?: FetchOptions;
312
+ fetch?: $Fetch;
313
+ onRateLimited?: (context: {
314
+ response: Response;
315
+ }) => void | Promise<void>;
316
+ }
317
+ declare function googleSearchConsole(auth: Auth, options?: GoogleSearchConsoleClientOptions): GoogleSearchConsoleClient;
318
+ interface GscdumpApiOptions {
319
+ /** API key (gsd_user_xxx or gsd_prod_xxx) */
320
+ apiKey: string;
321
+ /** Base URL (defaults to https://gscdump.com) */
322
+ baseUrl?: string;
323
+ }
324
+ declare function gscdumpApi(options: GscdumpApiOptions): GoogleSearchConsoleClient;
325
+ type GscErrorKind = 'auth-expired' | 'rate-limited' | 'not-found' | 'validation' | 'storage' | 'transport';
326
+ type GscError = {
327
+ kind: 'auth-expired';
328
+ message: string;
329
+ cause: unknown;
330
+ } | {
331
+ kind: 'rate-limited';
332
+ message: string;
333
+ retryAfter?: number;
334
+ cause: unknown;
335
+ } | {
336
+ kind: 'not-found';
337
+ message: string;
338
+ cause: unknown;
339
+ } | {
340
+ kind: 'validation';
341
+ message: string;
342
+ cause: unknown;
343
+ } | {
344
+ kind: 'storage';
345
+ message: string;
346
+ cause: unknown;
347
+ } | {
348
+ kind: 'transport';
349
+ message: string;
350
+ status?: number;
351
+ cause: unknown;
352
+ };
353
+ /** Approximate per-day GSC API quotas, used in CLI messaging. */
354
+ declare const GSC_QUOTAS: {
355
+ readonly searchAnalytics: 25000;
356
+ readonly urlInspection: 2000;
357
+ readonly indexing: 200;
358
+ };
359
+ /**
360
+ * Classify an unknown error into a `GscError` discriminated union.
361
+ * Transport is the catch-all — anything without a recognizable status ends up there.
362
+ */
363
+ declare function classifyError(cause: unknown): GscError;
364
+ /** Construct a storage-kind error from inside the analytics engine / adapters. */
365
+ declare function storageError(message: string, cause?: unknown): GscError;
366
+ /**
367
+ * Re-raises a `GscError` value as an `Error`, preserving its `cause` for
368
+ * stack-walking and stashing the original union under `.gscError`. Pairs with
369
+ * `unwrapResult` from `gscdump/result` so a `fooResult(): Result<A, GscError>`
370
+ * core can be wrapped by a throwing `foo()` without losing the typed error.
371
+ */
372
+ declare function gscErrorToException(error: GscError): Error;
373
+ interface GscApiErrorInfo {
374
+ code: number;
375
+ message: string;
376
+ reason?: string;
377
+ status?: string;
378
+ }
379
+ declare function parseGoogleError(text: string, httpStatus?: number): GscApiErrorInfo;
380
+ declare class GscApiError extends Error {
381
+ info: GscApiErrorInfo;
382
+ constructor(message: string, info: GscApiErrorInfo);
383
+ }
384
+ /**
385
+ * Returns a handler that re-throws `unknown` as a `GscApiError` prefixed with
386
+ * `prefix`. Recognises `ofetch` `FetchError` (parses `err.data` as Google JSON
387
+ * via `parseGoogleError`); passes through existing `GscApiError`; re-throws
388
+ * anything else as-is.
389
+ */
390
+ declare function rethrowAsGscApiError(prefix: string): (err: unknown) => never;
391
+ /**
392
+ * String-matches an error against the signals Google returns when a token
393
+ * has lost access to a property (revoked, downgraded, or never had it).
394
+ * Cheaper than a full {@link classifyError} call when the caller only
395
+ * needs the permission verdict.
396
+ */
397
+ declare function isPermissionDeniedError(err: unknown): boolean;
398
+ /** CLI-facing formatter. Returns an ANSI-colored multi-line string. */
399
+ declare function formatErrorForCli(cause: unknown): string;
400
+ interface GscPropertyCandidate {
401
+ siteUrl?: string | null;
402
+ permissionLevel?: string | null;
403
+ }
404
+ declare function isVerifiedGscProperty(property?: GscPropertyCandidate | null): boolean;
405
+ declare function isVerifiedGscPermission(level: string | null | undefined): boolean;
406
+ /**
407
+ * Does `propertyUrl` cover `targetDomain`? Matches sc-domain (exact or
408
+ * subdomain) and URL-prefix (host equality) without scheme/www noise.
409
+ */
410
+ declare function gscPropertyMatchesTarget(targetDomain: string, propertyUrl: string | null | undefined): boolean;
411
+ /**
412
+ * Convenience: match `siteUrl` against `gscSiteUrl` directly (extracts the
413
+ * hostname from `siteUrl` first).
414
+ */
415
+ declare function matchGscSite(siteUrl: string | null | undefined, gscSiteUrl: string | null | undefined): boolean;
416
+ /**
417
+ * Pick the best GSC property for a hostname from a candidate list. "Best":
418
+ * 1. Verified Domain property (widest + readable)
419
+ * 2. Verified URL-prefix property (narrower + readable)
420
+ * 3. Unverified Domain property (returned as a fallback so callers can
421
+ * surface the verification gap to the user)
422
+ * 4. Unverified URL-prefix property (same caveat)
423
+ *
424
+ * Without this ranking, naively picking the first match would register an
425
+ * unverified property and leave the site stuck with zero data.
426
+ */
427
+ declare function pickBestGscProperty<T extends GscPropertyCandidate>(origin: string, availableSites: readonly T[]): T | undefined;
428
+ /**
429
+ * Richer best-property selection that also returns the matched domain and
430
+ * URL candidates separately, so callers can show "we matched on X domain
431
+ * property and Y URL-prefix property" diagnostics.
432
+ */
433
+ declare function findBestGscProperty<T extends GscPropertyCandidate>(targetDomain: string, properties: readonly T[]): {
434
+ matchedSite: T | null;
435
+ domainProperty: T | null;
436
+ urlProperty: T | null;
437
+ };
438
+ declare function findExactGscProperty<T extends GscPropertyCandidate>(propertyUrl: string, properties: readonly T[]): T | null;
439
+ declare function formatGscPropertyCandidates(candidates: ReadonlyArray<GscPropertyCandidate | null | undefined>): string;
440
+ declare const URL_INSPECTION_DAILY_LIMIT = 2000;
441
+ declare const URL_INSPECTION_EFFECTIVE_LIMIT = 1800;
442
+ declare function hasGscReadScope(scopes: string | null | undefined): boolean;
443
+ declare function hasGscWriteScope(scopes: string | null | undefined): boolean;
444
+ declare function hasIndexingScope(scopes: string | null | undefined): boolean;
445
+ interface ParsedGscSiteUrl {
446
+ /** Original, canonical GSC property URL. */
447
+ label: string;
448
+ /** Bare hostname, stripped of protocol / sc-domain prefix / path. */
449
+ hostname: string;
450
+ /** Human-friendly label: scheme stripped, trailing slash trimmed, path retained. */
451
+ displayLabel: string;
452
+ propertyType: 'domain' | 'url-prefix';
453
+ isDomain: boolean;
454
+ }
455
+ declare function parseGscSiteUrl(siteUrl: string): ParsedGscSiteUrl;
456
+ /**
457
+ * Comparison-canonical form of a GSC property URL. Strips `sc-domain:`,
458
+ * protocol, leading `www.`, trailing slash, and lowercases. Use when matching
459
+ * the same logical site across `https://www.example.com/` vs
460
+ * `sc-domain:example.com` vs bare hostnames — properties Google sometimes
461
+ * returns in different shapes for the same site.
462
+ */
463
+ declare function normalizeGscSiteUrl(siteUrl: string): string;
464
+ /**
465
+ * Normalize a user-input URL/hostname into a canonical registration target.
466
+ * Returns lowercase hostname stripped of protocol, or null if unparseable.
467
+ */
468
+ declare function normalizeRegistrationTarget(inputUrl: string): string | null;
469
+ interface DiscoverSitemapOptions {
470
+ /** User-Agent sent on the discovery requests. */
471
+ userAgent?: string;
472
+ /** AbortSignal threaded through fetches; defaults to a 10s timeout per call. */
473
+ signal?: AbortSignal;
474
+ }
475
+ /**
476
+ * Try to discover a sitemap for `domain` by checking robots.txt for a
477
+ * `Sitemap:` directive, then a small set of common paths. Returns the first
478
+ * URL that responds with a 2xx, or `null`.
479
+ */
480
+ declare function discoverSitemap(domain: string, options?: DiscoverSitemapOptions): Promise<string | null>;
481
+ interface FetchSitemapUrlsOptions extends DiscoverSitemapOptions {
482
+ /** Maximum nested sitemap-index depth to follow. Default 3. */
483
+ maxDepth?: number;
484
+ /** Stop after this many URLs (across all nested sitemaps). Default unlimited. */
485
+ limit?: number;
486
+ }
487
+ /**
488
+ * Fetch a sitemap (or sitemap index) and return the list of `<loc>` URLs.
489
+ * Sitemap-index files are followed up to `maxDepth` levels. Duplicates are
490
+ * de-duplicated. The XML parser is regex-based — it handles the common
491
+ * `<loc>https://...</loc>` shape but doesn't validate the schema.
492
+ */
493
+ declare function fetchSitemapUrls(sitemapUrl: string, options?: FetchSitemapUrlsOptions): Promise<string[]>;
494
+ /**
495
+ * Equivalence key for matching two URLs that point at the same resource
496
+ * across protocol (http/https), www. prefix, trailing slash, and casing.
497
+ * Returns `null` for unparseable input.
498
+ *
499
+ * Example: `https://www.Example.com/Foo/` → `example.com/foo`
500
+ */
501
+ declare function urlMatchKey(url: string): string | null;
502
+ /**
503
+ * Batch runner with optional concurrency, inter-call delay, and progress.
504
+ * Used by batchRequestIndexing / batchInspectUrls. Defaults to sequential
505
+ * (concurrency = 1) because the underlying APIs rate-limit aggressively;
506
+ * callers that know their quota headroom can opt into parallelism.
507
+ */
508
+ declare function runSequentialBatch<I, R>(items: I[], operation: (item: I, index: number) => Promise<R>, options?: {
509
+ delayMs?: number;
510
+ concurrency?: number;
511
+ onProgress?: (result: R, index: number, total: number) => void;
512
+ }): Promise<R[]>;
513
+ type IndexingNotificationType = 'URL_UPDATED' | 'URL_DELETED';
514
+ interface IndexingResult {
515
+ url: string;
516
+ type: IndexingNotificationType;
517
+ notifyTime?: string;
518
+ }
519
+ interface IndexingMetadata {
520
+ url: string;
521
+ latestUpdate?: indexing_v3.Schema$UrlNotificationMetadata;
522
+ latestRemove?: indexing_v3.Schema$UrlNotificationMetadata;
523
+ }
524
+ /**
525
+ * Request Google to index or remove a URL via the Indexing API.
526
+ * Note: The Indexing API officially supports only job posting and livestream content,
527
+ * but can be used for any URL with varying success.
528
+ */
529
+ declare function requestIndexing(client: GoogleSearchConsoleClient, url: string, options?: {
530
+ type?: IndexingNotificationType;
531
+ }): Promise<IndexingResult>;
532
+ /**
533
+ * Get the indexing notification metadata for a URL.
534
+ * Returns when Google was last notified about updates/removals.
535
+ */
536
+ declare function getIndexingMetadata(client: GoogleSearchConsoleClient, url: string): Promise<IndexingMetadata>;
537
+ /**
538
+ * Batch request indexing for multiple URLs with rate limiting.
539
+ * Returns results for each URL.
540
+ */
541
+ declare function batchRequestIndexing(client: GoogleSearchConsoleClient, urls: string[], options?: {
542
+ type?: IndexingNotificationType;
543
+ delayMs?: number;
544
+ concurrency?: number;
545
+ onProgress?: (result: IndexingResult, index: number, total: number) => void;
546
+ }): Promise<IndexingResult[]>;
547
+ interface InspectUrlResult {
548
+ url: string;
549
+ inspection?: UrlInspectionResult;
550
+ isIndexed: boolean;
551
+ }
552
+ /**
553
+ * Inspects a URL in Google Search Console to check its indexing status.
554
+ */
555
+ declare function inspectUrl(client: GoogleSearchConsoleClient, siteUrl: string, inspectionUrl: string): Promise<{
556
+ inspection: UrlInspectionResult | undefined;
557
+ isIndexed: boolean;
558
+ }>;
559
+ /**
560
+ * Batch inspect multiple URLs with rate limiting.
561
+ * Returns inspection results for each URL.
562
+ */
563
+ declare function batchInspectUrls(client: GoogleSearchConsoleClient, siteUrl: string, urls: string[], options?: {
564
+ delayMs?: number;
565
+ concurrency?: number;
566
+ onProgress?: (result: InspectUrlResult, index: number, total: number) => void;
567
+ }): Promise<InspectUrlResult[]>;
568
+ interface ParsedIndexingResult {
569
+ url: string;
570
+ verdict: string | null;
571
+ coverageState: string | null;
572
+ indexingState: string | null;
573
+ robotsTxtState: string | null;
574
+ pageFetchState: string | null;
575
+ lastCrawlTime: string | null;
576
+ crawlingUserAgent: string | null;
577
+ userCanonical: string | null;
578
+ googleCanonical: string | null;
579
+ sitemaps: string | null;
580
+ referringUrls: string | null;
581
+ mobileVerdict: string | null;
582
+ mobileIssues: string | null;
583
+ richResultsVerdict: string | null;
584
+ richResultsItems: string | null;
585
+ ampVerdict: string | null;
586
+ ampUrl: string | null;
587
+ ampIndexingState: string | null;
588
+ ampIndexStatusVerdict: string | null;
589
+ ampRobotsTxtState: string | null;
590
+ ampPageFetchState: string | null;
591
+ ampLastCrawlTime: string | null;
592
+ ampIssues: string | null;
593
+ inspectionResultLink: string | null;
594
+ }
595
+ declare function inspectUrlFlat(client: GoogleSearchConsoleClient, siteUrl: string, inspectionUrl: string): Promise<ParsedIndexingResult>;
596
+ type InspectionPriority = 'high' | 'medium' | 'low';
597
+ declare function getNextCheckPriority(result: Pick<ParsedIndexingResult, 'verdict'>): InspectionPriority;
598
+ /** Next-check unix seconds for a given priority. */
599
+ declare function getNextCheckAfter(priority: InspectionPriority): number;
600
+ declare function canUseUrlInspection(permissionLevel: string | null | undefined): boolean;
601
+ declare function grantedScopeList(scopes: string | null | undefined): string[];
602
+ type IndexingIneligibleReason = 'missing_indexing_scope' | 'insufficient_gsc_permission';
603
+ interface IndexingEligibility {
604
+ indexingEligible: boolean;
605
+ indexingIneligibleReason?: IndexingIneligibleReason;
606
+ indexingPermissionLevel?: string | null;
607
+ grantedScopes?: string[];
608
+ }
609
+ declare function getIndexingEligibility(grantedScopes: string | null | undefined, permissionLevel: string | null | undefined): IndexingEligibility;
610
+ interface Ok<A> {
611
+ readonly ok: true;
612
+ readonly value: A;
613
+ }
614
+ interface Err<E> {
615
+ readonly ok: false;
616
+ readonly error: E;
617
+ }
618
+ type Result<A, E> = Ok<A> | Err<E>;
619
+ interface OAuthTokens {
620
+ accessToken: string;
621
+ /** Unix seconds. */
622
+ expiresAt: number;
623
+ }
624
+ /**
625
+ * Errors-as-values core for {@link refreshAccessToken}: returns a classified
626
+ * `GscError` instead of throwing, so token-storage callers can branch on
627
+ * `error.kind` — `auth-expired` (the refresh token is permanently bad, re-auth)
628
+ * vs `transport` (transient, safe to retry later) — rather than string-matching.
629
+ */
630
+ declare function refreshAccessTokenResult(refreshToken: string, clientId: string, clientSecret: string): Promise<Result<OAuthTokens, GscError>>;
631
+ /**
632
+ * Exchange a refresh token for an access token. Retries transient network
633
+ * failures; surfaces HTTP failures (invalid_grant, etc.) immediately as
634
+ * `GscApiError` so callers can mark the refresh token as bad.
635
+ */
636
+ declare function refreshAccessToken(refreshToken: string, clientId: string, clientSecret: string): Promise<OAuthTokens>;
637
+ /**
638
+ * Errors-as-values core for {@link exchangeAuthCode}: same `auth-expired` vs
639
+ * `transport` classification as {@link refreshAccessTokenResult}.
640
+ */
641
+ declare function exchangeAuthCodeResult(code: string, clientId: string, clientSecret: string, redirectUri: string): Promise<Result<OAuthTokens & {
642
+ refreshToken?: string;
643
+ }, GscError>>;
644
+ /**
645
+ * Exchange an authorization code (from the OAuth consent redirect) for
646
+ * access + refresh tokens. Same retry / surface model as `refreshAccessToken`.
647
+ */
648
+ declare function exchangeAuthCode(code: string, clientId: string, clientSecret: string, redirectUri: string): Promise<OAuthTokens & {
649
+ refreshToken?: string;
650
+ }>;
651
+ /**
652
+ * Fetches all sites the authenticated user has access to in Google Search Console.
653
+ */
654
+ declare function fetchSites(client: GoogleSearchConsoleClient): Promise<ApiSite[]>;
655
+ /**
656
+ * Fetches all verified sites with their sitemaps from Google Search Console.
657
+ */
658
+ declare function fetchSitesWithSitemaps(client: GoogleSearchConsoleClient): Promise<(Site & {
659
+ sitemaps: ApiSitemap[];
660
+ })[]>;
661
+ /**
662
+ * Fetches all sitemaps for a site.
663
+ */
664
+ declare function fetchSitemaps(client: GoogleSearchConsoleClient, siteUrl: string): Promise<ApiSitemap[]>;
665
+ /**
666
+ * Fetches a specific sitemap.
667
+ */
668
+ declare function fetchSitemap(client: GoogleSearchConsoleClient, siteUrl: string, feedpath: string): Promise<ApiSitemap>;
669
+ /**
670
+ * Submits a sitemap to Google Search Console.
671
+ */
672
+ declare function submitSitemap(client: GoogleSearchConsoleClient, siteUrl: string, feedpath: string): Promise<void>;
673
+ /**
674
+ * Deletes a sitemap from Google Search Console.
675
+ */
676
+ declare function deleteSitemap(client: GoogleSearchConsoleClient, siteUrl: string, feedpath: string): Promise<void>;
677
+ /**
678
+ * Add a property to the user's Search Console account.
679
+ *
680
+ * Note: this only registers the property in an unverified state. Ownership
681
+ * must be proven via the Site Verification API (see `verifySite`) before any
682
+ * data is accessible.
683
+ */
684
+ declare function addSite(client: GoogleSearchConsoleClient, siteUrl: string): Promise<void>;
685
+ /**
686
+ * Remove a property from the user's Search Console account.
687
+ */
688
+ declare function deleteSite(client: GoogleSearchConsoleClient, siteUrl: string): Promise<void>;
689
+ /**
690
+ * Resolve a Search Console site URL (`https://example.com/` or
691
+ * `sc-domain:example.com`) to the Site Verification API's site shape.
692
+ */
693
+ declare function siteUrlToVerificationSite(siteUrl: string): VerificationSite;
694
+ /**
695
+ * Methods valid for a given site shape. SITE properties can use META/FILE/
696
+ * ANALYTICS/TAG_MANAGER; INET_DOMAIN must use DNS_TXT or DNS_CNAME.
697
+ */
698
+ declare function verificationMethodsFor(site: VerificationSite): VerificationMethod[];
699
+ /**
700
+ * Get the verification token Google expects to find on the site or DNS.
701
+ */
702
+ declare function getVerificationToken(client: GoogleSearchConsoleClient, siteUrl: string, method: VerificationMethod): Promise<VerificationToken & {
703
+ site: VerificationSite;
704
+ }>;
705
+ /**
706
+ * Trigger Google to validate the placed token. Caller is responsible for
707
+ * having placed the token (HTML tag / file / DNS record) before calling.
708
+ */
709
+ declare function verifySite(client: GoogleSearchConsoleClient, siteUrl: string, method: VerificationMethod): Promise<VerificationWebResource>;
710
+ /**
711
+ * List all verified WebResources for the authed user.
712
+ */
713
+ declare function listVerifiedSites(client: GoogleSearchConsoleClient): Promise<VerificationWebResource[]>;
714
+ /**
715
+ * Fetch a single verified WebResource by id.
716
+ */
717
+ declare function getVerifiedSite(client: GoogleSearchConsoleClient, id: string): Promise<VerificationWebResource>;
718
+ /**
719
+ * Drop the calling user's verified ownership of a WebResource. The placed
720
+ * verification token (meta tag / file / DNS record) MUST be removed first,
721
+ * otherwise Google may auto-re-verify and the call will fail. Other owners
722
+ * on the property are unaffected.
723
+ */
724
+ declare function unverifySite(client: GoogleSearchConsoleClient, id: string): Promise<void>;
725
+ export { ApiSite, ApiSitemap, ApiSitemapContent, Auth, AuthClient, AuthOptions, CallOptions, DataRow, DimensionFilter, DimensionFilterGroup, DiscoverSitemapOptions, FetchSitemapUrlsOptions, GSC_QUOTAS, GoogleSearchConsoleClient, GoogleSearchConsoleClientOptions, GscApiError, GscApiErrorInfo, GscError, GscErrorKind, GscPropertyCandidate, GscdumpApiOptions, IndexStatusResult, IndexingEligibility, IndexingIneligibleReason, IndexingMetadata, IndexingNotificationType, IndexingResult, InspectUrlIndexResponse, InspectUrlResult, InspectionPriority, MobileUsabilityResult, OAuthTokens, ParsedGscSiteUrl, ParsedIndexingResult, Period, PublishUrlNotificationResponse, QueryReturn, RequiredNonNullable, ResolvedAnalyticsRange, RichResultsResult, SearchAnalyticsQuery, SearchAnalyticsResponse, Site, SiteAnalytics, URL_INSPECTION_DAILY_LIMIT, URL_INSPECTION_EFFECTIVE_LIMIT, UrlInspectionResult, UrlNotificationMetadata, VerificationMethod, VerificationSite, VerificationSiteType, VerificationToken, VerificationWebResource, addSite, batchInspectUrls, batchRequestIndexing, canUseUrlInspection, classifyError, createAuth, createFetch, deleteSite, deleteSitemap, discoverSitemap, exchangeAuthCode, exchangeAuthCodeResult, fetchSitemap, fetchSitemapUrls, fetchSitemaps, fetchSites, fetchSitesWithSitemaps, findBestGscProperty, findExactGscProperty, formatErrorForCli, formatGscPropertyCandidates, getIndexingEligibility, getIndexingMetadata, getNextCheckAfter, getNextCheckPriority, getVerificationToken, getVerifiedSite, googleSearchConsole, grantedScopeList, gscErrorToException, gscPropertyMatchesTarget, gscdumpApi, hasGscReadScope, hasGscWriteScope, hasIndexingScope, inspectUrl, inspectUrlFlat, isPermissionDeniedError, isVerifiedGscPermission, isVerifiedGscProperty, listVerifiedSites, matchGscSite, normalizeGscSiteUrl, normalizeRegistrationTarget, parseGoogleError, parseGscSiteUrl, pickBestGscProperty, refreshAccessToken, refreshAccessTokenResult, requestIndexing, rethrowAsGscApiError, runSequentialBatch, siteUrlToVerificationSite, storageError, submitSitemap, unverifySite, urlMatchKey, verificationMethodsFor, verifySite };