gscdump 3.7.0 → 4.0.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.
@@ -12,6 +12,16 @@ export declare function inspectUrl(client: GoogleSearchConsoleClient, siteUrl: s
12
12
  inspection: UrlInspectionResult | undefined;
13
13
  isIndexed: boolean;
14
14
  }>;
15
+ /** Google's URL Inspection quota for each property. */
16
+ export declare const URL_INSPECTION_QUOTA: {
17
+ readonly perDay: 2000;
18
+ readonly perMinute: 600;
19
+ };
20
+ /**
21
+ * Plain text for a failed URL Inspection call. The generic 403 and 429 texts
22
+ * do not say what URL Inspection needs, so these name the real limits.
23
+ */
24
+ export declare function describeInspectionError(cause: unknown): string;
15
25
  /**
16
26
  * Batch inspect multiple URLs with rate limiting.
17
27
  * Returns inspection results for each URL.
@@ -1,4 +1,5 @@
1
1
  import { runSequentialBatch } from "./batch.mjs";
2
+ import { classifyError } from "../core/errors.mjs";
2
3
  import { hasGscReadScope } from "../core/scopes.mjs";
3
4
  async function inspectUrl(client, siteUrl, inspectionUrl) {
4
5
  const inspection = (await client.inspect(siteUrl, inspectionUrl)).inspectionResult;
@@ -7,6 +8,16 @@ async function inspectUrl(client, siteUrl, inspectionUrl) {
7
8
  isIndexed: inspection?.indexStatusResult?.verdict === "PASS"
8
9
  };
9
10
  }
11
+ const URL_INSPECTION_QUOTA = {
12
+ perDay: 2e3,
13
+ perMinute: 600
14
+ };
15
+ function describeInspectionError(cause) {
16
+ const error = classifyError(cause);
17
+ if (error.kind === "rate-limited") return `URL Inspection quota reached. Google allows ${URL_INSPECTION_QUOTA.perDay.toLocaleString("en-US")} inspections per day and ${URL_INSPECTION_QUOTA.perMinute} per minute for each property.`;
18
+ if (error.kind === "permission-denied") return "The URL is outside this property, or you are not a full user or owner of the property.";
19
+ return error.message;
20
+ }
10
21
  async function batchInspectUrls(client, siteUrl, urls, options = {}) {
11
22
  const { delayMs = 200, concurrency, onProgress } = options;
12
23
  return runSequentialBatch(urls, async (url) => {
@@ -136,4 +147,4 @@ function getIndexingEligibility(grantedScopes, permissionLevel) {
136
147
  grantedScopes: scopes
137
148
  };
138
149
  }
139
- export { MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, batchInspectUrls, batchInspectUrlsFlatSettled, canUseUrlInspection, getIndexingEligibility, getNextCheckAfter, getNextCheckPriority, inspectUrl, inspectUrlFlat };
150
+ export { MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, URL_INSPECTION_QUOTA, batchInspectUrls, batchInspectUrlsFlatSettled, canUseUrlInspection, describeInspectionError, getIndexingEligibility, getNextCheckAfter, getNextCheckPriority, inspectUrl, inspectUrlFlat };
@@ -1,3 +1,4 @@
1
+ import { classifyError } from "./errors.mjs";
1
2
  import { refreshAccessToken } from "../api/oauth.mjs";
2
3
  import { resolveToBody } from "../query/resolver.mjs";
3
4
  import { rowWithMetricDefaults } from "./cli-format.mjs";
@@ -49,14 +50,30 @@ async function resolveToken(auth) {
49
50
  if ("credentials" in auth && auth.credentials) return auth.credentials.access_token || "";
50
51
  return "";
51
52
  }
53
+ function isQuota403(body) {
54
+ return classifyError({
55
+ status: 403,
56
+ data: body
57
+ }).kind === "rate-limited";
58
+ }
52
59
  function createFetch(auth, options) {
53
60
  const authState = typeof auth === "object" && auth !== null && "clientId" in auth && "refreshToken" in auth && !("getAccessToken" in auth) ? createAuth(auth) : auth;
54
61
  const headers = new Headers(options?.headers);
55
62
  if (!headers.has("Accept-Encoding")) headers.set("Accept-Encoding", "gzip");
56
63
  if (!headers.has("User-Agent")) headers.set("User-Agent", "gscdump (gzip)");
64
+ const baseRetryStatusCodes = options?.retryStatusCodes ?? [
65
+ 408,
66
+ 425,
67
+ 429,
68
+ 500,
69
+ 502,
70
+ 503,
71
+ 504
72
+ ];
73
+ const retries = options?.retry ?? 3;
57
74
  return ofetch.create({
58
75
  ...options,
59
- retry: options?.retry ?? 3,
76
+ retry: retries,
60
77
  retryDelay: options?.retryDelay ?? ((ctx) => {
61
78
  const status = ctx.response?.status;
62
79
  if (status === 429 || status === 503) {
@@ -68,17 +85,10 @@ function createFetch(auth, options) {
68
85
  if (Number.isFinite(when)) return Math.max(0, when - Date.now());
69
86
  }
70
87
  }
88
+ if (status === 403 && typeof ctx.options.retry === "number" && typeof retries === "number") return 5e3 * 3 ** Math.max(0, retries - ctx.options.retry);
71
89
  return 1e3;
72
90
  }),
73
- retryStatusCodes: options?.retryStatusCodes ?? [
74
- 408,
75
- 425,
76
- 429,
77
- 500,
78
- 502,
79
- 503,
80
- 504
81
- ],
91
+ retryStatusCodes: baseRetryStatusCodes,
82
92
  timeout: options?.timeout ?? 3e4,
83
93
  headers,
84
94
  async onRequest(ctx) {
@@ -93,7 +103,9 @@ function createFetch(auth, options) {
93
103
  }
94
104
  },
95
105
  async onResponseError(ctx) {
96
- if (ctx.response.status === 403) console.error("[gscdump] Permission denied (403). check your service account permissions being added to the GSC property.");
106
+ const retryable = new Set(baseRetryStatusCodes);
107
+ if (ctx.response.status === 403 && isQuota403(ctx.response._data)) retryable.add(403);
108
+ if (ctx.options) ctx.options.retryStatusCodes = [...retryable];
97
109
  if (options?.onResponseError) {
98
110
  if (Array.isArray(options.onResponseError)) for (const handler of options.onResponseError) await handler(ctx);
99
111
  else await options.onResponseError(ctx);
@@ -1,8 +1,12 @@
1
- export type GscErrorKind = 'auth-expired' | 'rate-limited' | 'not-found' | 'validation' | 'storage' | 'transport';
1
+ export type GscErrorKind = 'auth-expired' | 'permission-denied' | 'rate-limited' | 'not-found' | 'validation' | 'storage' | 'transport';
2
2
  export type GscError = {
3
3
  kind: 'auth-expired';
4
4
  message: string;
5
5
  cause: unknown;
6
+ } | {
7
+ kind: 'permission-denied';
8
+ message: string;
9
+ cause: unknown;
6
10
  } | {
7
11
  kind: 'rate-limited';
8
12
  message: string;
@@ -25,7 +25,6 @@ function extractStatus(error) {
25
25
  function extractMessage(error) {
26
26
  if (!error) return "Unknown error";
27
27
  if (typeof error === "string") return error;
28
- if (error instanceof Error) return error.message;
29
28
  if (typeof error !== "object") return String(error);
30
29
  return pickField(error, [
31
30
  [
@@ -33,6 +32,7 @@ function extractMessage(error) {
33
32
  "error",
34
33
  "message"
35
34
  ],
35
+ ["data", "error_description"],
36
36
  ["message"],
37
37
  ["statusMessage"]
38
38
  ], isString) ?? String(error);
@@ -59,7 +59,7 @@ function extractRetryAfter(error) {
59
59
  return Number.isNaN(seconds) ? void 0 : seconds;
60
60
  }
61
61
  }
62
- const QUOTA_MESSAGE_RE = /quota|rate\s*limit/i;
62
+ const QUOTA_MESSAGE_RE = /quota|rate\s*limit|\bqps\b/i;
63
63
  const QUOTA_REASONS = /* @__PURE__ */ new Set([
64
64
  "dailyLimitExceeded",
65
65
  "dailyLimitExceededUnreg",
@@ -120,7 +120,7 @@ function classifyError(cause) {
120
120
  cause
121
121
  };
122
122
  return {
123
- kind: "auth-expired",
123
+ kind: "permission-denied",
124
124
  message,
125
125
  cause
126
126
  };
@@ -8,8 +8,13 @@ export declare const GSC_FINALIZED_LAG_DAYS = 3;
8
8
  export declare const GSC_FRESHEST_LAG_DAYS = 1;
9
9
  /** Approximate historical retention window for Search Analytics. */
10
10
  export declare const GSC_RETENTION_MONTHS = 16;
11
- /** Today's date (YYYY-MM-DD) in PST. */
12
- export declare function getPstDate(): string;
11
+ /** Today's date (YYYY-MM-DD) in PST, whatever the machine's time zone. */
12
+ export declare function getPstDate(now?: Date): string;
13
+ /**
14
+ * Start of the next PST reporting day, in epoch milliseconds. Google resets
15
+ * its daily quotas then.
16
+ */
17
+ export declare function getNextPstMidnight(now?: Date): number;
13
18
  /** YYYY-MM-DD for `now() - n` days, UTC. */
14
19
  export declare function daysAgo(n: number): string;
15
20
  /** Most recent finalized date (3 days ago PST). */
@@ -5,13 +5,28 @@ function toIsoDate(d) {
5
5
  const GSC_FINALIZED_LAG_DAYS = 3;
6
6
  const GSC_FRESHEST_LAG_DAYS = 1;
7
7
  const GSC_RETENTION_MONTHS = 16;
8
- function getPstDate() {
9
- return (/* @__PURE__ */ new Date()).toLocaleDateString("en-CA", { timeZone: "America/Los_Angeles" });
8
+ let pstFormatter;
9
+ function getPstDate(now = /* @__PURE__ */ new Date()) {
10
+ pstFormatter ??= new Intl.DateTimeFormat("en-CA", {
11
+ timeZone: "America/Los_Angeles",
12
+ year: "numeric",
13
+ month: "2-digit",
14
+ day: "2-digit"
15
+ });
16
+ const parts = pstFormatter.formatToParts(now);
17
+ const get = (type) => parts.find((part) => part.type === type).value;
18
+ return `${get("year")}-${get("month")}-${get("day")}`;
10
19
  }
11
20
  function getPstDateDaysAgo(daysAgo) {
12
- const pstNow = new Date((/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: "America/Los_Angeles" }));
13
- pstNow.setDate(pstNow.getDate() - daysAgo);
14
- return toIsoDate(pstNow);
21
+ return addDays(getPstDate(), -daysAgo);
22
+ }
23
+ function getNextPstMidnight(now = /* @__PURE__ */ new Date()) {
24
+ const tomorrow = addDays(getPstDate(now), 1);
25
+ for (const offsetHours of [7, 8]) {
26
+ const at = Date.parse(`${tomorrow}T00:00:00Z`) + offsetHours * 36e5;
27
+ if (getPstDate(new Date(at)) === tomorrow && getPstDate(/* @__PURE__ */ new Date(at - 1)) !== tomorrow) return at;
28
+ }
29
+ return Date.parse(`${tomorrow}T08:00:00Z`);
15
30
  }
16
31
  function daysAgo(n) {
17
32
  return toIsoDate(/* @__PURE__ */ new Date(Date.now() - n * MS_PER_DAY));
@@ -68,8 +83,8 @@ function countDays(startDate, endDate) {
68
83
  return Math.round((Date.parse(`${endDate}T00:00:00Z`) - Date.parse(`${startDate}T00:00:00Z`)) / MS_PER_DAY) + 1;
69
84
  }
70
85
  function getOldestGscDate() {
71
- const date = /* @__PURE__ */ new Date();
72
- date.setMonth(date.getMonth() - 16);
86
+ const date = /* @__PURE__ */ new Date(`${getPstDate()}T00:00:00Z`);
87
+ date.setUTCMonth(date.getUTCMonth() - 16);
73
88
  return toIsoDate(date);
74
89
  }
75
90
  function addDays(dateStr, n) {
@@ -97,4 +112,4 @@ function getBackfillProgress(oldestDateSynced, newestDateSynced) {
97
112
  isComplete: oldestDateSynced <= oldestGsc
98
113
  };
99
114
  }
100
- export { DAYS_PER_RANGE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_RETENTION_MONTHS, MS_PER_DAY, addDays, countDays, daysAgo, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getLatestGscDate, getNextDate, getOldestGscDate, getPendingDates, getPreviousDate, getPstDate, groupIntoRanges, isValidGscDate, toIsoDate };
115
+ export { DAYS_PER_RANGE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_RETENTION_MONTHS, MS_PER_DAY, addDays, countDays, daysAgo, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getLatestGscDate, getNextDate, getNextPstMidnight, getOldestGscDate, getPendingDates, getPreviousDate, getPstDate, groupIntoRanges, isValidGscDate, toIsoDate };
@@ -37,4 +37,44 @@ export declare function findBestGscProperty<T extends GscPropertyCandidate>(targ
37
37
  urlProperty: T | null;
38
38
  };
39
39
  export declare function findExactGscProperty<T extends GscPropertyCandidate>(propertyUrl: string, properties: readonly T[]): T | null;
40
- export declare function formatGscPropertyCandidates(candidates: ReadonlyArray<GscPropertyCandidate | null | undefined>): string;
40
+ export declare function formatGscPropertyCandidates(candidates: ReadonlyArray<GscPropertyCandidate | null | undefined>): string;
41
+ /** One Site the resolver may pick. `inStore` marks a Site with local data. */
42
+ export interface SiteCandidate {
43
+ siteUrl: string;
44
+ inStore?: boolean;
45
+ }
46
+ /**
47
+ * Outcome of matching user input to a Site. `covered-by-parent` means a
48
+ * domain property covers the input, but the input names a narrower scope
49
+ * (a subdomain or a path). Callers must never swap one for the other
50
+ * silently: the parent Site holds more data than the input asked for.
51
+ */
52
+ export type SiteResolution = {
53
+ kind: 'resolved';
54
+ siteUrl: string;
55
+ via: 'exact' | 'host';
56
+ } | {
57
+ kind: 'ambiguous';
58
+ input: string;
59
+ candidates: string[];
60
+ } | {
61
+ kind: 'covered-by-parent';
62
+ input: string;
63
+ parent: string;
64
+ } | {
65
+ kind: 'not-found';
66
+ input: string;
67
+ known: string[];
68
+ };
69
+ /**
70
+ * Resolve what a person typed for `--site` to one Site from `candidates`.
71
+ *
72
+ * - An exact Site URL match wins, ignoring case and a trailing slash.
73
+ * - Otherwise the input matches on its Site root: scheme, `www.`, case and
74
+ * a trailing slash are ignored. Hosts compare whole, never as substrings.
75
+ * - Among several root matches, a Site with Store data wins, then a domain
76
+ * property, then the one whose `www.` matches the input, then HTTPS.
77
+ * - A domain property that only covers the input (a subdomain or a path)
78
+ * returns `covered-by-parent`.
79
+ */
80
+ export declare function resolveSiteInput(input: string, candidates: readonly SiteCandidate[]): SiteResolution;
@@ -71,4 +71,129 @@ function findExactGscProperty(propertyUrl, properties) {
71
71
  function formatGscPropertyCandidates(candidates) {
72
72
  return candidates.filter((c) => !!c).map((property) => `${property.siteUrl} (${property.permissionLevel})`).join(", ");
73
73
  }
74
- export { findBestGscProperty, findExactGscProperty, formatGscPropertyCandidates, gscPropertyMatchesTarget, isVerifiedGscPermission, isVerifiedGscProperty, matchGscSite, pickBestGscProperty };
74
+ const INPUT_SCHEME_RE = /^[a-z][\w+.-]*:\/\//i;
75
+ const SC_DOMAIN_PREFIX_RE = /^sc-domain:/i;
76
+ const TRAILING_SLASHES_RE = /\/+$/;
77
+ function parseSiteKey(value) {
78
+ const trimmed = value.trim();
79
+ if (!trimmed) return null;
80
+ if (SC_DOMAIN_PREFIX_RE.test(trimmed)) {
81
+ const host = trimmed.replace(SC_DOMAIN_PREFIX_RE, "").replace(TRAILING_SLASHES_RE, "").toLowerCase();
82
+ return host ? {
83
+ host,
84
+ bareHost: stripWww(host),
85
+ path: "",
86
+ domain: true,
87
+ https: false
88
+ } : null;
89
+ }
90
+ const https = /^https:\/\//i.test(trimmed);
91
+ const rest = trimmed.replace(INPUT_SCHEME_RE, "").split(/[?#]/)[0];
92
+ const slash = rest.indexOf("/");
93
+ const host = (slash === -1 ? rest : rest.slice(0, slash)).toLowerCase();
94
+ if (!host) return null;
95
+ const path = slash === -1 ? "" : rest.slice(slash).replace(TRAILING_SLASHES_RE, "").toLowerCase();
96
+ return {
97
+ host,
98
+ bareHost: stripWww(host),
99
+ path,
100
+ domain: false,
101
+ https
102
+ };
103
+ }
104
+ function sameSiteUrl(a, b) {
105
+ const normalize = (value) => value.trim().replace(TRAILING_SLASHES_RE, "").toLowerCase();
106
+ return normalize(a) === normalize(b);
107
+ }
108
+ function resolveSiteInput(input, candidates) {
109
+ const unique = /* @__PURE__ */ new Map();
110
+ for (const candidate of candidates) {
111
+ const prior = unique.get(candidate.siteUrl);
112
+ unique.set(candidate.siteUrl, {
113
+ siteUrl: candidate.siteUrl,
114
+ inStore: !!(prior?.inStore || candidate.inStore)
115
+ });
116
+ }
117
+ const pool = [...unique.values()];
118
+ const known = pool.map((candidate) => candidate.siteUrl);
119
+ const exact = pool.filter((candidate) => sameSiteUrl(candidate.siteUrl, input));
120
+ if (exact.length === 1) return {
121
+ kind: "resolved",
122
+ siteUrl: exact[0].siteUrl,
123
+ via: "exact"
124
+ };
125
+ if (exact.length > 1) {
126
+ const verbatim = exact.find((candidate) => candidate.siteUrl === input.trim());
127
+ return verbatim ? {
128
+ kind: "resolved",
129
+ siteUrl: verbatim.siteUrl,
130
+ via: "exact"
131
+ } : {
132
+ kind: "ambiguous",
133
+ input,
134
+ candidates: exact.map((candidate) => candidate.siteUrl)
135
+ };
136
+ }
137
+ const key = parseSiteKey(input);
138
+ if (!key) return {
139
+ kind: "not-found",
140
+ input,
141
+ known
142
+ };
143
+ const keyed = pool.flatMap((candidate) => {
144
+ const candidateKey = parseSiteKey(candidate.siteUrl);
145
+ return candidateKey ? [{
146
+ candidate,
147
+ key: candidateKey
148
+ }] : [];
149
+ });
150
+ const matches = keyed.filter((entry) => entry.key.bareHost === key.bareHost && entry.key.path === key.path);
151
+ if (matches.length > 0) {
152
+ const ranked = narrow(matches, [
153
+ (entry) => !!entry.candidate.inStore,
154
+ (entry) => entry.key.domain,
155
+ (entry) => entry.key.host === key.host,
156
+ (entry) => entry.key.https
157
+ ]);
158
+ return ranked.length === 1 ? {
159
+ kind: "resolved",
160
+ siteUrl: ranked[0].candidate.siteUrl,
161
+ via: "host"
162
+ } : {
163
+ kind: "ambiguous",
164
+ input,
165
+ candidates: ranked.map((entry) => entry.candidate.siteUrl)
166
+ };
167
+ }
168
+ const parents = keyed.filter((entry) => entry.key.bareHost === key.bareHost && entry.key.path !== "" && key.path.startsWith(`${entry.key.path}/`) || entry.key.bareHost === key.bareHost && entry.key.path === "" || entry.key.domain && key.bareHost.endsWith(`.${entry.key.bareHost}`));
169
+ if (parents.length > 0) {
170
+ const specificity = (entry) => entry.key.bareHost.length + entry.key.path.length;
171
+ const closest = Math.max(...parents.map(specificity));
172
+ const [parent] = narrow(parents.filter((entry) => specificity(entry) === closest), [
173
+ (entry) => !!entry.candidate.inStore,
174
+ (entry) => entry.key.domain,
175
+ (entry) => entry.key.host === key.host,
176
+ (entry) => entry.key.https
177
+ ]);
178
+ return {
179
+ kind: "covered-by-parent",
180
+ input,
181
+ parent: parent.candidate.siteUrl
182
+ };
183
+ }
184
+ return {
185
+ kind: "not-found",
186
+ input,
187
+ known
188
+ };
189
+ }
190
+ function narrow(entries, rules) {
191
+ let pool = [...entries];
192
+ for (const rule of rules) {
193
+ const kept = pool.filter(rule);
194
+ if (kept.length > 0) pool = kept;
195
+ if (pool.length === 1) break;
196
+ }
197
+ return pool;
198
+ }
199
+ export { findBestGscProperty, findExactGscProperty, formatGscPropertyCandidates, gscPropertyMatchesTarget, isVerifiedGscPermission, isVerifiedGscProperty, matchGscSite, pickBestGscProperty, resolveSiteInput };
@@ -1,12 +1,26 @@
1
- export type WindowPreset = 'last-7d' | 'last-28d' | 'last-30d' | 'last-90d' | 'last-180d' | 'last-365d' | 'mtd' | 'ytd' | 'custom';
1
+ export type WindowPreset = 'last-7d' | 'last-28d' | 'last-30d' | 'last-90d' | 'last-180d' | 'last-365d' | 'mtd' | 'qtd' | 'ytd' | 'last-quarter' | 'custom';
2
+ /**
3
+ * `yoy` shifts the window back 364 days (52 weeks), so each day compares
4
+ * against the same weekday one year earlier. Search traffic has a strong
5
+ * weekly cycle, so a 365-day shift would compare Mondays with Sundays.
6
+ */
2
7
  export type ComparisonMode = 'none' | 'prev-period' | 'yoy';
3
- export interface ResolveWindowOptions {
4
- preset: WindowPreset;
8
+ /**
9
+ * `anchor` is the last day the window may include: the newest complete date
10
+ * in the data, never the wall clock. Callers pass the Store's newest synced
11
+ * date, or `getLatestGscDate()` for live reads. Custom windows take explicit
12
+ * bounds and need no anchor.
13
+ */
14
+ export type ResolveWindowOptions = {
15
+ preset: Exclude<WindowPreset, 'custom'>;
16
+ anchor: string;
5
17
  comparison?: ComparisonMode;
6
- anchor?: string;
7
- start?: string;
8
- end?: string;
9
- }
18
+ } | {
19
+ preset: 'custom';
20
+ start: string;
21
+ end: string;
22
+ comparison?: ComparisonMode;
23
+ };
10
24
  export interface ResolvedWindow {
11
25
  start: string;
12
26
  end: string;
@@ -16,4 +30,5 @@ export interface ResolvedWindow {
16
30
  end: string;
17
31
  };
18
32
  }
33
+ /** Pure: the same options always resolve to the same window. */
19
34
  export declare function resolveWindow(opts: ResolveWindowOptions): ResolvedWindow;
@@ -1,46 +1,57 @@
1
1
  import { addDays, countDays, toIsoDate } from "./gsc-dates.mjs";
2
+ const ROLLING_DAYS = {
3
+ "last-7d": 7,
4
+ "last-28d": 28,
5
+ "last-30d": 30,
6
+ "last-90d": 90,
7
+ "last-180d": 180,
8
+ "last-365d": 365
9
+ };
10
+ function presetBounds(preset, anchorIso) {
11
+ const rolling = ROLLING_DAYS[preset];
12
+ if (rolling) return {
13
+ start: addDays(anchorIso, -(rolling - 1)),
14
+ end: anchorIso
15
+ };
16
+ const anchor = /* @__PURE__ */ new Date(`${anchorIso}T00:00:00Z`);
17
+ const year = anchor.getUTCFullYear();
18
+ const quarterStartMonth = Math.floor(anchor.getUTCMonth() / 3) * 3;
19
+ switch (preset) {
20
+ case "mtd": return {
21
+ start: toIsoDate(new Date(Date.UTC(year, anchor.getUTCMonth(), 1))),
22
+ end: anchorIso
23
+ };
24
+ case "qtd": return {
25
+ start: toIsoDate(new Date(Date.UTC(year, quarterStartMonth, 1))),
26
+ end: anchorIso
27
+ };
28
+ case "ytd": return {
29
+ start: toIsoDate(new Date(Date.UTC(year, 0, 1))),
30
+ end: anchorIso
31
+ };
32
+ case "last-quarter": {
33
+ const nextQuarterStart = new Date(Date.UTC(year, quarterStartMonth + 3, 1));
34
+ const startMonth = addDays(toIsoDate(nextQuarterStart), -1) === anchorIso ? quarterStartMonth : quarterStartMonth - 3;
35
+ return {
36
+ start: toIsoDate(new Date(Date.UTC(year, startMonth, 1))),
37
+ end: addDays(toIsoDate(new Date(Date.UTC(year, startMonth + 3, 1))), -1)
38
+ };
39
+ }
40
+ default: throw new Error(`resolveWindow: unknown preset ${preset}`);
41
+ }
42
+ }
2
43
  function resolveWindow(opts) {
3
- const anchor = opts.anchor ? /* @__PURE__ */ new Date(`${opts.anchor}T00:00:00Z`) : /* @__PURE__ */ new Date();
4
- const anchorIso = toIsoDate(anchor);
5
44
  let start;
6
45
  let end;
7
- switch (opts.preset) {
8
- case "last-7d":
9
- end = anchorIso;
10
- start = addDays(anchorIso, -6);
11
- break;
12
- case "last-28d":
13
- end = anchorIso;
14
- start = addDays(anchorIso, -27);
15
- break;
16
- case "last-30d":
17
- end = anchorIso;
18
- start = addDays(anchorIso, -29);
19
- break;
20
- case "last-90d":
21
- end = anchorIso;
22
- start = addDays(anchorIso, -89);
23
- break;
24
- case "last-180d":
25
- end = anchorIso;
26
- start = addDays(anchorIso, -179);
27
- break;
28
- case "last-365d":
29
- end = anchorIso;
30
- start = addDays(anchorIso, -364);
31
- break;
32
- case "mtd":
33
- end = anchorIso;
34
- start = toIsoDate(new Date(Date.UTC(anchor.getUTCFullYear(), anchor.getUTCMonth(), 1)));
35
- break;
36
- case "ytd":
37
- end = anchorIso;
38
- start = toIsoDate(new Date(Date.UTC(anchor.getUTCFullYear(), 0, 1)));
39
- break;
40
- case "custom":
41
- if (!opts.start || !opts.end) throw new Error("resolveWindow: preset=custom requires start and end");
42
- start = opts.start;
43
- end = opts.end;
46
+ if (opts.preset === "custom") {
47
+ if (!opts.start || !opts.end) throw new Error("resolveWindow: preset=custom requires start and end");
48
+ start = opts.start;
49
+ end = opts.end;
50
+ } else {
51
+ if (!opts.anchor) throw new Error(`resolveWindow: preset=${opts.preset} requires an anchor date`);
52
+ const bounds = presetBounds(opts.preset, opts.anchor);
53
+ start = bounds.start;
54
+ end = bounds.end;
44
55
  }
45
56
  const days = countDays(start, end);
46
57
  const result = {
@@ -55,8 +66,8 @@ function resolveWindow(opts) {
55
66
  end: previousEnd
56
67
  };
57
68
  } else if (opts.comparison === "yoy") result.comparison = {
58
- start: addDays(start, -365),
59
- end: addDays(end, -365)
69
+ start: addDays(start, -364),
70
+ end: addDays(end, -364)
60
71
  };
61
72
  return result;
62
73
  }
package/dist/dates.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Period, ResolvedAnalyticsRange } from "./core/types.mjs";
2
- import { DAYS_PER_RANGE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_RETENTION_MONTHS, MS_PER_DAY, addDays, countDays, daysAgo, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getLatestGscDate, getNextDate, getOldestGscDate, getPendingDates, getPstDate, groupIntoRanges, toIsoDate } from "./core/gsc-dates.mjs";
2
+ import { DAYS_PER_RANGE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_RETENTION_MONTHS, MS_PER_DAY, addDays, countDays, daysAgo, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getLatestGscDate, getNextDate, getNextPstMidnight, getOldestGscDate, getPendingDates, getPstDate, groupIntoRanges, toIsoDate } from "./core/gsc-dates.mjs";
3
3
  import { ComparisonMode, ResolveWindowOptions, ResolvedWindow, WindowPreset, resolveWindow } from "./core/window.mjs";
4
4
  import { currentPstDate, daysAgoPst } from "./query/utils/dayjs.mjs";
5
- export { type ComparisonMode, DAYS_PER_RANGE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_RETENTION_MONTHS, MS_PER_DAY, type Period, type ResolveWindowOptions, type ResolvedAnalyticsRange, type ResolvedWindow, type WindowPreset, addDays, countDays, currentPstDate, daysAgoPst, daysAgo as daysAgoUtc, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getLatestGscDate, getNextDate, getOldestGscDate, getPendingDates, getPstDate, groupIntoRanges, resolveWindow, toIsoDate };
5
+ export { type ComparisonMode, DAYS_PER_RANGE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_RETENTION_MONTHS, MS_PER_DAY, type Period, type ResolveWindowOptions, type ResolvedAnalyticsRange, type ResolvedWindow, type WindowPreset, addDays, countDays, currentPstDate, daysAgoPst, daysAgo as daysAgoUtc, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getLatestGscDate, getNextDate, getNextPstMidnight, getOldestGscDate, getPendingDates, getPstDate, groupIntoRanges, resolveWindow, toIsoDate };
package/dist/dates.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { DAYS_PER_RANGE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_RETENTION_MONTHS, MS_PER_DAY, addDays, countDays, daysAgo, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getLatestGscDate, getNextDate, getOldestGscDate, getPendingDates, getPstDate, groupIntoRanges, toIsoDate } from "./core/gsc-dates.mjs";
1
+ import { DAYS_PER_RANGE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_RETENTION_MONTHS, MS_PER_DAY, addDays, countDays, daysAgo, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getLatestGscDate, getNextDate, getNextPstMidnight, getOldestGscDate, getPendingDates, getPstDate, groupIntoRanges, toIsoDate } from "./core/gsc-dates.mjs";
2
2
  import { currentPstDate, daysAgoPst } from "./query/utils/dayjs.mjs";
3
3
  import { resolveWindow } from "./core/window.mjs";
4
- export { DAYS_PER_RANGE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_RETENTION_MONTHS, MS_PER_DAY, addDays, countDays, currentPstDate, daysAgoPst, daysAgo as daysAgoUtc, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getLatestGscDate, getNextDate, getOldestGscDate, getPendingDates, getPstDate, groupIntoRanges, resolveWindow, toIsoDate };
4
+ export { DAYS_PER_RANGE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_RETENTION_MONTHS, MS_PER_DAY, addDays, countDays, currentPstDate, daysAgoPst, daysAgo as daysAgoUtc, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getLatestGscDate, getNextDate, getNextPstMidnight, getOldestGscDate, getPendingDates, getPstDate, groupIntoRanges, resolveWindow, toIsoDate };
package/dist/index.d.mts CHANGED
@@ -7,17 +7,17 @@ import { BackfillProgress, DAYS_PER_RANGE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_
7
7
  import { GscApiError, GscApiErrorInfo, GscError, GscErrorKind, classifyError, gscErrorToException, isPermissionDeniedError, parseGoogleError, rethrowAsGscApiError } from "./core/errors.mjs";
8
8
  import { runSequentialBatch } from "./api/batch.mjs";
9
9
  import { IndexingMetadata, IndexingNotificationType, IndexingResult, batchRequestIndexing, getIndexingMetadata, requestIndexing } from "./api/indexing.mjs";
10
- import { BatchInspectUrlsFlatSettledOptions, IndexingEligibility, IndexingIneligibleReason, InspectUrlFlatSettledResult, InspectUrlResult, InspectionPriority, LegacyInspectionPriority, MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, ParsedIndexingResult, ValueWeightedInspectionPriority, batchInspectUrls, batchInspectUrlsFlatSettled, canUseUrlInspection, getIndexingEligibility, getNextCheckAfter, getNextCheckPriority, inspectUrl, inspectUrlFlat } from "./api/inspection.mjs";
10
+ import { BatchInspectUrlsFlatSettledOptions, IndexingEligibility, IndexingIneligibleReason, InspectUrlFlatSettledResult, InspectUrlResult, InspectionPriority, LegacyInspectionPriority, MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, ParsedIndexingResult, URL_INSPECTION_QUOTA, ValueWeightedInspectionPriority, batchInspectUrls, batchInspectUrlsFlatSettled, canUseUrlInspection, describeInspectionError, getIndexingEligibility, getNextCheckAfter, getNextCheckPriority, inspectUrl, inspectUrlFlat } from "./api/inspection.mjs";
11
11
  import { OAuthTokenInfo, OAuthTokens, exchangeAuthCodeResult, introspectAccessToken, introspectAccessTokenResult, refreshAccessToken, revokeOAuthToken, revokeOAuthTokenResult } from "./api/oauth.mjs";
12
12
  import { FetchSitesWithSitemapsOptions, addSite, deleteSite, deleteSitemap, fetchSitemap, fetchSitemaps, fetchSites, fetchSitesWithSitemaps, submitSitemap } from "./api/sites.mjs";
13
13
  import { getVerificationToken, getVerifiedSite, listVerifiedSites, resolveVerificationTarget, siteUrlToVerificationSite, unverifySite, verificationMethodsFor, verifySite } from "./api/verification.mjs";
14
14
  import { CanonicalDifferenceKind, classifyCanonicalDifference, isCanonicalMismatch } from "./core/canonical.mjs";
15
15
  import { INDEXING_ISSUE_FILTERS, INDEXING_ISSUE_LABELS, INDEXING_ISSUE_SEVERITY, IndexingIssueType, KNOWN_COVERAGE_STATES, KNOWN_PAGE_FETCH_STATES, UnmappedInspectionReasons, isFragmentUrl, unmappedInspectionReasons } from "./core/indexing-issues.mjs";
16
- import { GscPropertyCandidate, findBestGscProperty, findExactGscProperty, formatGscPropertyCandidates, gscPropertyMatchesTarget, isVerifiedGscPermission, isVerifiedGscProperty, matchGscSite, pickBestGscProperty } from "./core/property.mjs";
16
+ import { GscPropertyCandidate, SiteCandidate, SiteResolution, findBestGscProperty, findExactGscProperty, formatGscPropertyCandidates, gscPropertyMatchesTarget, isVerifiedGscPermission, isVerifiedGscProperty, matchGscSite, pickBestGscProperty, resolveSiteInput } from "./core/property.mjs";
17
17
  import { URL_INSPECTION_EFFECTIVE_LIMIT } from "./core/quota.mjs";
18
18
  import { ParsedGscSiteUrl, normalizeGscSiteUrl, normalizeRegistrationTarget, parseGscSiteUrl } from "./core/site-url.mjs";
19
19
  import { normalizeUrl } from "./normalize.mjs";
20
20
  import { AccountNextAction, AccountStatus, AnalyticsNextAction, AnalyticsStatus, GSCDUMP_ONBOARDING_CONTRACT_VERSION, GSCDUMP_OPTIONAL_INDEXING_SCOPE, GSCDUMP_REQUIRED_ANALYTICS_SCOPE, GSCDUMP_WRITE_ANALYTICS_SCOPE, IndexingNextAction, IndexingStatus, LifecycleError, LifecycleErrorCode, LifecycleProgress, LifecycleWebhookEnvelope, LifecycleWebhookEvent, PartnerLifecycleAccount, PartnerLifecycleResponse, PartnerLifecycleSite, PropertyNextAction, PropertyStatus, QuerySourceMode, SitemapNextAction, SitemapStatus, accountNextActions, accountStatuses, analyticsNextActions, analyticsStatuses, hasOptionalIndexingScope, hasRequiredAnalyticsScope, indexingNextActions, indexingStatuses, lifecycleErrorCodes, parseGrantedScopes, propertyNextActions, propertyStatuses, querySourceModes, sitemapNextActions, sitemapStatuses } from "./onboarding.mjs";
21
21
  import { decodeSiteId, encodeSiteId, normalizeSiteUrl } from "./tenant.mjs";
22
22
  import { urlMatchKey } from "./url.mjs";
23
- export { type AccountNextAction, type AccountStatus, AmpInspectionResult, AmpIssue, type AnalyticsNextAction, type AnalyticsStatus, ApiSite, ApiSitemap, ApiSitemapContent, Auth, AuthClient, AuthOptions, type BackfillProgress, BatchInspectUrlsFlatSettledOptions, CallOptions, CanonicalDifferenceKind, DAYS_PER_RANGE, DEFAULT_GSC_REQUEST_TIMEOUT_MS, DataRow, DimensionFilter, DimensionFilterGroup, Err, FetchSitesWithSitemapsOptions, GSCDUMP_ONBOARDING_CONTRACT_VERSION, GSCDUMP_OPTIONAL_INDEXING_SCOPE, GSCDUMP_REQUIRED_ANALYTICS_SCOPE, GSCDUMP_WRITE_ANALYTICS_SCOPE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_INDEXING_SCOPE, GSC_READ_SCOPE, GSC_RETENTION_MONTHS, GSC_SITE_VERIFICATION_SCOPE, GSC_WRITE_SCOPE, GoogleSearchConsoleClient, GoogleSearchConsoleClientOptions, GscApiError, type GscApiErrorInfo, type GscError, type GscErrorKind, GscPropertyCandidate, INDEXING_ISSUE_FILTERS, INDEXING_ISSUE_LABELS, INDEXING_ISSUE_SEVERITY, IndexStatusResult, IndexingEligibility, IndexingIneligibleReason, IndexingIssueType, IndexingMetadata, type IndexingNextAction, IndexingNotificationType, IndexingResult, type IndexingStatus, InspectUrlFlatSettledResult, InspectUrlIndexResponse, InspectUrlResult, InspectionPriority, KNOWN_COVERAGE_STATES, KNOWN_PAGE_FETCH_STATES, LegacyInspectionPriority, type LifecycleError, type LifecycleErrorCode, type LifecycleProgress, type LifecycleWebhookEnvelope, type LifecycleWebhookEvent, MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, MS_PER_DAY, MobileUsabilityIssue, MobileUsabilityResult, OAuthTokenInfo, OAuthTokens, Ok, ParsedGscSiteUrl, ParsedIndexingResult, type PartnerLifecycleAccount, type PartnerLifecycleResponse, type PartnerLifecycleSite, Period, type PropertyNextAction, type PropertyStatus, PublishUrlNotificationResponse, QueryReturn, type QuerySourceMode, RequiredNonNullable, ResolvedAnalyticsRange, Result, RichResultsDetectedItem, RichResultsIssue, RichResultsItem, RichResultsResult, SearchAnalyticsMetadata, SearchAnalyticsQuery, SearchAnalyticsResponse, Site, SiteAnalytics, type SitemapNextAction, type SitemapStatus, URL_INSPECTION_EFFECTIVE_LIMIT, UnmappedInspectionReasons, UrlInspectionResult, UrlNotification, UrlNotificationMetadata, ValueWeightedInspectionPriority, VerificationMethod, VerificationSite, VerificationSiteType, VerificationToken, VerificationWebResource, accountNextActions, accountStatuses, addDays, addSite, analyticsNextActions, analyticsStatuses, batchInspectUrls, batchInspectUrlsFlatSettled, batchRequestIndexing, canUseUrlInspection, classifyCanonicalDifference, classifyError, countDays, createAuth, createFetch, decodeSiteId, deleteSite, deleteSitemap, encodeSiteId, err, exchangeAuthCodeResult, fetchSitemap, fetchSitemaps, fetchSites, fetchSitesWithSitemaps, findBestGscProperty, findExactGscProperty, formatGscPropertyCandidates, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getIndexingEligibility, getIndexingMetadata, getLatestGscDate, getNextCheckAfter, getNextCheckPriority, getNextDate, getOldestGscDate, getPendingDates, getPreviousDate, getPstDate, getVerificationToken, getVerifiedSite, googleSearchConsole, groupIntoRanges, gscErrorToException, gscPropertyMatchesTarget, hasGoogleScope, hasGscReadScope, hasGscWriteScope, hasIndexingScope, hasOptionalIndexingScope, hasRequiredAnalyticsScope, indexingNextActions, indexingStatuses, inspectUrl, inspectUrlFlat, introspectAccessToken, introspectAccessTokenResult, isCanonicalMismatch, isErr, isFragmentUrl, isOk, isPermissionDeniedError, isValidGscDate, isVerifiedGscPermission, isVerifiedGscProperty, lifecycleErrorCodes, listVerifiedSites, matchGscSite, normalizeGscSiteUrl, normalizeRegistrationTarget, normalizeSiteUrl, normalizeUrl, ok, parseGoogleError, parseGrantedScopes, parseGscSiteUrl, pickBestGscProperty, propertyNextActions, propertyStatuses, querySourceModes, refreshAccessToken, requestIndexing, resolveVerificationTarget, rethrowAsGscApiError, revokeOAuthToken, revokeOAuthTokenResult, runSequentialBatch, siteUrlToVerificationSite, sitemapNextActions, sitemapStatuses, submitSitemap, toIsoDate, unmappedInspectionReasons, unverifySite, unwrapResult, urlMatchKey, verificationMethodsFor, verifySite };
23
+ export { type AccountNextAction, type AccountStatus, AmpInspectionResult, AmpIssue, type AnalyticsNextAction, type AnalyticsStatus, ApiSite, ApiSitemap, ApiSitemapContent, Auth, AuthClient, AuthOptions, type BackfillProgress, BatchInspectUrlsFlatSettledOptions, CallOptions, CanonicalDifferenceKind, DAYS_PER_RANGE, DEFAULT_GSC_REQUEST_TIMEOUT_MS, DataRow, DimensionFilter, DimensionFilterGroup, Err, FetchSitesWithSitemapsOptions, GSCDUMP_ONBOARDING_CONTRACT_VERSION, GSCDUMP_OPTIONAL_INDEXING_SCOPE, GSCDUMP_REQUIRED_ANALYTICS_SCOPE, GSCDUMP_WRITE_ANALYTICS_SCOPE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_INDEXING_SCOPE, GSC_READ_SCOPE, GSC_RETENTION_MONTHS, GSC_SITE_VERIFICATION_SCOPE, GSC_WRITE_SCOPE, GoogleSearchConsoleClient, GoogleSearchConsoleClientOptions, GscApiError, type GscApiErrorInfo, type GscError, type GscErrorKind, GscPropertyCandidate, INDEXING_ISSUE_FILTERS, INDEXING_ISSUE_LABELS, INDEXING_ISSUE_SEVERITY, IndexStatusResult, IndexingEligibility, IndexingIneligibleReason, IndexingIssueType, IndexingMetadata, type IndexingNextAction, IndexingNotificationType, IndexingResult, type IndexingStatus, InspectUrlFlatSettledResult, InspectUrlIndexResponse, InspectUrlResult, InspectionPriority, KNOWN_COVERAGE_STATES, KNOWN_PAGE_FETCH_STATES, LegacyInspectionPriority, type LifecycleError, type LifecycleErrorCode, type LifecycleProgress, type LifecycleWebhookEnvelope, type LifecycleWebhookEvent, MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, MS_PER_DAY, MobileUsabilityIssue, MobileUsabilityResult, OAuthTokenInfo, OAuthTokens, Ok, ParsedGscSiteUrl, ParsedIndexingResult, type PartnerLifecycleAccount, type PartnerLifecycleResponse, type PartnerLifecycleSite, Period, type PropertyNextAction, type PropertyStatus, PublishUrlNotificationResponse, QueryReturn, type QuerySourceMode, RequiredNonNullable, ResolvedAnalyticsRange, Result, RichResultsDetectedItem, RichResultsIssue, RichResultsItem, RichResultsResult, SearchAnalyticsMetadata, SearchAnalyticsQuery, SearchAnalyticsResponse, Site, SiteAnalytics, SiteCandidate, SiteResolution, type SitemapNextAction, type SitemapStatus, URL_INSPECTION_EFFECTIVE_LIMIT, URL_INSPECTION_QUOTA, UnmappedInspectionReasons, UrlInspectionResult, UrlNotification, UrlNotificationMetadata, ValueWeightedInspectionPriority, VerificationMethod, VerificationSite, VerificationSiteType, VerificationToken, VerificationWebResource, accountNextActions, accountStatuses, addDays, addSite, analyticsNextActions, analyticsStatuses, batchInspectUrls, batchInspectUrlsFlatSettled, batchRequestIndexing, canUseUrlInspection, classifyCanonicalDifference, classifyError, countDays, createAuth, createFetch, decodeSiteId, deleteSite, deleteSitemap, describeInspectionError, encodeSiteId, err, exchangeAuthCodeResult, fetchSitemap, fetchSitemaps, fetchSites, fetchSitesWithSitemaps, findBestGscProperty, findExactGscProperty, formatGscPropertyCandidates, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getIndexingEligibility, getIndexingMetadata, getLatestGscDate, getNextCheckAfter, getNextCheckPriority, getNextDate, getOldestGscDate, getPendingDates, getPreviousDate, getPstDate, getVerificationToken, getVerifiedSite, googleSearchConsole, groupIntoRanges, gscErrorToException, gscPropertyMatchesTarget, hasGoogleScope, hasGscReadScope, hasGscWriteScope, hasIndexingScope, hasOptionalIndexingScope, hasRequiredAnalyticsScope, indexingNextActions, indexingStatuses, inspectUrl, inspectUrlFlat, introspectAccessToken, introspectAccessTokenResult, isCanonicalMismatch, isErr, isFragmentUrl, isOk, isPermissionDeniedError, isValidGscDate, isVerifiedGscPermission, isVerifiedGscProperty, lifecycleErrorCodes, listVerifiedSites, matchGscSite, normalizeGscSiteUrl, normalizeRegistrationTarget, normalizeSiteUrl, normalizeUrl, ok, parseGoogleError, parseGrantedScopes, parseGscSiteUrl, pickBestGscProperty, propertyNextActions, propertyStatuses, querySourceModes, refreshAccessToken, requestIndexing, resolveSiteInput, resolveVerificationTarget, rethrowAsGscApiError, revokeOAuthToken, revokeOAuthTokenResult, runSequentialBatch, siteUrlToVerificationSite, sitemapNextActions, sitemapStatuses, submitSitemap, toIsoDate, unmappedInspectionReasons, unverifySite, unwrapResult, urlMatchKey, verificationMethodsFor, verifySite };
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import { runSequentialBatch } from "./api/batch.mjs";
2
2
  import { batchRequestIndexing, getIndexingMetadata, requestIndexing } from "./api/indexing.mjs";
3
+ import { GscApiError, classifyError, gscErrorToException, isPermissionDeniedError, parseGoogleError, rethrowAsGscApiError } from "./core/errors.mjs";
3
4
  import { GSC_INDEXING_SCOPE, GSC_READ_SCOPE, GSC_SITE_VERIFICATION_SCOPE, GSC_WRITE_SCOPE, hasGoogleScope } from "./core/scope-values.mjs";
4
5
  import { hasGscReadScope, hasGscWriteScope, hasIndexingScope } from "./core/scopes.mjs";
5
- import { MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, batchInspectUrls, batchInspectUrlsFlatSettled, canUseUrlInspection, getIndexingEligibility, getNextCheckAfter, getNextCheckPriority, inspectUrl, inspectUrlFlat } from "./api/inspection.mjs";
6
- import { GscApiError, classifyError, gscErrorToException, isPermissionDeniedError, parseGoogleError, rethrowAsGscApiError } from "./core/errors.mjs";
6
+ import { MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, URL_INSPECTION_QUOTA, batchInspectUrls, batchInspectUrlsFlatSettled, canUseUrlInspection, describeInspectionError, getIndexingEligibility, getNextCheckAfter, getNextCheckPriority, inspectUrl, inspectUrlFlat } from "./api/inspection.mjs";
7
7
  import { err, isErr, isOk, ok, unwrapResult } from "./core/result.mjs";
8
8
  import { exchangeAuthCodeResult, introspectAccessToken, introspectAccessTokenResult, refreshAccessToken, revokeOAuthToken, revokeOAuthTokenResult } from "./api/oauth.mjs";
9
9
  import { addSite, deleteSite, deleteSitemap, fetchSitemap, fetchSitemaps, fetchSites, fetchSitesWithSitemaps, submitSitemap } from "./api/sites.mjs";
@@ -13,11 +13,11 @@ import { DAYS_PER_RANGE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_RETE
13
13
  import { DEFAULT_GSC_REQUEST_TIMEOUT_MS, createAuth, createFetch, googleSearchConsole } from "./core/client.mjs";
14
14
  import { INDEXING_ISSUE_FILTERS, INDEXING_ISSUE_LABELS, INDEXING_ISSUE_SEVERITY, KNOWN_COVERAGE_STATES, KNOWN_PAGE_FETCH_STATES, isFragmentUrl, unmappedInspectionReasons } from "./core/indexing-issues.mjs";
15
15
  import { normalizeGscSiteUrl, normalizeRegistrationTarget, parseGscSiteUrl } from "./core/site-url.mjs";
16
- import { findBestGscProperty, findExactGscProperty, formatGscPropertyCandidates, gscPropertyMatchesTarget, isVerifiedGscPermission, isVerifiedGscProperty, matchGscSite, pickBestGscProperty } from "./core/property.mjs";
16
+ import { findBestGscProperty, findExactGscProperty, formatGscPropertyCandidates, gscPropertyMatchesTarget, isVerifiedGscPermission, isVerifiedGscProperty, matchGscSite, pickBestGscProperty, resolveSiteInput } from "./core/property.mjs";
17
17
  import { URL_INSPECTION_EFFECTIVE_LIMIT } from "./core/quota.mjs";
18
18
  import "./core/types.mjs";
19
19
  import { normalizeUrl } from "./normalize.mjs";
20
20
  import { GSCDUMP_ONBOARDING_CONTRACT_VERSION, GSCDUMP_OPTIONAL_INDEXING_SCOPE, GSCDUMP_REQUIRED_ANALYTICS_SCOPE, GSCDUMP_WRITE_ANALYTICS_SCOPE, accountNextActions, accountStatuses, analyticsNextActions, analyticsStatuses, hasOptionalIndexingScope, hasRequiredAnalyticsScope, indexingNextActions, indexingStatuses, lifecycleErrorCodes, parseGrantedScopes, propertyNextActions, propertyStatuses, querySourceModes, sitemapNextActions, sitemapStatuses } from "./onboarding.mjs";
21
21
  import { decodeSiteId, encodeSiteId, normalizeSiteUrl } from "./tenant.mjs";
22
22
  import { urlMatchKey } from "./url.mjs";
23
- export { DAYS_PER_RANGE, DEFAULT_GSC_REQUEST_TIMEOUT_MS, GSCDUMP_ONBOARDING_CONTRACT_VERSION, GSCDUMP_OPTIONAL_INDEXING_SCOPE, GSCDUMP_REQUIRED_ANALYTICS_SCOPE, GSCDUMP_WRITE_ANALYTICS_SCOPE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_INDEXING_SCOPE, GSC_READ_SCOPE, GSC_RETENTION_MONTHS, GSC_SITE_VERIFICATION_SCOPE, GSC_WRITE_SCOPE, GscApiError, INDEXING_ISSUE_FILTERS, INDEXING_ISSUE_LABELS, INDEXING_ISSUE_SEVERITY, KNOWN_COVERAGE_STATES, KNOWN_PAGE_FETCH_STATES, MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, MS_PER_DAY, URL_INSPECTION_EFFECTIVE_LIMIT, accountNextActions, accountStatuses, addDays, addSite, analyticsNextActions, analyticsStatuses, batchInspectUrls, batchInspectUrlsFlatSettled, batchRequestIndexing, canUseUrlInspection, classifyCanonicalDifference, classifyError, countDays, createAuth, createFetch, decodeSiteId, deleteSite, deleteSitemap, encodeSiteId, err, exchangeAuthCodeResult, fetchSitemap, fetchSitemaps, fetchSites, fetchSitesWithSitemaps, findBestGscProperty, findExactGscProperty, formatGscPropertyCandidates, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getIndexingEligibility, getIndexingMetadata, getLatestGscDate, getNextCheckAfter, getNextCheckPriority, getNextDate, getOldestGscDate, getPendingDates, getPreviousDate, getPstDate, getVerificationToken, getVerifiedSite, googleSearchConsole, groupIntoRanges, gscErrorToException, gscPropertyMatchesTarget, hasGoogleScope, hasGscReadScope, hasGscWriteScope, hasIndexingScope, hasOptionalIndexingScope, hasRequiredAnalyticsScope, indexingNextActions, indexingStatuses, inspectUrl, inspectUrlFlat, introspectAccessToken, introspectAccessTokenResult, isCanonicalMismatch, isErr, isFragmentUrl, isOk, isPermissionDeniedError, isValidGscDate, isVerifiedGscPermission, isVerifiedGscProperty, lifecycleErrorCodes, listVerifiedSites, matchGscSite, normalizeGscSiteUrl, normalizeRegistrationTarget, normalizeSiteUrl, normalizeUrl, ok, parseGoogleError, parseGrantedScopes, parseGscSiteUrl, pickBestGscProperty, propertyNextActions, propertyStatuses, querySourceModes, refreshAccessToken, requestIndexing, resolveVerificationTarget, rethrowAsGscApiError, revokeOAuthToken, revokeOAuthTokenResult, runSequentialBatch, siteUrlToVerificationSite, sitemapNextActions, sitemapStatuses, submitSitemap, toIsoDate, unmappedInspectionReasons, unverifySite, unwrapResult, urlMatchKey, verificationMethodsFor, verifySite };
23
+ export { DAYS_PER_RANGE, DEFAULT_GSC_REQUEST_TIMEOUT_MS, GSCDUMP_ONBOARDING_CONTRACT_VERSION, GSCDUMP_OPTIONAL_INDEXING_SCOPE, GSCDUMP_REQUIRED_ANALYTICS_SCOPE, GSCDUMP_WRITE_ANALYTICS_SCOPE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_INDEXING_SCOPE, GSC_READ_SCOPE, GSC_RETENTION_MONTHS, GSC_SITE_VERIFICATION_SCOPE, GSC_WRITE_SCOPE, GscApiError, INDEXING_ISSUE_FILTERS, INDEXING_ISSUE_LABELS, INDEXING_ISSUE_SEVERITY, KNOWN_COVERAGE_STATES, KNOWN_PAGE_FETCH_STATES, MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, MS_PER_DAY, URL_INSPECTION_EFFECTIVE_LIMIT, URL_INSPECTION_QUOTA, accountNextActions, accountStatuses, addDays, addSite, analyticsNextActions, analyticsStatuses, batchInspectUrls, batchInspectUrlsFlatSettled, batchRequestIndexing, canUseUrlInspection, classifyCanonicalDifference, classifyError, countDays, createAuth, createFetch, decodeSiteId, deleteSite, deleteSitemap, describeInspectionError, encodeSiteId, err, exchangeAuthCodeResult, fetchSitemap, fetchSitemaps, fetchSites, fetchSitesWithSitemaps, findBestGscProperty, findExactGscProperty, formatGscPropertyCandidates, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getIndexingEligibility, getIndexingMetadata, getLatestGscDate, getNextCheckAfter, getNextCheckPriority, getNextDate, getOldestGscDate, getPendingDates, getPreviousDate, getPstDate, getVerificationToken, getVerifiedSite, googleSearchConsole, groupIntoRanges, gscErrorToException, gscPropertyMatchesTarget, hasGoogleScope, hasGscReadScope, hasGscWriteScope, hasIndexingScope, hasOptionalIndexingScope, hasRequiredAnalyticsScope, indexingNextActions, indexingStatuses, inspectUrl, inspectUrlFlat, introspectAccessToken, introspectAccessTokenResult, isCanonicalMismatch, isErr, isFragmentUrl, isOk, isPermissionDeniedError, isValidGscDate, isVerifiedGscPermission, isVerifiedGscProperty, lifecycleErrorCodes, listVerifiedSites, matchGscSite, normalizeGscSiteUrl, normalizeRegistrationTarget, normalizeSiteUrl, normalizeUrl, ok, parseGoogleError, parseGrantedScopes, parseGscSiteUrl, pickBestGscProperty, propertyNextActions, propertyStatuses, querySourceModes, refreshAccessToken, requestIndexing, resolveSiteInput, resolveVerificationTarget, rethrowAsGscApiError, revokeOAuthToken, revokeOAuthTokenResult, runSequentialBatch, siteUrlToVerificationSite, sitemapNextActions, sitemapStatuses, submitSitemap, toIsoDate, unmappedInspectionReasons, unverifySite, unwrapResult, urlMatchKey, verificationMethodsFor, verifySite };
@@ -1,5 +1,5 @@
1
1
  import { UrlInspectionResult } from "./core/types.mjs";
2
2
  import { runSequentialBatch } from "./api/batch.mjs";
3
3
  import { IndexingMetadata, IndexingNotificationType, IndexingResult, batchRequestIndexing, getIndexingMetadata, requestIndexing } from "./api/indexing.mjs";
4
- import { BatchInspectUrlsFlatSettledOptions, IndexingEligibility, IndexingIneligibleReason, InspectUrlFlatSettledResult, InspectUrlResult, InspectionPriority, LegacyInspectionPriority, MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, ParsedIndexingResult, ValueWeightedInspectionPriority, batchInspectUrls, batchInspectUrlsFlatSettled, canUseUrlInspection, getIndexingEligibility, getNextCheckAfter, getNextCheckPriority, inspectUrl, inspectUrlFlat } from "./api/inspection.mjs";
5
- export { type BatchInspectUrlsFlatSettledOptions, type IndexingEligibility, type IndexingIneligibleReason, type IndexingMetadata, type IndexingNotificationType, type IndexingResult, type InspectUrlFlatSettledResult, type InspectUrlResult, type InspectionPriority, type LegacyInspectionPriority, MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, type ParsedIndexingResult, type UrlInspectionResult, type ValueWeightedInspectionPriority, batchInspectUrls, batchInspectUrlsFlatSettled, batchRequestIndexing, canUseUrlInspection, getIndexingEligibility, getIndexingMetadata, getNextCheckAfter, getNextCheckPriority, inspectUrl, inspectUrlFlat, requestIndexing, runSequentialBatch };
4
+ import { BatchInspectUrlsFlatSettledOptions, IndexingEligibility, IndexingIneligibleReason, InspectUrlFlatSettledResult, InspectUrlResult, InspectionPriority, LegacyInspectionPriority, MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, ParsedIndexingResult, URL_INSPECTION_QUOTA, ValueWeightedInspectionPriority, batchInspectUrls, batchInspectUrlsFlatSettled, canUseUrlInspection, describeInspectionError, getIndexingEligibility, getNextCheckAfter, getNextCheckPriority, inspectUrl, inspectUrlFlat } from "./api/inspection.mjs";
5
+ export { type BatchInspectUrlsFlatSettledOptions, type IndexingEligibility, type IndexingIneligibleReason, type IndexingMetadata, type IndexingNotificationType, type IndexingResult, type InspectUrlFlatSettledResult, type InspectUrlResult, type InspectionPriority, type LegacyInspectionPriority, MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, type ParsedIndexingResult, URL_INSPECTION_QUOTA, type UrlInspectionResult, type ValueWeightedInspectionPriority, batchInspectUrls, batchInspectUrlsFlatSettled, batchRequestIndexing, canUseUrlInspection, describeInspectionError, getIndexingEligibility, getIndexingMetadata, getNextCheckAfter, getNextCheckPriority, inspectUrl, inspectUrlFlat, requestIndexing, runSequentialBatch };
package/dist/indexing.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  import { runSequentialBatch } from "./api/batch.mjs";
2
2
  import { batchRequestIndexing, getIndexingMetadata, requestIndexing } from "./api/indexing.mjs";
3
- import { MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, batchInspectUrls, batchInspectUrlsFlatSettled, canUseUrlInspection, getIndexingEligibility, getNextCheckAfter, getNextCheckPriority, inspectUrl, inspectUrlFlat } from "./api/inspection.mjs";
4
- export { MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, batchInspectUrls, batchInspectUrlsFlatSettled, batchRequestIndexing, canUseUrlInspection, getIndexingEligibility, getIndexingMetadata, getNextCheckAfter, getNextCheckPriority, inspectUrl, inspectUrlFlat, requestIndexing, runSequentialBatch };
3
+ import { MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, URL_INSPECTION_QUOTA, batchInspectUrls, batchInspectUrlsFlatSettled, canUseUrlInspection, describeInspectionError, getIndexingEligibility, getNextCheckAfter, getNextCheckPriority, inspectUrl, inspectUrlFlat } from "./api/inspection.mjs";
4
+ export { MAX_FLAT_INSPECTION_BATCH_CONCURRENCY, URL_INSPECTION_QUOTA, batchInspectUrls, batchInspectUrlsFlatSettled, batchRequestIndexing, canUseUrlInspection, describeInspectionError, getIndexingEligibility, getIndexingMetadata, getNextCheckAfter, getNextCheckPriority, inspectUrl, inspectUrlFlat, requestIndexing, runSequentialBatch };
@@ -1,26 +1,6 @@
1
- import { addDays } from "../../core/gsc-dates.mjs";
2
- let pstFormatter;
3
- function getPstFormatter() {
4
- pstFormatter ??= new Intl.DateTimeFormat("en-CA", {
5
- timeZone: "America/Los_Angeles",
6
- year: "numeric",
7
- month: "2-digit",
8
- day: "2-digit"
9
- });
10
- return pstFormatter;
11
- }
12
- function pstDateParts(d = /* @__PURE__ */ new Date()) {
13
- const parts = getPstFormatter().formatToParts(d);
14
- const get = (t) => Number(parts.find((p) => p.type === t).value);
15
- return {
16
- year: get("year"),
17
- month: get("month"),
18
- day: get("day")
19
- };
20
- }
1
+ import { addDays, getPstDate } from "../../core/gsc-dates.mjs";
21
2
  function currentPstDate() {
22
- const { year, month, day } = pstDateParts();
23
- return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
3
+ return getPstDate();
24
4
  }
25
5
  function daysAgoPst(n) {
26
6
  return addDays(currentPstDate(), -n);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gscdump",
3
3
  "type": "module",
4
- "version": "3.7.0",
4
+ "version": "4.0.0",
5
5
  "description": "Direct Google Search Console and Bing Webmaster clients with typed queries and Indexing Evidence",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",
@@ -110,10 +110,10 @@
110
110
  "dist"
111
111
  ],
112
112
  "engines": {
113
- "node": ">=22"
113
+ "node": ">=22.13.0"
114
114
  },
115
115
  "dependencies": {
116
- "@gscdump/contracts": "^3.7.0",
116
+ "@gscdump/contracts": "^4.0.0",
117
117
  "ofetch": "^1.5.1"
118
118
  },
119
119
  "scripts": {