gscdump 0.37.3 → 0.37.5

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.
@@ -2352,7 +2352,9 @@ function parseGoogleError(text, httpStatus) {
2352
2352
  let parsed = null;
2353
2353
  try {
2354
2354
  parsed = JSON.parse(text);
2355
- } catch {}
2355
+ } catch (error) {
2356
+ if (!(error instanceof SyntaxError)) throw error;
2357
+ }
2356
2358
  if (!parsed || !("error" in parsed)) return {
2357
2359
  code: httpStatus ?? 500,
2358
2360
  message: text || "Unknown Google API error"
@@ -2597,16 +2599,18 @@ async function fetchSitemapUrls(sitemapUrl, options = {}) {
2597
2599
  });
2598
2600
  if (!res.ok) throw new Error(`Fetch ${url} failed: ${res.status}`);
2599
2601
  const text = await res.text();
2600
- const isIndex = SITEMAPINDEX_RE.test(text);
2601
- const matches = [...text.matchAll(LOC_RE)].map((m) => m[1].trim()).filter(Boolean);
2602
- if (isIndex) {
2603
- for (const child of matches) {
2602
+ if (SITEMAPINDEX_RE.test(text)) {
2603
+ for (const match of text.matchAll(LOC_RE)) {
2604
2604
  if (limit != null && out.length >= limit) return;
2605
+ const child = match[1].trim();
2606
+ if (!child) continue;
2605
2607
  await visit(child, depth + 1);
2606
2608
  }
2607
2609
  return;
2608
2610
  }
2609
- for (const u of matches) {
2611
+ for (const match of text.matchAll(LOC_RE)) {
2612
+ const u = match[1].trim();
2613
+ if (!u) continue;
2610
2614
  if (seen.has(u)) continue;
2611
2615
  seen.add(u);
2612
2616
  out.push(u);
@@ -0,0 +1,61 @@
1
+ /** Milliseconds in a UTC day. Use for date arithmetic without DST surprises. */
2
+ declare const MS_PER_DAY = 86400000;
3
+ /** Format a Date as YYYY-MM-DD (UTC). */
4
+ declare function toIsoDate(d: Date): string;
5
+ /** Most recent date GSC has fully finalized data for (no further updates). */
6
+ declare const GSC_FINALIZED_LAG_DAYS = 3;
7
+ /** Most recent date GSC will return data for, may still be updating. */
8
+ declare const GSC_FRESHEST_LAG_DAYS = 1;
9
+ /** Approximate historical retention window for Search Analytics. */
10
+ declare const GSC_RETENTION_MONTHS = 16;
11
+ /** Today's date (YYYY-MM-DD) in PST. */
12
+ declare function getPstDate(): string;
13
+ /** YYYY-MM-DD for `now() - n` days, UTC. */
14
+ declare function daysAgo(n: number): string;
15
+ /** Most recent finalized date (3 days ago PST). */
16
+ declare function getLatestGscDate(): string;
17
+ /** Freshest date GSC will return (yesterday PST, may still update). */
18
+ declare function getFreshestGscDate(): string;
19
+ /**
20
+ * Dates that are still pending (1-3 days ago PST). These need to be re-synced
21
+ * each day until they finalize.
22
+ */
23
+ declare function getPendingDates(): string[];
24
+ /** All dates between two YYYY-MM-DD strings (inclusive, oldest first). */
25
+ declare function getDateRange(startDate: string, endDate: string): string[];
26
+ /** Default span used when chunking long backfills into batches. */
27
+ declare const DAYS_PER_RANGE = 30;
28
+ /**
29
+ * Like {@link getDateRange} but skips dates outside GSC's queryable window
30
+ * (older than retention or newer than the freshest date).
31
+ */
32
+ declare function generateGscDateRange(startDate: string, endDate: string): string[];
33
+ /**
34
+ * Group a sorted list of dates into contiguous runs, splitting on either a
35
+ * gap or after `daysPerRange` dates accumulate. Useful for bucketing
36
+ * backfill work into bounded jobs.
37
+ */
38
+ declare function groupIntoRanges(dates: string[], daysPerRange?: number): Array<{
39
+ startDate: string;
40
+ endDate: string;
41
+ }>;
42
+ /** Inclusive day count between two YYYY-MM-DD strings. */
43
+ declare function countDays(startDate: string, endDate: string): number;
44
+ /** Oldest date GSC retains (~16 months ago). */
45
+ declare function getOldestGscDate(): string;
46
+ declare function getNextDate(dateStr: string): string;
47
+ interface BackfillProgress {
48
+ progress: number;
49
+ daysAvailable: number;
50
+ daysSynced: number;
51
+ oldestGscDate: string;
52
+ isComplete: boolean;
53
+ }
54
+ /**
55
+ * Backfill progress (0-1) given the oldest + newest dates synced.
56
+ * Returns null when no sync data exists.
57
+ */
58
+ declare function getBackfillProgress(oldestDateSynced: string | null, newestDateSynced: string | null): BackfillProgress | null;
59
+ declare function currentPstDate(): string;
60
+ declare function daysAgoPst(n: number): string;
61
+ export { DAYS_PER_RANGE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_RETENTION_MONTHS, MS_PER_DAY, countDays, currentPstDate, daysAgoPst, daysAgo as daysAgoUtc, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getLatestGscDate, getNextDate, getOldestGscDate, getPendingDates, getPstDate, groupIntoRanges, toIsoDate };
package/dist/dates.mjs ADDED
@@ -0,0 +1,118 @@
1
+ import { format, subDays } from "date-fns";
2
+ const MS_PER_DAY = 864e5;
3
+ function toIsoDate(d) {
4
+ return d.toISOString().slice(0, 10);
5
+ }
6
+ const GSC_FINALIZED_LAG_DAYS = 3;
7
+ const GSC_FRESHEST_LAG_DAYS = 1;
8
+ const GSC_RETENTION_MONTHS = 16;
9
+ function getPstDate() {
10
+ return (/* @__PURE__ */ new Date()).toLocaleDateString("en-CA", { timeZone: "America/Los_Angeles" });
11
+ }
12
+ function getPstDateDaysAgo(daysAgo) {
13
+ const pstNow = new Date((/* @__PURE__ */ new Date()).toLocaleString("en-US", { timeZone: "America/Los_Angeles" }));
14
+ pstNow.setDate(pstNow.getDate() - daysAgo);
15
+ return toIsoDate(pstNow);
16
+ }
17
+ function daysAgo(n) {
18
+ return toIsoDate(/* @__PURE__ */ new Date(Date.now() - n * MS_PER_DAY));
19
+ }
20
+ function getLatestGscDate() {
21
+ return getPstDateDaysAgo(3);
22
+ }
23
+ function getFreshestGscDate() {
24
+ return getPstDateDaysAgo(1);
25
+ }
26
+ function getPendingDates() {
27
+ const dates = [];
28
+ for (let daysAgo = 1; daysAgo <= 3; daysAgo++) dates.push(getPstDateDaysAgo(daysAgo));
29
+ return dates;
30
+ }
31
+ function getDateRange(startDate, endDate) {
32
+ const dates = [];
33
+ const endMs = Date.parse(`${endDate}T00:00:00Z`);
34
+ for (let cursor = Date.parse(`${startDate}T00:00:00Z`); cursor <= endMs; cursor += MS_PER_DAY) dates.push(toIsoDate(new Date(cursor)));
35
+ return dates;
36
+ }
37
+ const DAYS_PER_RANGE = 30;
38
+ function generateGscDateRange(startDate, endDate) {
39
+ const start = startDate < getOldestGscDate() ? getOldestGscDate() : startDate;
40
+ const end = endDate > getFreshestGscDate() ? getFreshestGscDate() : endDate;
41
+ return start <= end ? getDateRange(start, end) : [];
42
+ }
43
+ function groupIntoRanges(dates, daysPerRange = 30) {
44
+ if (dates.length === 0) return [];
45
+ const sorted = [...dates].sort();
46
+ const ranges = [];
47
+ let rangeStart = sorted[0];
48
+ let rangePrev = sorted[0];
49
+ for (let i = 1; i < sorted.length; i++) {
50
+ const current = sorted[i];
51
+ const expected = getNextDate(rangePrev);
52
+ const daysInRange = countDays(rangeStart, rangePrev);
53
+ if (current !== expected || daysInRange >= daysPerRange) {
54
+ ranges.push({
55
+ startDate: rangeStart,
56
+ endDate: rangePrev
57
+ });
58
+ rangeStart = current;
59
+ }
60
+ rangePrev = current;
61
+ }
62
+ ranges.push({
63
+ startDate: rangeStart,
64
+ endDate: rangePrev
65
+ });
66
+ return ranges;
67
+ }
68
+ function countDays(startDate, endDate) {
69
+ return Math.round((Date.parse(`${endDate}T00:00:00Z`) - Date.parse(`${startDate}T00:00:00Z`)) / MS_PER_DAY) + 1;
70
+ }
71
+ function getOldestGscDate() {
72
+ const date = /* @__PURE__ */ new Date();
73
+ date.setMonth(date.getMonth() - 16);
74
+ return toIsoDate(date);
75
+ }
76
+ function addDays(dateStr, n) {
77
+ return toIsoDate(new Date(Date.parse(`${dateStr}T00:00:00Z`) + n * MS_PER_DAY));
78
+ }
79
+ function getNextDate(dateStr) {
80
+ return addDays(dateStr, 1);
81
+ }
82
+ function getBackfillProgress(oldestDateSynced, newestDateSynced) {
83
+ if (!oldestDateSynced || !newestDateSynced) return null;
84
+ const oldestGsc = getOldestGscDate();
85
+ const totalDays = countDays(oldestGsc, getLatestGscDate());
86
+ const syncedDays = countDays(oldestDateSynced, newestDateSynced);
87
+ return {
88
+ progress: Math.round(Math.min(1, syncedDays / totalDays) * 100) / 100,
89
+ daysAvailable: totalDays,
90
+ daysSynced: syncedDays,
91
+ oldestGscDate: oldestGsc,
92
+ isComplete: oldestDateSynced <= oldestGsc
93
+ };
94
+ }
95
+ const PST_FORMATTER = new Intl.DateTimeFormat("en-CA", {
96
+ timeZone: "America/Los_Angeles",
97
+ year: "numeric",
98
+ month: "2-digit",
99
+ day: "2-digit"
100
+ });
101
+ function pstDateParts(d = /* @__PURE__ */ new Date()) {
102
+ const parts = PST_FORMATTER.formatToParts(d);
103
+ const get = (t) => Number(parts.find((p) => p.type === t).value);
104
+ return {
105
+ year: get("year"),
106
+ month: get("month"),
107
+ day: get("day")
108
+ };
109
+ }
110
+ function currentPstDate() {
111
+ const { year, month, day } = pstDateParts();
112
+ return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
113
+ }
114
+ function daysAgoPst(n) {
115
+ const { year, month, day } = pstDateParts();
116
+ return format(subDays(new Date(year, month - 1, day, 12), n), "yyyy-MM-dd");
117
+ }
118
+ export { DAYS_PER_RANGE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_RETENTION_MONTHS, MS_PER_DAY, countDays, currentPstDate, daysAgoPst, daysAgo as daysAgoUtc, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getLatestGscDate, getNextDate, getOldestGscDate, getPendingDates, getPstDate, groupIntoRanges, toIsoDate };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { $Fetch, FetchOptions } from "ofetch";
2
+ 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, lifecycleWebhookEvents, parseGrantedScopes, propertyNextActions, propertyStatuses, querySourceModes, sitemapNextActions, sitemapStatuses } from "@gscdump/contracts/partner";
2
3
  import { indexing_v3 } from "@googleapis/indexing/build/v3";
3
4
  import { searchconsole_v1 } from "@googleapis/searchconsole/build/v1";
4
5
  /**
@@ -820,17 +821,17 @@ declare function findExactGscProperty<T extends GscPropertyCandidate>(propertyUr
820
821
  declare function formatGscPropertyCandidates(candidates: ReadonlyArray<GscPropertyCandidate | null | undefined>): string;
821
822
  declare const URL_INSPECTION_DAILY_LIMIT = 2000;
822
823
  declare const URL_INSPECTION_EFFECTIVE_LIMIT = 1800;
823
- type GoogleScopesInput$2 = string | readonly string[] | null | undefined;
824
+ type GoogleScopesInput$1 = string | readonly string[] | null | undefined;
824
825
  declare const GSC_READ_SCOPE: "https://www.googleapis.com/auth/webmasters.readonly";
825
826
  declare const GSC_WRITE_SCOPE: "https://www.googleapis.com/auth/webmasters";
826
827
  declare const GSC_INDEXING_SCOPE: "https://www.googleapis.com/auth/indexing";
827
828
  declare const GSC_SITE_VERIFICATION_SCOPE: "https://www.googleapis.com/auth/siteverification";
828
- declare function parseGoogleScopes(scopes: GoogleScopesInput$2): string[];
829
- declare function hasGoogleScope(scopes: GoogleScopesInput$2, scope: string): boolean;
830
- type GoogleScopesInput$1 = string | readonly string[] | null | undefined;
831
- declare function hasGscReadScope(scopes: GoogleScopesInput$1): boolean;
832
- declare function hasGscWriteScope(scopes: GoogleScopesInput$1): boolean;
833
- declare function hasIndexingScope(scopes: GoogleScopesInput$1): boolean;
829
+ declare function parseGoogleScopes(scopes: GoogleScopesInput$1): string[];
830
+ declare function hasGoogleScope(scopes: GoogleScopesInput$1, scope: string): boolean;
831
+ type GoogleScopesInput = string | readonly string[] | null | undefined;
832
+ declare function hasGscReadScope(scopes: GoogleScopesInput): boolean;
833
+ declare function hasGscWriteScope(scopes: GoogleScopesInput): boolean;
834
+ declare function hasIndexingScope(scopes: GoogleScopesInput): boolean;
834
835
  interface ParsedGscSiteUrl {
835
836
  /** Original, canonical GSC property URL. */
836
837
  label: string;
@@ -856,113 +857,6 @@ declare function normalizeGscSiteUrl(siteUrl: string): string;
856
857
  */
857
858
  declare function normalizeRegistrationTarget(inputUrl: string): string | null;
858
859
  declare function normalizeUrl(input: string): string;
859
- type GoogleScopesInput = string | readonly string[] | null | undefined;
860
- declare const GSCDUMP_ONBOARDING_CONTRACT_VERSION: "2026-05-11";
861
- declare const GSCDUMP_REQUIRED_ANALYTICS_SCOPE: "https://www.googleapis.com/auth/webmasters.readonly";
862
- declare const GSCDUMP_OPTIONAL_INDEXING_SCOPE: "https://www.googleapis.com/auth/indexing";
863
- declare const accountStatuses: readonly ["disconnected", "oauth_received", "scope_missing", "refresh_missing", "db_provisioning", "ready", "reauth_required"];
864
- declare const accountNextActions: readonly ["connect_google", "reconnect_google", "wait_for_provisioning", "none"];
865
- declare const propertyStatuses: readonly ["no_local_site", "no_gsc_property", "unverified_property", "verified_candidate", "registered", "linked"];
866
- declare const propertyNextActions: readonly ["create_site", "verify_gsc_property", "choose_property", "register_site", "none"];
867
- declare const analyticsStatuses: readonly ["not_registered", "queued", "preparing", "syncing", "queryable_live", "queryable_partial", "ready", "failed"];
868
- declare const analyticsNextActions: readonly ["wait_for_sync", "retry_sync", "none"];
869
- declare const querySourceModes: readonly ["none", "live", "d1", "r2", "mixed"];
870
- declare const sitemapStatuses: readonly ["unknown", "discovering", "none_found", "auto_submitted", "syncing", "ready", "failed"];
871
- declare const sitemapNextActions: readonly ["submit_sitemap", "wait_for_sitemaps", "retry_sitemaps", "none"];
872
- declare const indexingStatuses: readonly ["not_requested", "missing_scope", "insufficient_permission", "waiting_for_sitemaps", "discovering", "checking", "ready", "budget_exhausted", "no_urls", "failed"];
873
- declare const indexingNextActions: readonly ["reconnect_google", "fix_gsc_permission", "wait_for_sitemaps", "wait_for_indexing", "retry_indexing", "none"];
874
- declare const lifecycleWebhookEvents: readonly ["user.lifecycle.changed", "site.lifecycle.changed", "site.analytics.ready", "site.indexing.ready", "site.auth.failed", "job.failed"];
875
- declare const lifecycleErrorCodes: readonly ["missing_refresh_token", "missing_analytics_scope", "missing_indexing_scope", "token_refresh_failed", "permission_lost", "insufficient_gsc_permission", "gsc_property_not_found", "gsc_property_unverified", "user_database_not_provisioned", "sync_failed", "sitemap_sync_failed", "indexing_failed"];
876
- type AccountStatus = typeof accountStatuses[number];
877
- type AccountNextAction = typeof accountNextActions[number];
878
- type PropertyStatus = typeof propertyStatuses[number];
879
- type PropertyNextAction = typeof propertyNextActions[number];
880
- type AnalyticsStatus = typeof analyticsStatuses[number];
881
- type AnalyticsNextAction = typeof analyticsNextActions[number];
882
- type QuerySourceMode = typeof querySourceModes[number];
883
- type SitemapStatus = typeof sitemapStatuses[number];
884
- type SitemapNextAction = typeof sitemapNextActions[number];
885
- type IndexingStatus = typeof indexingStatuses[number];
886
- type IndexingNextAction = typeof indexingNextActions[number];
887
- type LifecycleWebhookEvent = typeof lifecycleWebhookEvents[number];
888
- type LifecycleErrorCode = typeof lifecycleErrorCodes[number];
889
- interface LifecycleProgress {
890
- completed: number;
891
- failed: number;
892
- total: number;
893
- percent: number;
894
- }
895
- interface LifecycleError {
896
- code: LifecycleErrorCode;
897
- message: string;
898
- retryable: boolean;
899
- }
900
- interface PartnerLifecycleAccount {
901
- status: AccountStatus;
902
- grantedScopes: string[];
903
- missingScopes: string[];
904
- nextAction: AccountNextAction;
905
- }
906
- interface PartnerLifecycleSite {
907
- siteId: string;
908
- externalSiteId: string | null;
909
- requestedUrl: string;
910
- gscPropertyUrl: string | null;
911
- permissionLevel: string | null;
912
- property: {
913
- status: PropertyStatus;
914
- nextAction: PropertyNextAction;
915
- };
916
- analytics: {
917
- status: AnalyticsStatus;
918
- progress: LifecycleProgress;
919
- queryable: boolean;
920
- sourceMode: QuerySourceMode;
921
- syncedRange: {
922
- oldest: string | null;
923
- newest: string | null;
924
- };
925
- nextAction: AnalyticsNextAction;
926
- };
927
- sitemaps: {
928
- status: SitemapStatus;
929
- discoveredCount: number;
930
- nextAction: SitemapNextAction;
931
- };
932
- indexing: {
933
- status: IndexingStatus;
934
- eligible: boolean;
935
- reason: string | null;
936
- progress: LifecycleProgress;
937
- nextAction: IndexingNextAction;
938
- };
939
- latestError: LifecycleError | null;
940
- lifecycleRevision: number;
941
- updatedAt: string;
942
- }
943
- interface PartnerLifecycleResponse {
944
- contractVersion: typeof GSCDUMP_ONBOARDING_CONTRACT_VERSION;
945
- userId: string;
946
- partnerId: string | null;
947
- account: PartnerLifecycleAccount;
948
- sites: PartnerLifecycleSite[];
949
- }
950
- interface LifecycleWebhookEnvelope<TData extends Record<string, unknown> = Record<string, unknown>> {
951
- contractVersion: typeof GSCDUMP_ONBOARDING_CONTRACT_VERSION;
952
- deliveryId: string;
953
- event: LifecycleWebhookEvent;
954
- partnerId: string;
955
- userId: string;
956
- siteId?: string;
957
- externalUserId?: string | null;
958
- externalSiteId?: string | null;
959
- lifecycleRevision: number;
960
- occurredAt: string;
961
- data: TData;
962
- }
963
- declare function parseGrantedScopes(scopes: GoogleScopesInput): string[];
964
- declare function hasRequiredAnalyticsScope(scopes: GoogleScopesInput): boolean;
965
- declare function hasOptionalIndexingScope(scopes: GoogleScopesInput): boolean;
966
860
  interface DiscoverSitemapOptions {
967
861
  /** User-Agent sent on the discovery requests. */
968
862
  userAgent?: string;
@@ -1013,4 +907,4 @@ declare function normalizeSiteUrl(siteUrl: string): string;
1013
907
  * Example: `https://www.Example.com/Foo/` → `example.com/foo`
1014
908
  */
1015
909
  declare function urlMatchKey(url: string): string | null;
1016
- export { AccountNextAction, AccountStatus, AnalyticsNextAction, AnalyticsStatus, ApiSite, ApiSitemap, ApiSitemapContent, Auth, AuthClient, AuthOptions, BackfillProgress, CallOptions, DAYS_PER_RANGE, DataRow, DimensionFilter, DimensionFilterGroup, DiscoverSitemapOptions, Err, FetchSitemapUrlsOptions, GSCDUMP_ONBOARDING_CONTRACT_VERSION, GSCDUMP_OPTIONAL_INDEXING_SCOPE, GSCDUMP_REQUIRED_ANALYTICS_SCOPE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_INDEXING_SCOPE, GSC_QUOTAS, GSC_READ_SCOPE, GSC_RETENTION_MONTHS, GSC_SITE_VERIFICATION_SCOPE, GSC_WRITE_SCOPE, GoogleSearchConsoleClient, GoogleSearchConsoleClientOptions, GscApiError, GscApiErrorInfo, GscError, GscErrorKind, GscPropertyCandidate, GscdumpApiOptions, INDEXING_ISSUE_FILTERS, INDEXING_ISSUE_LABELS, INDEXING_ISSUE_SEVERITY, IndexStatusResult, IndexingEligibility, IndexingIneligibleReason, IndexingIssueType, IndexingMetadata, IndexingNextAction, IndexingNotificationType, IndexingResult, IndexingStatus, InspectUrlIndexResponse, InspectUrlResult, InspectionPriority, KNOWN_COVERAGE_STATES, KNOWN_PAGE_FETCH_STATES, LifecycleError, LifecycleErrorCode, LifecycleProgress, LifecycleWebhookEnvelope, LifecycleWebhookEvent, MS_PER_DAY, MobileUsabilityResult, OAuthTokens, Ok, ParsedGscSiteUrl, ParsedIndexingResult, PartnerLifecycleAccount, PartnerLifecycleResponse, PartnerLifecycleSite, Period, PropertyNextAction, PropertyStatus, PublishUrlNotificationResponse, QueryReturn, QuerySourceMode, RequiredNonNullable, ResolvedAnalyticsRange, Result, RichResultsResult, SearchAnalyticsQuery, SearchAnalyticsResponse, Site, SiteAnalytics, SitemapNextAction, SitemapStatus, URL_INSPECTION_DAILY_LIMIT, URL_INSPECTION_EFFECTIVE_LIMIT, UnmappedInspectionReasons, UrlInspectionResult, UrlNotificationMetadata, VerificationMethod, VerificationSite, VerificationSiteType, VerificationToken, VerificationWebResource, accountNextActions, accountStatuses, addDays, addSite, analyticsNextActions, analyticsStatuses, batchInspectUrls, batchRequestIndexing, canUseUrlInspection, classifyError, countDays, createAuth, createFetch, daysAgo, decodeSiteId, deleteSite, deleteSitemap, discoverSitemap, encodeSiteId, err, exchangeAuthCode, exchangeAuthCodeResult, fetchSitemap, fetchSitemapUrls, fetchSitemaps, fetchSites, fetchSitesWithSitemaps, findBestGscProperty, findExactGscProperty, formatErrorForCli, formatGscPropertyCandidates, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getIndexingEligibility, getIndexingMetadata, getLatestGscDate, getNextCheckAfter, getNextCheckPriority, getNextDate, getOldestGscDate, getPendingDates, getPreviousDate, getPstDate, getVerificationToken, getVerifiedSite, googleSearchConsole, grantedScopeList, groupIntoRanges, gscErrorToException, gscPropertyMatchesTarget, gscdumpApi, hasGoogleScope, hasGscReadScope, hasGscWriteScope, hasIndexingScope, hasOptionalIndexingScope, hasRequiredAnalyticsScope, indexingNextActions, indexingStatuses, inspectUrl, inspectUrlFlat, isErr, isOk, isPermissionDeniedError, isValidGscDate, isVerifiedGscPermission, isVerifiedGscProperty, lifecycleErrorCodes, lifecycleWebhookEvents, listVerifiedSites, mapErr, mapResult, matchGscSite, matchResult, normalizeGscSiteUrl, normalizeRegistrationTarget, normalizeSiteUrl, normalizeUrl, ok, parseGoogleError, parseGoogleScopes, parseGrantedScopes, parseGscSiteUrl, pickBestGscProperty, progressBar, propertyNextActions, propertyStatuses, querySourceModes, refreshAccessToken, refreshAccessTokenResult, requestIndexing, rethrowAsGscApiError, rowWithMetricDefaults, runSequentialBatch, siteUrlToVerificationSite, sitemapNextActions, sitemapStatuses, storageError, submitSitemap, toIsoDate, unmappedInspectionReasons, unverifySite, unwrapResult, urlMatchKey, verificationMethodsFor, verifySite };
910
+ export { type AccountNextAction, type AccountStatus, type AnalyticsNextAction, type AnalyticsStatus, ApiSite, ApiSitemap, ApiSitemapContent, Auth, AuthClient, AuthOptions, BackfillProgress, CallOptions, DAYS_PER_RANGE, DataRow, DimensionFilter, DimensionFilterGroup, DiscoverSitemapOptions, Err, FetchSitemapUrlsOptions, 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_QUOTAS, GSC_READ_SCOPE, GSC_RETENTION_MONTHS, GSC_SITE_VERIFICATION_SCOPE, GSC_WRITE_SCOPE, GoogleSearchConsoleClient, GoogleSearchConsoleClientOptions, GscApiError, GscApiErrorInfo, GscError, GscErrorKind, GscPropertyCandidate, GscdumpApiOptions, INDEXING_ISSUE_FILTERS, INDEXING_ISSUE_LABELS, INDEXING_ISSUE_SEVERITY, IndexStatusResult, IndexingEligibility, IndexingIneligibleReason, IndexingIssueType, IndexingMetadata, type IndexingNextAction, IndexingNotificationType, IndexingResult, type IndexingStatus, InspectUrlIndexResponse, InspectUrlResult, InspectionPriority, KNOWN_COVERAGE_STATES, KNOWN_PAGE_FETCH_STATES, type LifecycleError, type LifecycleErrorCode, type LifecycleProgress, type LifecycleWebhookEnvelope, type LifecycleWebhookEvent, MS_PER_DAY, MobileUsabilityResult, OAuthTokens, Ok, ParsedGscSiteUrl, ParsedIndexingResult, type PartnerLifecycleAccount, type PartnerLifecycleResponse, type PartnerLifecycleSite, Period, type PropertyNextAction, type PropertyStatus, PublishUrlNotificationResponse, QueryReturn, type QuerySourceMode, RequiredNonNullable, ResolvedAnalyticsRange, Result, RichResultsResult, SearchAnalyticsQuery, SearchAnalyticsResponse, Site, SiteAnalytics, type SitemapNextAction, type SitemapStatus, URL_INSPECTION_DAILY_LIMIT, URL_INSPECTION_EFFECTIVE_LIMIT, UnmappedInspectionReasons, UrlInspectionResult, UrlNotificationMetadata, VerificationMethod, VerificationSite, VerificationSiteType, VerificationToken, VerificationWebResource, accountNextActions, accountStatuses, addDays, addSite, analyticsNextActions, analyticsStatuses, batchInspectUrls, batchRequestIndexing, canUseUrlInspection, classifyError, countDays, createAuth, createFetch, daysAgo, decodeSiteId, deleteSite, deleteSitemap, discoverSitemap, encodeSiteId, err, exchangeAuthCode, exchangeAuthCodeResult, fetchSitemap, fetchSitemapUrls, fetchSitemaps, fetchSites, fetchSitesWithSitemaps, findBestGscProperty, findExactGscProperty, formatErrorForCli, formatGscPropertyCandidates, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getIndexingEligibility, getIndexingMetadata, getLatestGscDate, getNextCheckAfter, getNextCheckPriority, getNextDate, getOldestGscDate, getPendingDates, getPreviousDate, getPstDate, getVerificationToken, getVerifiedSite, googleSearchConsole, grantedScopeList, groupIntoRanges, gscErrorToException, gscPropertyMatchesTarget, gscdumpApi, hasGoogleScope, hasGscReadScope, hasGscWriteScope, hasIndexingScope, hasOptionalIndexingScope, hasRequiredAnalyticsScope, indexingNextActions, indexingStatuses, inspectUrl, inspectUrlFlat, isErr, isOk, isPermissionDeniedError, isValidGscDate, isVerifiedGscPermission, isVerifiedGscProperty, lifecycleErrorCodes, lifecycleWebhookEvents, listVerifiedSites, mapErr, mapResult, matchGscSite, matchResult, normalizeGscSiteUrl, normalizeRegistrationTarget, normalizeSiteUrl, normalizeUrl, ok, parseGoogleError, parseGoogleScopes, parseGrantedScopes, parseGscSiteUrl, pickBestGscProperty, progressBar, propertyNextActions, propertyStatuses, querySourceModes, refreshAccessToken, refreshAccessTokenResult, requestIndexing, rethrowAsGscApiError, rowWithMetricDefaults, runSequentialBatch, siteUrlToVerificationSite, sitemapNextActions, sitemapStatuses, storageError, submitSitemap, toIsoDate, unmappedInspectionReasons, unverifySite, unwrapResult, urlMatchKey, verificationMethodsFor, verifySite };
package/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ofetch } from "ofetch";
2
+ 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, lifecycleWebhookEvents, parseGrantedScopes, propertyNextActions, propertyStatuses, querySourceModes, sitemapNextActions, sitemapStatuses } from "@gscdump/contracts/partner";
2
3
  async function runSequentialBatch(items, operation, options = {}) {
3
4
  const { delayMs = 0, concurrency = 1, onProgress } = options;
4
5
  const results = Array.from({ length: items.length });
@@ -339,7 +340,9 @@ function parseGoogleError(text, httpStatus) {
339
340
  let parsed = null;
340
341
  try {
341
342
  parsed = JSON.parse(text);
342
- } catch {}
343
+ } catch (error) {
344
+ if (!(error instanceof SyntaxError)) throw error;
345
+ }
343
346
  if (!parsed || !("error" in parsed)) return {
344
347
  code: httpStatus ?? 500,
345
348
  message: text || "Unknown Google API error"
@@ -3126,127 +3129,6 @@ function safeParse(input) {
3126
3129
  return null;
3127
3130
  }
3128
3131
  }
3129
- const GSCDUMP_ONBOARDING_CONTRACT_VERSION = "2026-05-11";
3130
- const GSCDUMP_REQUIRED_ANALYTICS_SCOPE = GSC_READ_SCOPE;
3131
- const GSCDUMP_OPTIONAL_INDEXING_SCOPE = GSC_INDEXING_SCOPE;
3132
- const accountStatuses = [
3133
- "disconnected",
3134
- "oauth_received",
3135
- "scope_missing",
3136
- "refresh_missing",
3137
- "db_provisioning",
3138
- "ready",
3139
- "reauth_required"
3140
- ];
3141
- const accountNextActions = [
3142
- "connect_google",
3143
- "reconnect_google",
3144
- "wait_for_provisioning",
3145
- "none"
3146
- ];
3147
- const propertyStatuses = [
3148
- "no_local_site",
3149
- "no_gsc_property",
3150
- "unverified_property",
3151
- "verified_candidate",
3152
- "registered",
3153
- "linked"
3154
- ];
3155
- const propertyNextActions = [
3156
- "create_site",
3157
- "verify_gsc_property",
3158
- "choose_property",
3159
- "register_site",
3160
- "none"
3161
- ];
3162
- const analyticsStatuses = [
3163
- "not_registered",
3164
- "queued",
3165
- "preparing",
3166
- "syncing",
3167
- "queryable_live",
3168
- "queryable_partial",
3169
- "ready",
3170
- "failed"
3171
- ];
3172
- const analyticsNextActions = [
3173
- "wait_for_sync",
3174
- "retry_sync",
3175
- "none"
3176
- ];
3177
- const querySourceModes = [
3178
- "none",
3179
- "live",
3180
- "d1",
3181
- "r2",
3182
- "mixed"
3183
- ];
3184
- const sitemapStatuses = [
3185
- "unknown",
3186
- "discovering",
3187
- "none_found",
3188
- "auto_submitted",
3189
- "syncing",
3190
- "ready",
3191
- "failed"
3192
- ];
3193
- const sitemapNextActions = [
3194
- "submit_sitemap",
3195
- "wait_for_sitemaps",
3196
- "retry_sitemaps",
3197
- "none"
3198
- ];
3199
- const indexingStatuses = [
3200
- "not_requested",
3201
- "missing_scope",
3202
- "insufficient_permission",
3203
- "waiting_for_sitemaps",
3204
- "discovering",
3205
- "checking",
3206
- "ready",
3207
- "budget_exhausted",
3208
- "no_urls",
3209
- "failed"
3210
- ];
3211
- const indexingNextActions = [
3212
- "reconnect_google",
3213
- "fix_gsc_permission",
3214
- "wait_for_sitemaps",
3215
- "wait_for_indexing",
3216
- "retry_indexing",
3217
- "none"
3218
- ];
3219
- const lifecycleWebhookEvents = [
3220
- "user.lifecycle.changed",
3221
- "site.lifecycle.changed",
3222
- "site.analytics.ready",
3223
- "site.indexing.ready",
3224
- "site.auth.failed",
3225
- "job.failed"
3226
- ];
3227
- const lifecycleErrorCodes = [
3228
- "missing_refresh_token",
3229
- "missing_analytics_scope",
3230
- "missing_indexing_scope",
3231
- "token_refresh_failed",
3232
- "permission_lost",
3233
- "insufficient_gsc_permission",
3234
- "gsc_property_not_found",
3235
- "gsc_property_unverified",
3236
- "user_database_not_provisioned",
3237
- "sync_failed",
3238
- "sitemap_sync_failed",
3239
- "indexing_failed"
3240
- ];
3241
- function parseGrantedScopes(scopes) {
3242
- return parseGoogleScopes(scopes);
3243
- }
3244
- function hasRequiredAnalyticsScope(scopes) {
3245
- return hasGscReadScope(scopes);
3246
- }
3247
- function hasOptionalIndexingScope(scopes) {
3248
- return hasIndexingScope(scopes);
3249
- }
3250
3132
  const FETCH_TIMEOUT_MS = 1e4;
3251
3133
  const COMMON_PATHS = ["/sitemap.xml", "/sitemap_index.xml"];
3252
3134
  const SITEMAP_DIRECTIVE_RE = /^Sitemap:\s*(\S+)/im;
@@ -3295,16 +3177,18 @@ async function fetchSitemapUrls(sitemapUrl, options = {}) {
3295
3177
  });
3296
3178
  if (!res.ok) throw new Error(`Fetch ${url} failed: ${res.status}`);
3297
3179
  const text = await res.text();
3298
- const isIndex = SITEMAPINDEX_RE.test(text);
3299
- const matches = [...text.matchAll(LOC_RE)].map((m) => m[1].trim()).filter(Boolean);
3300
- if (isIndex) {
3301
- for (const child of matches) {
3180
+ if (SITEMAPINDEX_RE.test(text)) {
3181
+ for (const match of text.matchAll(LOC_RE)) {
3302
3182
  if (limit != null && out.length >= limit) return;
3183
+ const child = match[1].trim();
3184
+ if (!child) continue;
3303
3185
  await visit(child, depth + 1);
3304
3186
  }
3305
3187
  return;
3306
3188
  }
3307
- for (const u of matches) {
3189
+ for (const match of text.matchAll(LOC_RE)) {
3190
+ const u = match[1].trim();
3191
+ if (!u) continue;
3308
3192
  if (seen.has(u)) continue;
3309
3193
  seen.add(u);
3310
3194
  out.push(u);
@@ -3336,4 +3220,4 @@ function urlMatchKey(url) {
3336
3220
  if (!u) return null;
3337
3221
  return [u.hostname.replace(/^www\./, ""), u.pathname.replace(/\/$/, "") || "/"].join("").toLowerCase();
3338
3222
  }
3339
- export { DAYS_PER_RANGE, GSCDUMP_ONBOARDING_CONTRACT_VERSION, GSCDUMP_OPTIONAL_INDEXING_SCOPE, GSCDUMP_REQUIRED_ANALYTICS_SCOPE, GSC_FINALIZED_LAG_DAYS, GSC_FRESHEST_LAG_DAYS, GSC_INDEXING_SCOPE, GSC_QUOTAS, 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, MS_PER_DAY, URL_INSPECTION_DAILY_LIMIT, URL_INSPECTION_EFFECTIVE_LIMIT, accountNextActions, accountStatuses, addDays, addSite, analyticsNextActions, analyticsStatuses, batchInspectUrls, batchRequestIndexing, canUseUrlInspection, classifyError, countDays, createAuth, createFetch, daysAgo, decodeSiteId, deleteSite, deleteSitemap, discoverSitemap, encodeSiteId, err, exchangeAuthCode, exchangeAuthCodeResult, fetchSitemap, fetchSitemapUrls, fetchSitemaps, fetchSites, fetchSitesWithSitemaps, findBestGscProperty, findExactGscProperty, formatErrorForCli, formatGscPropertyCandidates, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getIndexingEligibility, getIndexingMetadata, getLatestGscDate, getNextCheckAfter, getNextCheckPriority, getNextDate, getOldestGscDate, getPendingDates, getPreviousDate, getPstDate, getVerificationToken, getVerifiedSite, googleSearchConsole, grantedScopeList, groupIntoRanges, gscErrorToException, gscPropertyMatchesTarget, gscdumpApi, hasGoogleScope, hasGscReadScope, hasGscWriteScope, hasIndexingScope, hasOptionalIndexingScope, hasRequiredAnalyticsScope, indexingNextActions, indexingStatuses, inspectUrl, inspectUrlFlat, isErr, isOk, isPermissionDeniedError, isValidGscDate, isVerifiedGscPermission, isVerifiedGscProperty, lifecycleErrorCodes, lifecycleWebhookEvents, listVerifiedSites, mapErr, mapResult, matchGscSite, matchResult, normalizeGscSiteUrl, normalizeRegistrationTarget, normalizeSiteUrl, normalizeUrl, ok, parseGoogleError, parseGoogleScopes, parseGrantedScopes, parseGscSiteUrl, pickBestGscProperty, progressBar, propertyNextActions, propertyStatuses, querySourceModes, refreshAccessToken, refreshAccessTokenResult, requestIndexing, rethrowAsGscApiError, rowWithMetricDefaults, runSequentialBatch, siteUrlToVerificationSite, sitemapNextActions, sitemapStatuses, storageError, submitSitemap, toIsoDate, unmappedInspectionReasons, unverifySite, unwrapResult, urlMatchKey, verificationMethodsFor, verifySite };
3223
+ export { DAYS_PER_RANGE, 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_QUOTAS, 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, MS_PER_DAY, URL_INSPECTION_DAILY_LIMIT, URL_INSPECTION_EFFECTIVE_LIMIT, accountNextActions, accountStatuses, addDays, addSite, analyticsNextActions, analyticsStatuses, batchInspectUrls, batchRequestIndexing, canUseUrlInspection, classifyError, countDays, createAuth, createFetch, daysAgo, decodeSiteId, deleteSite, deleteSitemap, discoverSitemap, encodeSiteId, err, exchangeAuthCode, exchangeAuthCodeResult, fetchSitemap, fetchSitemapUrls, fetchSitemaps, fetchSites, fetchSitesWithSitemaps, findBestGscProperty, findExactGscProperty, formatErrorForCli, formatGscPropertyCandidates, generateGscDateRange, getBackfillProgress, getDateRange, getFreshestGscDate, getIndexingEligibility, getIndexingMetadata, getLatestGscDate, getNextCheckAfter, getNextCheckPriority, getNextDate, getOldestGscDate, getPendingDates, getPreviousDate, getPstDate, getVerificationToken, getVerifiedSite, googleSearchConsole, grantedScopeList, groupIntoRanges, gscErrorToException, gscPropertyMatchesTarget, gscdumpApi, hasGoogleScope, hasGscReadScope, hasGscWriteScope, hasIndexingScope, hasOptionalIndexingScope, hasRequiredAnalyticsScope, indexingNextActions, indexingStatuses, inspectUrl, inspectUrlFlat, isErr, isOk, isPermissionDeniedError, isValidGscDate, isVerifiedGscPermission, isVerifiedGscProperty, lifecycleErrorCodes, lifecycleWebhookEvents, listVerifiedSites, mapErr, mapResult, matchGscSite, matchResult, normalizeGscSiteUrl, normalizeRegistrationTarget, normalizeSiteUrl, normalizeUrl, ok, parseGoogleError, parseGoogleScopes, parseGrantedScopes, parseGscSiteUrl, pickBestGscProperty, progressBar, propertyNextActions, propertyStatuses, querySourceModes, refreshAccessToken, refreshAccessTokenResult, requestIndexing, rethrowAsGscApiError, rowWithMetricDefaults, runSequentialBatch, siteUrlToVerificationSite, sitemapNextActions, sitemapStatuses, storageError, submitSitemap, toIsoDate, unmappedInspectionReasons, unverifySite, unwrapResult, urlMatchKey, verificationMethodsFor, verifySite };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gscdump",
3
3
  "type": "module",
4
- "version": "0.37.3",
4
+ "version": "0.37.5",
5
5
  "description": "Google Search Console API wrapper with typed query builder, streaming pagination, and SEO analysis functions",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",
@@ -62,6 +62,11 @@
62
62
  "import": "./dist/contracts.mjs",
63
63
  "default": "./dist/contracts.mjs"
64
64
  },
65
+ "./dates": {
66
+ "types": "./dist/dates.d.mts",
67
+ "import": "./dist/dates.mjs",
68
+ "default": "./dist/dates.mjs"
69
+ },
65
70
  "./normalize": {
66
71
  "types": "./dist/normalize.d.mts",
67
72
  "import": "./dist/normalize.mjs",
@@ -98,7 +103,7 @@
98
103
  "defu": "^6.1.7",
99
104
  "ofetch": "^1.5.1",
100
105
  "ufo": "^1.6.4",
101
- "@gscdump/contracts": "0.37.3"
106
+ "@gscdump/contracts": "0.37.5"
102
107
  },
103
108
  "devDependencies": {
104
109
  "@googleapis/indexing": "^6.0.1",