@gscdump/sdk 1.0.1 → 1.0.3

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.
Files changed (52) hide show
  1. package/README.md +7 -1
  2. package/dist/_chunks/errors.d.mts +22 -0
  3. package/dist/_chunks/request.d.mts +25 -0
  4. package/dist/_chunks/request.mjs +84 -0
  5. package/dist/_chunks/search-console-signals.mjs +9 -0
  6. package/dist/analytics-client.d.mts +53 -0
  7. package/dist/analytics-client.mjs +128 -0
  8. package/dist/analyzer-defs.d.mts +73 -0
  9. package/dist/analyzer-defs.mjs +4 -0
  10. package/dist/anonymization.d.mts +6 -0
  11. package/dist/anonymization.mjs +12 -0
  12. package/dist/archetype-compile.d.mts +48 -0
  13. package/dist/archetype-compile.mjs +124 -0
  14. package/dist/client.d.mts +122 -0
  15. package/dist/client.mjs +365 -0
  16. package/dist/country-names.d.mts +2 -0
  17. package/dist/country-names.mjs +56 -0
  18. package/dist/cwv-thresholds.d.mts +13 -0
  19. package/dist/cwv-thresholds.mjs +23 -0
  20. package/dist/errors.d.mts +2 -0
  21. package/dist/errors.mjs +47 -0
  22. package/dist/gsc-console-url.d.mts +12 -0
  23. package/dist/gsc-console-url.mjs +15 -0
  24. package/dist/gsc-constants.d.mts +17 -0
  25. package/dist/gsc-constants.mjs +2 -0
  26. package/dist/gsc-error.d.mts +12 -0
  27. package/dist/gsc-error.mjs +42 -0
  28. package/dist/gsc-period-presets.d.mts +31 -0
  29. package/dist/gsc-period-presets.mjs +115 -0
  30. package/dist/gsc-rows.d.mts +54 -0
  31. package/dist/gsc-rows.mjs +48 -0
  32. package/dist/hosted-query.d.mts +31 -0
  33. package/dist/hosted-query.mjs +105 -0
  34. package/dist/index.d.mts +21 -852
  35. package/dist/index.mjs +21 -2275
  36. package/dist/indexing-issues.d.mts +29 -0
  37. package/dist/indexing-issues.mjs +168 -0
  38. package/dist/lifecycle.d.mts +14 -0
  39. package/dist/lifecycle.mjs +84 -0
  40. package/dist/period.d.mts +49 -0
  41. package/dist/period.mjs +138 -0
  42. package/dist/search-console-stage.d.mts +102 -0
  43. package/dist/search-console-stage.mjs +292 -0
  44. package/dist/site-baseline.d.mts +69 -0
  45. package/dist/site-baseline.mjs +112 -0
  46. package/dist/site-triage.d.mts +86 -0
  47. package/dist/site-triage.mjs +268 -0
  48. package/dist/v1/index.d.mts +1 -1
  49. package/dist/v1/index.mjs +2 -2
  50. package/dist/webhook.d.mts +29 -0
  51. package/dist/webhook.mjs +118 -0
  52. package/package.json +110 -5
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Google Search Console data is considered "unstable" for this many days from
3
+ * today (PST). Rows within the window may still shift as GSC finalizes clicks/
4
+ * impressions; charts render those points under a dimmed / striped overlay so
5
+ * users don't misread last-day dips as trends.
6
+ *
7
+ * This is the client DISPLAY-latency band, NOT the server lake-membership
8
+ * boundary. gscdump's `DEFAULT_STABILITY_CUTOFF_DAYS` (= 4) decides which days
9
+ * live in the Iceberg lake vs the recent overlay; this constant (= 3) only dims
10
+ * the UI. The display band is intentionally one day SMALLER so that, even at
11
+ * maximum UTC-vs-PST clock skew, the freshest UI-requested day is lake-resident
12
+ * (R2-SQL-complete) rather than overlay-only. The two are distinct concepts; do
13
+ * not unify them to a single value (gscdump plan
14
+ * `2026-06-24-overlay-canonical-merge-unification.md` W6).
15
+ */
16
+ declare const GSC_STABLE_LATENCY_DAYS = 3;
17
+ export { GSC_STABLE_LATENCY_DAYS };
@@ -0,0 +1,2 @@
1
+ const GSC_STABLE_LATENCY_DAYS = 3;
2
+ export { GSC_STABLE_LATENCY_DAYS };
@@ -0,0 +1,12 @@
1
+ type GscErrorStatus = 'auth-missing' | 'rate-limited' | 'network' | 'error';
2
+ interface GscClassifiedError {
3
+ status: GscErrorStatus;
4
+ /** HTTP status code if the error came from a response, otherwise undefined. */
5
+ code?: number;
6
+ /** Best-effort human message: server-supplied `message`, then `data.message`, then the error's own message. */
7
+ message?: string;
8
+ /** Seconds the server suggested waiting (429/503 retry payloads). */
9
+ retryAfter?: number;
10
+ }
11
+ declare function classifyGscError(e: unknown): GscClassifiedError;
12
+ export { GscClassifiedError, GscErrorStatus, classifyGscError };
@@ -0,0 +1,42 @@
1
+ function classifyGscError(e) {
2
+ const code = e?.statusCode ?? e?.status;
3
+ const message = extractMessage(e);
4
+ if (code === 401 || code === 403) return {
5
+ status: "auth-missing",
6
+ code,
7
+ message
8
+ };
9
+ if (code === 429 || code === 503) {
10
+ const data = e?.data;
11
+ const retry = data?.retryAfter ?? data?.retryAfterSeconds;
12
+ return {
13
+ status: code === 429 ? "rate-limited" : "network",
14
+ code,
15
+ message,
16
+ retryAfter: typeof retry === "number" ? retry : void 0
17
+ };
18
+ }
19
+ if (code == null && !isAbort(e)) return {
20
+ status: "network",
21
+ message
22
+ };
23
+ return {
24
+ status: "error",
25
+ code,
26
+ message
27
+ };
28
+ }
29
+ function extractMessage(e) {
30
+ if (!e || typeof e !== "object") return void 0;
31
+ const data = e.data;
32
+ if (data && typeof data === "object") {
33
+ const m = data.message ?? data.error;
34
+ if (typeof m === "string") return m;
35
+ }
36
+ const m = e.message;
37
+ return typeof m === "string" ? m : void 0;
38
+ }
39
+ function isAbort(e) {
40
+ return e?.name === "AbortError";
41
+ }
42
+ export { classifyGscError };
@@ -0,0 +1,31 @@
1
+ import { CompareMode, Period } from "./period.mjs";
2
+ type GscColumn = 'clicks' | 'impressions' | 'ctr' | 'position';
3
+ interface GscColumnOption {
4
+ key: GscColumn;
5
+ label: string;
6
+ icon: string;
7
+ color: string;
8
+ }
9
+ interface PeriodPreset {
10
+ value: Period;
11
+ label: string;
12
+ shortLabel: string;
13
+ group: 'rolling' | 'calendar';
14
+ }
15
+ declare const PERIOD_PRESETS: PeriodPreset[];
16
+ declare const COMPARE_OPTIONS: {
17
+ value: CompareMode;
18
+ label: string;
19
+ description: string;
20
+ }[];
21
+ declare const GSC_PERIOD_OPTIONS: {
22
+ label: string;
23
+ value: Period;
24
+ longLabel: string;
25
+ }[];
26
+ declare const GSC_PERIOD_OPTIONS_LONG: {
27
+ label: string;
28
+ value: Period;
29
+ }[];
30
+ declare const GSC_COLUMN_OPTIONS: GscColumnOption[];
31
+ export { COMPARE_OPTIONS, GSC_COLUMN_OPTIONS, GSC_PERIOD_OPTIONS, GSC_PERIOD_OPTIONS_LONG, GscColumn, GscColumnOption, PERIOD_PRESETS, PeriodPreset };
@@ -0,0 +1,115 @@
1
+ const PERIOD_PRESETS = [
2
+ {
3
+ value: "7d",
4
+ label: "Last 7 days",
5
+ shortLabel: "7d",
6
+ group: "rolling"
7
+ },
8
+ {
9
+ value: "28d",
10
+ label: "Last 28 days",
11
+ shortLabel: "28d",
12
+ group: "rolling"
13
+ },
14
+ {
15
+ value: "3m",
16
+ label: "Last 3 months",
17
+ shortLabel: "3m",
18
+ group: "rolling"
19
+ },
20
+ {
21
+ value: "6m",
22
+ label: "Last 6 months",
23
+ shortLabel: "6m",
24
+ group: "rolling"
25
+ },
26
+ {
27
+ value: "12m",
28
+ label: "Last 12 months",
29
+ shortLabel: "12m",
30
+ group: "rolling"
31
+ },
32
+ {
33
+ value: "this-week",
34
+ label: "This week",
35
+ shortLabel: "Week",
36
+ group: "calendar"
37
+ },
38
+ {
39
+ value: "this-month",
40
+ label: "This month",
41
+ shortLabel: "Month",
42
+ group: "calendar"
43
+ },
44
+ {
45
+ value: "last-month",
46
+ label: "Last month",
47
+ shortLabel: "Last mo",
48
+ group: "calendar"
49
+ },
50
+ {
51
+ value: "this-quarter",
52
+ label: "This quarter",
53
+ shortLabel: "Qtr",
54
+ group: "calendar"
55
+ },
56
+ {
57
+ value: "this-year",
58
+ label: "This year",
59
+ shortLabel: "Year",
60
+ group: "calendar"
61
+ }
62
+ ];
63
+ const COMPARE_OPTIONS = [
64
+ {
65
+ value: "previous",
66
+ label: "Previous period",
67
+ description: "Compare to the period immediately before"
68
+ },
69
+ {
70
+ value: "year",
71
+ label: "Year over year",
72
+ description: "Compare to the same period last year"
73
+ },
74
+ {
75
+ value: "none",
76
+ label: "No comparison",
77
+ description: "Disable comparison"
78
+ }
79
+ ];
80
+ const GSC_PERIOD_OPTIONS = PERIOD_PRESETS.filter((p) => p.group === "rolling").map((p) => ({
81
+ label: p.shortLabel,
82
+ value: p.value,
83
+ longLabel: p.label
84
+ }));
85
+ const GSC_PERIOD_OPTIONS_LONG = GSC_PERIOD_OPTIONS.map((o) => ({
86
+ label: o.longLabel,
87
+ value: o.value
88
+ }));
89
+ const GSC_COLUMN_OPTIONS = [
90
+ {
91
+ key: "clicks",
92
+ label: "Clicks",
93
+ icon: "i-lucide-mouse-pointer-click",
94
+ color: "blue"
95
+ },
96
+ {
97
+ key: "impressions",
98
+ label: "Views",
99
+ icon: "i-lucide-eye",
100
+ color: "purple"
101
+ },
102
+ {
103
+ key: "ctr",
104
+ label: "CTR",
105
+ icon: "i-lucide-percent",
106
+ color: "green"
107
+ },
108
+ {
109
+ key: "position",
110
+ label: "Pos",
111
+ icon: "i-lucide-hash",
112
+ color: "orange"
113
+ }
114
+ ];
115
+ export { COMPARE_OPTIONS, GSC_COLUMN_OPTIONS, GSC_PERIOD_OPTIONS, GSC_PERIOD_OPTIONS_LONG, PERIOD_PRESETS };
@@ -0,0 +1,54 @@
1
+ interface RawDailyRow {
2
+ date: string;
3
+ clicks: number;
4
+ impressions: number;
5
+ sum_position?: number;
6
+ position?: number;
7
+ }
8
+ interface CanonicalDailyRow {
9
+ date: string;
10
+ clicks: number;
11
+ impressions: number;
12
+ sum_position: number;
13
+ }
14
+ interface GscRowTotals {
15
+ clicks: number;
16
+ impressions: number;
17
+ ctr: number;
18
+ position: number;
19
+ }
20
+ interface GscDailySummary {
21
+ daily: CanonicalDailyRow[];
22
+ totals: GscRowTotals;
23
+ chartData: Array<{
24
+ date: string;
25
+ clicks: number;
26
+ impressions: number;
27
+ }>;
28
+ }
29
+ /**
30
+ * Fill `sum_position` from `(position - 1) * impressions` when the row only
31
+ * carries `position`. GSC positions are 1-based and 0/absent is a no-data
32
+ * sentinel — the old `Math.max(1, …)` clamp synthesized rank #1 (sum 0 with
33
+ * full impression weight) for such rows instead of contributing nothing.
34
+ */
35
+ declare function coerceRowMetrics<T extends {
36
+ impressions: number;
37
+ sum_position?: number;
38
+ position?: number;
39
+ }>(row: T): T & {
40
+ sum_position: number;
41
+ };
42
+ /** Sort daily rows by date asc, coerce `sum_position`, reduce totals, derive chartData. */
43
+ declare function summarizeDailyRows(raw: readonly RawDailyRow[]): GscDailySummary;
44
+ /**
45
+ * Rollup-row position helper. `sum_position` is GSC's average-position sum
46
+ * across impressions; dividing back out (+1 because GSC is 1-indexed) gives
47
+ * the impression-weighted average position. Returns 0 when there were no
48
+ * impressions so the column renders blank rather than NaN.
49
+ */
50
+ declare function positionFor(r: {
51
+ impressions: number;
52
+ sum_position: number;
53
+ }): number;
54
+ export { CanonicalDailyRow, GscDailySummary, GscRowTotals, RawDailyRow, coerceRowMetrics, positionFor, summarizeDailyRows };
@@ -0,0 +1,48 @@
1
+ function coerceRowMetrics(row) {
2
+ const position = row.position ?? 0;
3
+ return {
4
+ ...row,
5
+ sum_position: row.sum_position ?? (position > 0 ? (position - 1) * row.impressions : 0)
6
+ };
7
+ }
8
+ function summarizeDailyRows(raw) {
9
+ const daily = [];
10
+ for (let index = 0; index < raw.length; index++) {
11
+ const row = raw[index];
12
+ const position = row.position ?? 0;
13
+ const sumPosition = row.sum_position ?? (position > 0 ? (position - 1) * row.impressions : 0);
14
+ daily.push({
15
+ date: row.date,
16
+ clicks: row.clicks,
17
+ impressions: row.impressions,
18
+ sum_position: sumPosition
19
+ });
20
+ }
21
+ daily.sort((a, b) => a.date.localeCompare(b.date));
22
+ let clicks = 0;
23
+ let impressions = 0;
24
+ let weightedPosition = 0;
25
+ for (const row of daily) {
26
+ clicks += row.clicks;
27
+ impressions += row.impressions;
28
+ weightedPosition += row.sum_position;
29
+ }
30
+ return {
31
+ daily,
32
+ totals: {
33
+ clicks,
34
+ impressions,
35
+ ctr: impressions > 0 ? clicks / impressions : 0,
36
+ position: impressions > 0 ? weightedPosition / impressions + 1 : 0
37
+ },
38
+ chartData: daily.map((d) => ({
39
+ date: d.date,
40
+ clicks: d.clicks,
41
+ impressions: d.impressions
42
+ }))
43
+ };
44
+ }
45
+ function positionFor(r) {
46
+ return r.impressions > 0 ? r.sum_position / r.impressions + 1 : 0;
47
+ }
48
+ export { coerceRowMetrics, positionFor, summarizeDailyRows };
@@ -0,0 +1,31 @@
1
+ import { BuilderStateWire, DataDetailOptions, DataQueryOptions, GscdumpPageTrendParams, GscdumpQueryTrendParams, IndexingDiagnosticsParams, IndexingUrlsParams, SourceInfoOptions } from "@gscdump/contracts";
2
+ type GscSearchType = 'web' | 'image' | 'video' | 'news' | 'discover' | 'googleNews';
3
+ interface SearchTypeOptions {
4
+ searchType?: GscSearchType;
5
+ }
6
+ interface SourceRangeOptions {
7
+ start?: string;
8
+ end?: string;
9
+ startDate?: string;
10
+ endDate?: string;
11
+ }
12
+ interface AnalysisSourcesOptions extends SearchTypeOptions, SourceRangeOptions {
13
+ tables?: string[] | string;
14
+ maxBytes?: number;
15
+ maxRows?: number;
16
+ maxFiles?: number;
17
+ }
18
+ declare const DEFAULT_SEARCH_TYPE: GscSearchType;
19
+ declare function withDefaultSearchType<T extends object>(value: T, searchType?: GscSearchType): T & SearchTypeOptions & Record<string, unknown>;
20
+ declare function withDefaultSearchType<T>(value: T, searchType?: GscSearchType): T;
21
+ declare function searchTypeQuery(searchType?: GscSearchType): Record<string, string>;
22
+ declare function dateRangeOptionsQuery(options: SourceRangeOptions | undefined): Record<string, string>;
23
+ declare function sourceInfoQuery(options: SourceInfoOptions | undefined): Record<string, string>;
24
+ declare function tablesQuery(tablesOrOptions: string[] | string | AnalysisSourcesOptions | undefined, options?: AnalysisSourcesOptions): Record<string, string>;
25
+ declare function dataQuery(state: BuilderStateWire, options?: DataQueryOptions): Record<string, string>;
26
+ declare function dataDetailQuery(state: BuilderStateWire, options?: DataDetailOptions): Record<string, string>;
27
+ declare function indexingUrlsQuery(params?: IndexingUrlsParams): Record<string, string | number>;
28
+ declare function indexingDiagnosticsQuery(params?: IndexingDiagnosticsParams): Record<string, string | number>;
29
+ declare function queryTrendQuery(params: GscdumpQueryTrendParams): Record<string, string>;
30
+ declare function pageTrendQuery(params: GscdumpPageTrendParams): Record<string, string>;
31
+ export { AnalysisSourcesOptions, DEFAULT_SEARCH_TYPE, GscSearchType, SearchTypeOptions, SourceRangeOptions, dataDetailQuery, dataQuery, dateRangeOptionsQuery, indexingDiagnosticsQuery, indexingUrlsQuery, pageTrendQuery, queryTrendQuery, searchTypeQuery, sourceInfoQuery, tablesQuery, withDefaultSearchType };
@@ -0,0 +1,105 @@
1
+ const DEFAULT_SEARCH_TYPE = "web";
2
+ function isAnalysisSourcesOptions(value) {
3
+ return !!value && typeof value === "object" && !Array.isArray(value);
4
+ }
5
+ function withDefaultSearchType(value, searchType) {
6
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
7
+ const scoped = value;
8
+ return {
9
+ ...scoped,
10
+ searchType: searchType ?? scoped.searchType ?? "web"
11
+ };
12
+ }
13
+ function searchTypeQuery(searchType) {
14
+ return { searchType: searchType ?? "web" };
15
+ }
16
+ function stableJson(value) {
17
+ if (value == null || typeof value !== "object") return JSON.stringify(value) ?? "null";
18
+ if (Array.isArray(value)) return `[${value.map((item) => item === void 0 ? "null" : stableJson(item)).join(",")}]`;
19
+ return `{${Object.entries(value).filter(([, item]) => item !== void 0).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => `${JSON.stringify(key)}:${stableJson(item)}`).join(",")}}`;
20
+ }
21
+ function dateRangeOptionsQuery(options) {
22
+ const query = {};
23
+ const start = options?.start ?? options?.startDate;
24
+ const end = options?.end ?? options?.endDate;
25
+ if (start) query.start = start;
26
+ if (end) query.end = end;
27
+ return query;
28
+ }
29
+ function sourceInfoQuery(options) {
30
+ return {
31
+ ...searchTypeQuery(options?.searchType),
32
+ ...dateRangeOptionsQuery(options)
33
+ };
34
+ }
35
+ function tablesQuery(tablesOrOptions, options) {
36
+ const tables = isAnalysisSourcesOptions(tablesOrOptions) ? tablesOrOptions.tables : tablesOrOptions;
37
+ const source = isAnalysisSourcesOptions(tablesOrOptions) ? tablesOrOptions : options;
38
+ const query = {
39
+ ...searchTypeQuery(source?.searchType),
40
+ ...dateRangeOptionsQuery(source)
41
+ };
42
+ if (tables) query.tables = Array.isArray(tables) ? [...new Set(tables.filter(Boolean))].sort().join(",") : [...new Set(tables.split(",").map((t) => t.trim()).filter(Boolean))].sort().join(",");
43
+ if (source?.maxBytes != null) query.maxBytes = String(Math.max(1, Math.floor(source.maxBytes)));
44
+ if (source?.maxRows != null) query.maxRows = String(Math.max(1, Math.floor(source.maxRows)));
45
+ if (source?.maxFiles != null) query.maxFiles = String(Math.max(1, Math.floor(source.maxFiles)));
46
+ return query;
47
+ }
48
+ function dataQuery(state, options) {
49
+ const opts = options;
50
+ const scoped = withDefaultSearchType(state, opts?.searchType);
51
+ const query = {
52
+ q: stableJson(scoped),
53
+ searchType: scoped.searchType ?? "web"
54
+ };
55
+ if (opts?.comparison) query.qc = stableJson(withDefaultSearchType(opts.comparison, scoped.searchType));
56
+ if (opts?.filter) query.filter = opts.filter;
57
+ return query;
58
+ }
59
+ function dataDetailQuery(state, options) {
60
+ const opts = options;
61
+ const scoped = withDefaultSearchType(state, opts?.searchType);
62
+ const query = {
63
+ q: stableJson(scoped),
64
+ searchType: scoped.searchType ?? "web"
65
+ };
66
+ if (opts?.comparison) query.qc = stableJson(withDefaultSearchType(opts.comparison, scoped.searchType));
67
+ return query;
68
+ }
69
+ function indexingUrlsQuery(params = {}) {
70
+ const query = {};
71
+ if (params.limit != null) query.limit = params.limit;
72
+ if (params.offset != null) query.offset = params.offset;
73
+ if (params.status) query.status = params.status;
74
+ if (params.issue) query.issue = params.issue;
75
+ if (params.search) query.search = params.search;
76
+ if (params.count === 0 || params.count === false) query.count = 0;
77
+ return query;
78
+ }
79
+ function indexingDiagnosticsQuery(params = {}) {
80
+ const query = {};
81
+ if (params.sampleIssues) query.sampleIssues = Array.isArray(params.sampleIssues) ? [...new Set(params.sampleIssues.map((item) => String(item).trim()).filter(Boolean))].sort().join(",") : params.sampleIssues;
82
+ if (params.sampleLimit != null) query.sampleLimit = params.sampleLimit;
83
+ return query;
84
+ }
85
+ function queryTrendQuery(params) {
86
+ const query = {
87
+ startDate: params.startDate,
88
+ endDate: params.endDate,
89
+ searchType: params.searchType ?? "web"
90
+ };
91
+ if (params.prevStartDate) query.prevStartDate = params.prevStartDate;
92
+ if (params.prevEndDate) query.prevEndDate = params.prevEndDate;
93
+ return query;
94
+ }
95
+ function pageTrendQuery(params) {
96
+ const query = {
97
+ startDate: params.startDate,
98
+ endDate: params.endDate,
99
+ searchType: params.searchType ?? "web"
100
+ };
101
+ if (params.prevStartDate) query.prevStartDate = params.prevStartDate;
102
+ if (params.prevEndDate) query.prevEndDate = params.prevEndDate;
103
+ return query;
104
+ }
105
+ export { DEFAULT_SEARCH_TYPE, dataDetailQuery, dataQuery, dateRangeOptionsQuery, indexingDiagnosticsQuery, indexingUrlsQuery, pageTrendQuery, queryTrendQuery, searchTypeQuery, sourceInfoQuery, tablesQuery, withDefaultSearchType };