gscdump 2.0.6 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/inspection.d.mts +3 -1
- package/dist/api/inspection.mjs +7 -7
- package/dist/api/oauth.mjs +5 -1
- package/dist/core/client.d.mts +2 -0
- package/dist/core/client.mjs +35 -9
- package/dist/core/types.d.mts +4 -7
- package/dist/query/plan.mjs +4 -2
- package/dist/query/resolver.mjs +0 -1
- package/package.json +2 -2
|
@@ -34,7 +34,9 @@ interface ParsedIndexingResult {
|
|
|
34
34
|
googleCanonical: string | null;
|
|
35
35
|
sitemaps: string | null;
|
|
36
36
|
referringUrls: string | null;
|
|
37
|
+
/** @deprecated Retained for historical storage rows. */
|
|
37
38
|
mobileVerdict: string | null;
|
|
39
|
+
/** @deprecated Retained for historical storage rows. */
|
|
38
40
|
mobileIssues: string | null;
|
|
39
41
|
richResultsVerdict: string | null;
|
|
40
42
|
richResultsItems: string | null;
|
|
@@ -90,7 +92,7 @@ declare function getNextCheckPriority(result: Pick<ParsedIndexingResult, 'verdic
|
|
|
90
92
|
/** Next-check unix seconds for a given priority. */
|
|
91
93
|
declare function getNextCheckAfter(priority: InspectionPriority): number;
|
|
92
94
|
declare function canUseUrlInspection(permissionLevel: string | null | undefined): boolean;
|
|
93
|
-
type IndexingIneligibleReason = '
|
|
95
|
+
type IndexingIneligibleReason = 'missing_gsc_read_scope' | 'insufficient_gsc_permission';
|
|
94
96
|
interface IndexingEligibility {
|
|
95
97
|
indexingEligible: boolean;
|
|
96
98
|
indexingIneligibleReason?: IndexingIneligibleReason;
|
package/dist/api/inspection.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { runSequentialBatch } from "./batch.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { hasGscReadScope } from "../core/scopes.mjs";
|
|
3
3
|
async function inspectUrl(client, siteUrl, inspectionUrl) {
|
|
4
4
|
const inspection = (await client.inspect(siteUrl, inspectionUrl)).inspectionResult;
|
|
5
5
|
return {
|
|
@@ -97,12 +97,12 @@ function getNextCheckAfter(priority) {
|
|
|
97
97
|
const now = Math.floor(Date.now() / 1e3);
|
|
98
98
|
switch (priority) {
|
|
99
99
|
case "critical":
|
|
100
|
-
case "high": return now +
|
|
100
|
+
case "high": return now + 604800;
|
|
101
101
|
case "elevated":
|
|
102
|
-
case "medium": return now +
|
|
102
|
+
case "medium": return now + 1209600;
|
|
103
103
|
case "low":
|
|
104
|
-
case "normal": return now +
|
|
105
|
-
case "dormant": return now +
|
|
104
|
+
case "normal": return now + 2592e3;
|
|
105
|
+
case "dormant": return now + 10368e3;
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
const INSPECTION_ALLOWED_PERMISSIONS = /* @__PURE__ */ new Set([
|
|
@@ -118,9 +118,9 @@ function grantedScopeList(scopes) {
|
|
|
118
118
|
}
|
|
119
119
|
function getIndexingEligibility(grantedScopes, permissionLevel) {
|
|
120
120
|
const scopes = grantedScopeList(grantedScopes);
|
|
121
|
-
if (!
|
|
121
|
+
if (!hasGscReadScope(grantedScopes)) return {
|
|
122
122
|
indexingEligible: false,
|
|
123
|
-
indexingIneligibleReason: "
|
|
123
|
+
indexingIneligibleReason: "missing_gsc_read_scope",
|
|
124
124
|
indexingPermissionLevel: permissionLevel ?? null,
|
|
125
125
|
grantedScopes: scopes
|
|
126
126
|
};
|
package/dist/api/oauth.mjs
CHANGED
|
@@ -118,7 +118,11 @@ async function requestOAuthResult(url, init, op) {
|
|
|
118
118
|
return null;
|
|
119
119
|
});
|
|
120
120
|
if (!res) continue;
|
|
121
|
-
if (!res.ok)
|
|
121
|
+
if (!res.ok) {
|
|
122
|
+
const text = await res.text();
|
|
123
|
+
const info = parseGoogleError(text, res.status);
|
|
124
|
+
return err(oauthHttpError(op, info));
|
|
125
|
+
}
|
|
122
126
|
return ok(res);
|
|
123
127
|
}
|
|
124
128
|
return err({
|
package/dist/core/client.d.mts
CHANGED
|
@@ -85,6 +85,8 @@ interface GoogleSearchConsoleClient {
|
|
|
85
85
|
}, opts?: CallOptions) => Promise<VerificationWebResource>;
|
|
86
86
|
list: (opts?: CallOptions) => Promise<VerificationWebResource[]>;
|
|
87
87
|
get: (id: string, opts?: CallOptions) => Promise<VerificationWebResource>;
|
|
88
|
+
patch: (id: string, resource: VerificationWebResource, opts?: CallOptions) => Promise<VerificationWebResource>;
|
|
89
|
+
update: (id: string, resource: VerificationWebResource, opts?: CallOptions) => Promise<VerificationWebResource>;
|
|
88
90
|
delete: (id: string, opts?: CallOptions) => Promise<void>;
|
|
89
91
|
};
|
|
90
92
|
/** Inspect a URL. `languageCode` is a BCP-47 tag for translating result strings; omit to let Google pick. */
|
package/dist/core/client.mjs
CHANGED
|
@@ -91,8 +91,10 @@ function createFetch(auth, options) {
|
|
|
91
91
|
},
|
|
92
92
|
async onResponseError(ctx) {
|
|
93
93
|
if (ctx.response.status === 403) console.error("[gscdump] Permission denied (403). check your service account permissions being added to the GSC property.");
|
|
94
|
-
if (options?.onResponseError)
|
|
95
|
-
|
|
94
|
+
if (options?.onResponseError) {
|
|
95
|
+
if (Array.isArray(options.onResponseError)) for (const handler of options.onResponseError) await handler(ctx);
|
|
96
|
+
else await options.onResponseError(ctx);
|
|
97
|
+
}
|
|
96
98
|
}
|
|
97
99
|
});
|
|
98
100
|
}
|
|
@@ -106,17 +108,31 @@ function googleSearchConsole(auth, options = {}) {
|
|
|
106
108
|
const originalOnError = fetchOptions.onResponseError;
|
|
107
109
|
fetchOptions.onResponseError = async (ctx) => {
|
|
108
110
|
if (ctx.response.status === 429) await options.onRateLimited({ response: ctx.response });
|
|
109
|
-
if (originalOnError)
|
|
110
|
-
|
|
111
|
+
if (originalOnError) {
|
|
112
|
+
if (Array.isArray(originalOnError)) for (const handler of originalOnError) await handler(ctx);
|
|
113
|
+
else await originalOnError(ctx);
|
|
114
|
+
}
|
|
111
115
|
};
|
|
112
116
|
}
|
|
113
117
|
fetch = createFetch(authState, fetchOptions);
|
|
114
118
|
}
|
|
115
|
-
const querySearchAnalytics = (siteUrl, body, opts) =>
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
const querySearchAnalytics = async (siteUrl, body, opts) => {
|
|
120
|
+
const response = await fetch(`${GSC_API}/webmasters/v3/sites/${encodeSiteUrl(siteUrl)}/searchAnalytics/query`, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
body,
|
|
123
|
+
signal: opts?.signal
|
|
124
|
+
});
|
|
125
|
+
if (!response.metadata) return response;
|
|
126
|
+
const firstIncompleteDate = response.metadata.first_incomplete_date ?? response.metadata.firstIncompleteDate;
|
|
127
|
+
const firstIncompleteHour = response.metadata.first_incomplete_hour ?? response.metadata.firstIncompleteHour;
|
|
128
|
+
return {
|
|
129
|
+
...response,
|
|
130
|
+
metadata: {
|
|
131
|
+
...typeof firstIncompleteDate === "string" ? { first_incomplete_date: firstIncompleteDate } : {},
|
|
132
|
+
...typeof firstIncompleteHour === "string" ? { first_incomplete_hour: firstIncompleteHour } : {}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
};
|
|
120
136
|
return {
|
|
121
137
|
async *query(siteUrl, builder, opts) {
|
|
122
138
|
const state = builder.getState();
|
|
@@ -192,6 +208,16 @@ function googleSearchConsole(auth, options = {}) {
|
|
|
192
208
|
return (await fetch(`${SITE_VERIFICATION_API}/webResource`, { signal: opts?.signal })).items || [];
|
|
193
209
|
},
|
|
194
210
|
get: (id, opts) => fetch(`${SITE_VERIFICATION_API}/webResource/${encodeURIComponent(id)}`, { signal: opts?.signal }),
|
|
211
|
+
patch: (id, resource, opts) => fetch(`${SITE_VERIFICATION_API}/webResource/${encodeURIComponent(id)}`, {
|
|
212
|
+
method: "PATCH",
|
|
213
|
+
body: resource,
|
|
214
|
+
signal: opts?.signal
|
|
215
|
+
}),
|
|
216
|
+
update: (id, resource, opts) => fetch(`${SITE_VERIFICATION_API}/webResource/${encodeURIComponent(id)}`, {
|
|
217
|
+
method: "PUT",
|
|
218
|
+
body: resource,
|
|
219
|
+
signal: opts?.signal
|
|
220
|
+
}),
|
|
195
221
|
delete: (id, opts) => fetch(`${SITE_VERIFICATION_API}/webResource/${encodeURIComponent(id)}`, {
|
|
196
222
|
method: "DELETE",
|
|
197
223
|
signal: opts?.signal
|
package/dist/core/types.d.mts
CHANGED
|
@@ -5,7 +5,7 @@ interface ApiSite {
|
|
|
5
5
|
}
|
|
6
6
|
/** Per-content-type counts returned with a sitemap. */
|
|
7
7
|
interface ApiSitemapContent {
|
|
8
|
-
/**
|
|
8
|
+
/** @deprecated Google can still include this field on the wire. */
|
|
9
9
|
indexed?: string | null;
|
|
10
10
|
submitted?: string | null;
|
|
11
11
|
type?: string | null;
|
|
@@ -56,12 +56,8 @@ interface DataRow {
|
|
|
56
56
|
}
|
|
57
57
|
/** Completeness metadata returned with recent Search Analytics data. */
|
|
58
58
|
interface SearchAnalyticsMetadata {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
/** Field name returned by the direct REST endpoint. */
|
|
62
|
-
first_incomplete_date?: string | null;
|
|
63
|
-
/** Field name returned by the direct REST endpoint. */
|
|
64
|
-
first_incomplete_hour?: string | null;
|
|
59
|
+
first_incomplete_date?: string;
|
|
60
|
+
first_incomplete_hour?: string;
|
|
65
61
|
}
|
|
66
62
|
/** Raw Search Analytics response returned by Google's REST endpoint. */
|
|
67
63
|
interface SearchAnalyticsResponse {
|
|
@@ -126,6 +122,7 @@ interface UrlInspectionResult {
|
|
|
126
122
|
ampResult?: AmpInspectionResult;
|
|
127
123
|
indexStatusResult?: IndexStatusResult;
|
|
128
124
|
inspectionResultLink?: string | null;
|
|
125
|
+
/** @deprecated Google no longer returns this result. */
|
|
129
126
|
mobileUsabilityResult?: MobileUsabilityResult;
|
|
130
127
|
richResultsResult?: RichResultsResult;
|
|
131
128
|
}
|
package/dist/query/plan.mjs
CHANGED
|
@@ -94,7 +94,8 @@ function buildLogicalPlanResult(state, capabilities = {}) {
|
|
|
94
94
|
if (!capabilities.regex && allFilters.some((f) => isDimensionLeaf(f) && isRegexOperator(f.operator))) return err(queryErrors.unsupportedCapability("regex", "logical plan"));
|
|
95
95
|
const metricFilters = extractMetricFilters(normalizedFilter);
|
|
96
96
|
const specialFilters = extractSpecialOperatorFilters(normalizedFilter);
|
|
97
|
-
const
|
|
97
|
+
const normalizedPrefilter = normalizeFilter(state.prefilter);
|
|
98
|
+
const prefilters = extractMetricFilters(normalizedPrefilter);
|
|
98
99
|
const queryParams = {};
|
|
99
100
|
const dimensionFilters = [];
|
|
100
101
|
for (const filter of allFilters) {
|
|
@@ -115,8 +116,9 @@ function buildLogicalPlanResult(state, capabilities = {}) {
|
|
|
115
116
|
const dimensionFilterTree = buildDimensionFilterTree(normalizedFilter);
|
|
116
117
|
const filterDims = dimensionFilters.map((filter) => filter.dimension);
|
|
117
118
|
if (!isDatasetResolvable(state.dimensions, filterDims)) return err(queryErrors.unresolvableDataset(state.dimensions, filterDims));
|
|
119
|
+
const dataset = inferDataset(state.dimensions, filterDims);
|
|
118
120
|
return ok({
|
|
119
|
-
dataset
|
|
121
|
+
dataset,
|
|
120
122
|
dimensions: [...state.dimensions],
|
|
121
123
|
groupByDimensions: state.dimensions.filter((d) => d !== "date"),
|
|
122
124
|
hasDate: state.dimensions.includes("date"),
|
package/dist/query/resolver.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gscdump",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.1.1",
|
|
5
5
|
"description": "Direct Google Search Console client with typed queries, streaming pagination, URL inspection, and indexing helpers",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
},
|
|
89
89
|
"dependencies": {
|
|
90
90
|
"ofetch": "^1.5.1",
|
|
91
|
-
"@gscdump/contracts": "^2.
|
|
91
|
+
"@gscdump/contracts": "^2.1.1"
|
|
92
92
|
},
|
|
93
93
|
"scripts": {
|
|
94
94
|
"dev": "obuild --stub",
|