@gscdump/engine-gsc-api 0.17.4 → 0.18.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.
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { GoogleSearchConsoleClient } from "gscdump";
1
+ import { GoogleSearchConsoleClient, GscDataState, GscSearchAnalyticsMetadata } from "gscdump";
2
2
  import { BuilderState, Column, Dimension } from "gscdump/query";
3
3
  import { SearchType } from "@gscdump/engine";
4
4
  import { AnalysisQuerySource } from "@gscdump/engine/source";
@@ -82,10 +82,21 @@ interface RunGscSyncSliceOptions {
82
82
  client: GoogleSearchConsoleClient;
83
83
  siteUrl: string;
84
84
  /** One of the engine sync-fan tables. Drives the dimension list. */
85
- table: 'pages' | 'keywords' | 'countries' | 'devices' | 'page_keywords';
85
+ table: 'pages' | 'keywords' | 'countries' | 'devices' | 'page_keywords' | 'hourly_pages';
86
86
  startDate: string;
87
87
  endDate: string;
88
88
  domainFilter?: SyncSliceDomainFilter | null;
89
+ /**
90
+ * Override the dimension list for this slice. Defaults to
91
+ * `DIMENSIONS_BY_TABLE[table]`. Hosts that need bespoke groupings (e.g.
92
+ * hourly Discover variants) supply this directly.
93
+ */
94
+ dimensions?: string[];
95
+ /**
96
+ * GSC `dataState` for the query. Defaults to `'all'`. Use `'hourly_all'`
97
+ * for hourly Discover slices.
98
+ */
99
+ dataState?: GscDataState;
89
100
  /**
90
101
  * Invoked per GSC API page with the rows fetched. Return a promise; the
91
102
  * loop awaits it before paging further. Throw inside to abort; AbortError /
@@ -116,6 +127,12 @@ interface RunGscSyncSliceResult {
116
127
  totalRows: number;
117
128
  hasMore: boolean;
118
129
  nextStartRow: number;
130
+ /**
131
+ * Metadata from the LAST GSC API page seen during this slice run. When
132
+ * `dataState='hourly_all'` and grouped by `hour`, this surfaces
133
+ * `first_incomplete_hour` so hosts can watermark hourly progress.
134
+ */
135
+ metadata?: GscSearchAnalyticsMetadata;
119
136
  }
120
137
  declare function runGscSyncSlice(opts: RunGscSyncSliceOptions): Promise<RunGscSyncSliceResult>;
121
138
  export { type CreateLiveGscSourceOptions, type FetchTopNOptions, type GscApiQuerySourceOptions, type GscApiRow, type GscDailyRow, type GscRange, type GscTopNRow, type RunGscSyncSliceOptions, type RunGscSyncSliceResult, type SyncSliceDomainFilter, canProxyToGsc, createGscApiQuerySource, createLiveGscSource, fetchGscDaily, fetchGscTopN, runGscSyncSlice };
package/dist/index.mjs CHANGED
@@ -168,7 +168,8 @@ const DIMENSIONS_BY_TABLE = {
168
168
  "page",
169
169
  "query",
170
170
  "date"
171
- ]
171
+ ],
172
+ hourly_pages: ["hour", "page"]
172
173
  };
173
174
  function isTimeoutLike(err) {
174
175
  if (!(err instanceof Error)) return false;
@@ -187,22 +188,26 @@ async function runGscSyncSlice(opts) {
187
188
  const cpuBudgetMs = opts.cpuBudgetMs ?? 2e4;
188
189
  const maxPages = opts.maxPages ?? Infinity;
189
190
  const searchType = opts.searchType ?? "web";
190
- const dimensions = [...DIMENSIONS_BY_TABLE[opts.table]];
191
+ const dimensions = opts.dimensions ? [...opts.dimensions] : [...DIMENSIONS_BY_TABLE[opts.table]];
192
+ const dataState = opts.dataState ?? "all";
191
193
  const dimensionFilterGroups = buildDomainFilterGroups(opts.domainFilter);
192
194
  const loopStart = Date.now();
193
195
  let startRow = opts.initialStartRow ?? 0;
194
196
  let totalRows = 0;
195
197
  let pageCount = 0;
198
+ let metadata;
196
199
  while (true) {
197
200
  if (pageCount >= maxPages) return {
198
201
  totalRows,
199
202
  hasMore: true,
200
- nextStartRow: startRow
203
+ nextStartRow: startRow,
204
+ metadata
201
205
  };
202
206
  if (Date.now() - loopStart >= cpuBudgetMs) return {
203
207
  totalRows,
204
208
  hasMore: true,
205
- nextStartRow: startRow
209
+ nextStartRow: startRow,
210
+ metadata
206
211
  };
207
212
  const query = {
208
213
  startDate: opts.startDate,
@@ -210,8 +215,8 @@ async function runGscSyncSlice(opts) {
210
215
  dimensions,
211
216
  rowLimit,
212
217
  startRow,
213
- dataState: "all",
214
- searchType,
218
+ dataState,
219
+ type: searchType,
215
220
  ...dimensionFilterGroups ? { dimensionFilterGroups } : {}
216
221
  };
217
222
  const response = await opts.client._rawQuery(opts.siteUrl, query).catch((err) => {
@@ -221,11 +226,13 @@ async function runGscSyncSlice(opts) {
221
226
  if (!response) return {
222
227
  totalRows,
223
228
  hasMore: true,
224
- nextStartRow: startRow
229
+ nextStartRow: startRow,
230
+ metadata
225
231
  };
226
232
  const rows = response.rows ?? [];
227
233
  totalRows += rows.length;
228
234
  pageCount++;
235
+ if (response.metadata) metadata = response.metadata;
229
236
  opts.onPage?.({
230
237
  searchType,
231
238
  rowsThisPage: rows.length
@@ -240,7 +247,8 @@ async function runGscSyncSlice(opts) {
240
247
  return {
241
248
  totalRows,
242
249
  hasMore: false,
243
- nextStartRow: startRow
250
+ nextStartRow: startRow,
251
+ metadata
244
252
  };
245
253
  }
246
254
  export { canProxyToGsc, createGscApiQuerySource, createLiveGscSource, fetchGscDaily, fetchGscTopN, runGscSyncSlice };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gscdump/engine-gsc-api",
3
3
  "type": "module",
4
- "version": "0.17.4",
4
+ "version": "0.18.0",
5
5
  "description": "GSC live-API engine adapter — wraps the Search Analytics REST API as an AnalysisQuerySource for typed analyzer dispatch.",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",
@@ -36,8 +36,8 @@
36
36
  "node": ">=18"
37
37
  },
38
38
  "dependencies": {
39
- "@gscdump/engine": "0.17.4",
40
- "gscdump": "0.17.4"
39
+ "gscdump": "0.18.0",
40
+ "@gscdump/engine": "0.18.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "vitest": "^4.1.6"