gscdump 0.0.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,172 @@
1
+ # gscdump
2
+
3
+ [![npm version](https://img.shields.io/npm/v/gscdump?color=yellow)](https://npmjs.com/package/gscdump)
4
+ [![npm downloads](https://img.shields.io/npm/dm/gscdump?color=yellow)](https://npm.chart.dev/gscdump)
5
+ [![license](https://img.shields.io/github/license/harlan-zw/gscdump?color=yellow)](https://github.com/harlan-zw/gscdump/blob/main/LICENSE)
6
+
7
+ > Google Search Console API wrapper with typed query builder, streaming pagination, and SEO analysis functions.
8
+
9
+ ## Features
10
+
11
+ - **Typed Query Builder** - Drizzle-style API with filter constraints narrowing result types
12
+ - **Streaming Pagination** - Memory-efficient iteration over large datasets (>25k rows)
13
+ - **SEO Analysis** - Pure functions for cannibalization, striking distance, movers & shakers, decay detection
14
+ - **Edge-Compatible** - Works in Cloudflare Workers, Deno, and other edge runtimes
15
+ - **Full API Coverage** - Sites, sitemaps, indexing, and analytics
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ npm install gscdump
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```ts
26
+ import { daysAgo, today } from '@gscdump/query'
27
+ import { fetchKeywordsWithComparison, fetchPagesWithComparison } from 'gscdump'
28
+
29
+ // Auth accepts token string or object
30
+ const auth = 'ya29.xxx...'
31
+ // or: { accessToken: 'ya29.xxx...' }
32
+
33
+ const range = {
34
+ period: { start: daysAgo(28), end: today() },
35
+ }
36
+
37
+ // Pages with top keyword per page
38
+ const pages = await fetchPagesWithComparison(auth, site, range)
39
+
40
+ // Keywords with change percentages
41
+ const keywords = await fetchKeywordsWithComparison(auth, site, range)
42
+ ```
43
+
44
+ ### Streaming Large Datasets
45
+
46
+ For memory-efficient pagination of large datasets (>25k rows):
47
+
48
+ ```ts
49
+ import { queryRecursiveStream } from 'gscdump'
50
+
51
+ // Stream keyword+page combinations - yields batches as they're fetched
52
+ for await (const batch of queryRecursiveStream(client, site, {
53
+ dimensions: ['query', 'page'] as const, // as const required for type inference
54
+ startDate: '2024-01-01',
55
+ endDate: '2024-01-31',
56
+ })) {
57
+ // batch: { keyword: string, page: string, clicks, impressions, ctr, position }[]
58
+ await db.insert(batch)
59
+ }
60
+ ```
61
+
62
+ ### Typed Query Builder
63
+
64
+ Drizzle-style query builder with full type safety. Filter constraints flow through to result types.
65
+
66
+ ```ts
67
+ import { and, between, contains, country, Country, date, device, Device, eq, gsc, inArray, page } from 'gscdump/query'
68
+
69
+ const result = await gsc
70
+ .select('page', 'query', 'device', 'country')
71
+ .where(and(
72
+ eq(device, Device.MOBILE),
73
+ inArray(country, [Country.USA, Country.GBR]),
74
+ contains(page, '/blog/'),
75
+ between(date, '2024-01-01', '2024-01-31')
76
+ ))
77
+ .siteUrl('https://example.com')
78
+ .execute(client)
79
+
80
+ // Fully typed results - narrowed by filters
81
+ result.rows[0].device // type: 'MOBILE' (narrowed by eq)
82
+ result.rows[0].country // type: 'usa' | 'gbr' (narrowed by inArray)
83
+ result.rows[0].page // type: string (contains doesn't narrow)
84
+ result.rows[0].clicks // type: number
85
+ ```
86
+
87
+ **With date helpers:**
88
+
89
+ ```ts
90
+ import { daysAgo, today } from '@gscdump/query'
91
+ import { and, between, date, gsc, query, regex } from 'gscdump/query'
92
+
93
+ const q = gsc
94
+ .select('query', 'page')
95
+ .where(and(
96
+ between(date, daysAgo(28), today()),
97
+ regex(query, /how to/)
98
+ ))
99
+ .limit(100)
100
+ ```
101
+
102
+ **Operators:**
103
+
104
+ | Operator | Narrows Type? | Description |
105
+ |----------|---------------|-------------|
106
+ | `eq(col, val)` | ✓ | Exact match |
107
+ | `ne(col, val)` | ✗ | Not equal |
108
+ | `inArray(col, [a, b])` | ✓ | Value in array (becomes `a \| b`) |
109
+ | `contains(col, str)` | ✗ | String contains |
110
+ | `like(col, '%pattern%')` | ✗ | SQL LIKE pattern |
111
+ | `regex(col, /pattern/)` | ✗ | Regex match |
112
+ | `notRegex(col, /pattern/)` | ✗ | Regex exclusion |
113
+ | `between(col, start, end)` | ✗ | Inclusive range (primarily for date) |
114
+ | `gte(col, val)` | ✗ | Greater than or equal |
115
+ | `lte(col, val)` | ✗ | Less than or equal |
116
+ | `gt(col, val)` | ✗ | Greater than |
117
+ | `lt(col, val)` | ✗ | Less than |
118
+ | `and(...filters)` | ✓ | Merge constraints |
119
+ | `or(...filters)` | ✗ | Any match |
120
+ | `not(filter)` | ✗ | Invert filter |
121
+
122
+ ### Analysis Functions
123
+
124
+ Analysis functions are pure - they operate on typed data arrays and return typed results.
125
+
126
+ ```ts
127
+ import {
128
+ analyzeCannibalization,
129
+ analyzeDecay,
130
+ analyzeMovers,
131
+ analyzeStrikingDistance,
132
+ fetchKeywordsWithComparison,
133
+ } from 'gscdump'
134
+
135
+ // Fetch data first
136
+ const { current, previous } = await fetchKeywordsWithComparison(auth, site, range)
137
+
138
+ // Run pure analysis on the data
139
+ const striking = analyzeStrikingDistance(current)
140
+ const movers = analyzeMovers(current, previous)
141
+ const decay = analyzeDecay(current, previous)
142
+ const cannibalization = analyzeCannibalization(keywordPageData)
143
+ ```
144
+
145
+ ## Exports
146
+
147
+ **Sites:** `fetchSites`, `fetchSitesWithSitemaps`, `fetchSitemaps`, `getSitemap`, `submitSitemap`, `deleteSitemap`, `inspectUrl`, `batchInspectUrls`
148
+
149
+ **Indexing:** `requestIndexing`, `getIndexingMetadata`, `batchRequestIndexing`
150
+
151
+ **Analytics:** `fetchAnalyticsWithComparison`, `fetchPagesWithComparison`, `fetchKeywordsWithComparison`, `fetchDevicesWithComparison`, `fetchCountriesWithComparison`, `fetchSearchAppearanceWithComparison`, `fetchDates`, `fetchDatesWithComparison`, `fetchPages`, `fetchPage`, `fetchKeyword`
152
+
153
+ **Analysis (Pure):** `analyzeStrikingDistance`, `analyzeOpportunity`, `analyzeBrandSegmentation`, `analyzeConcentration`, `analyzeDecay`, `analyzeMovers`, `analyzeCannibalization`, `analyzeZeroClick`, `analyzeSeasonality`, `analyzeClustering`
154
+
155
+ **Low-level:** `gscClient`, `queryRecursive`, `queryRecursiveStream`, `createQueryBody`, `withPropertyAggregation`, `withSearchAppearance`, `withDataType`, `withFreshData`, `withFinalData`
156
+
157
+ **Query Builder (`gscdump/query`):** `gsc`, `eq`, `ne`, `and`, `or`, `inArray`, `contains`, `like`, `regex`, `notRegex`, `not`, `between`, `gte`, `gt`, `lte`, `lt`, `page`, `query`, `device`, `country`, `date`, `searchAppearance`, `Device`, `Country`
158
+
159
+ **Error Utilities:** `isQuotaError`, `isRateLimitError`, `isAuthError`, `getErrorCode`, `getErrorMessage`, `getRetryAfter`, `analyzeGscError`, `formatGscErrorForCli`
160
+
161
+ **Utils:** `formatDateGsc`, `percentDifference`
162
+
163
+ ## Related Packages
164
+
165
+ - [`@gscdump/cli`](../cli) - CLI for dump, sync, compare, analyze
166
+ - [`@gscdump/mcp`](../mcp) - MCP server for AI agents
167
+ - [`@gscdump/db`](../db) - SQLite persistence
168
+ - [`@gscdump/query`](../query) - Unified data provider
169
+
170
+ ## License
171
+
172
+ [MIT](../../LICENSE)