@gscdump/engine 0.38.2 → 0.40.1

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.mjs CHANGED
@@ -3,7 +3,7 @@ import { DEFAULT_SEARCH_TYPE, dayPartition, hourPartition, inferLegacyTier, infe
3
3
  import { SCHEMAS, TABLE_METADATA, allTables, countries, currentSchemaVersion, dates, dimensionToColumn, drizzleSchema, hourly_pages, inferTable, page_queries, pages, queries } from "./_chunks/schema.mjs";
4
4
  import { enumeratePartitions } from "./_chunks/compaction.mjs";
5
5
  import { FILES_PLACEHOLDER, resolveParquetSQL, substituteNamedFiles } from "./_chunks/parquet-plan.mjs";
6
- import { engineErrorToException, engineErrors, formatEngineError, isEngineError } from "./errors.mjs";
6
+ import { engineErrorToException, engineErrors, isEngineError } from "./errors.mjs";
7
7
  import { bindLiterals, formatLiteral } from "./sql-bind.mjs";
8
8
  import { MAX_DAY_BYTES, canonicalEmptyParquetSchema, createDuckDBCodec, createDuckDBExecutor, createStorageEngine } from "./_chunks/engine.mjs";
9
9
  import { assembleDatesRow, createRowAccumulator, toPath, toSumPosition, transformGscRow } from "./ingest.mjs";
@@ -13,12 +13,6 @@ import { rebuildDailyFromHourly } from "./rollups.mjs";
13
13
  import { fixedPolicy, inspectionPolicy, sitemapPolicy } from "./schedule.mjs";
14
14
  import { ENGINE_QUERY_CAPABILITIES, createSqlQuerySource } from "./_chunks/source.mjs";
15
15
  import { err, ok, unwrapResult } from "gscdump/result";
16
- const NOOP_RESULT = {
17
- flushed: 0,
18
- recovered: 0,
19
- failed: 0,
20
- rowsWritten: 0
21
- };
22
16
  function scopeOf(ctx, table, date) {
23
17
  return {
24
18
  userId: String(ctx.userId),
@@ -28,16 +22,6 @@ function scopeOf(ctx, table, date) {
28
22
  ...ctx.searchType !== void 0 ? { searchType: ctx.searchType } : {}
29
23
  };
30
24
  }
31
- function createNoopIngestAccumulator() {
32
- return {
33
- push() {
34
- return false;
35
- },
36
- async finalize() {
37
- return NOOP_RESULT;
38
- }
39
- };
40
- }
41
25
  function createIngestAccumulator(opts) {
42
26
  const { engine, ctx, hooks, ...accOpts } = opts;
43
27
  const acc = createRowAccumulator(accOpts);
@@ -331,4 +315,4 @@ const MIN_SYNC_IMPRESSIONS = 1;
331
315
  const MIN_COUNTRY_IMPRESSIONS = 10;
332
316
  const MAX_SITEMAP_URLS_PER_SITE = 5e4;
333
317
  const MAX_TRACKED_URLS_PER_SITE = 2e5;
334
- export { DEFAULT_SEARCH_TYPE, ENGINE_QUERY_CAPABILITIES, FILES_PLACEHOLDER, MAX_DAY_BYTES, MAX_GSC_PAGES_R2, MAX_SITEMAP_URLS_PER_SITE, MAX_TRACKED_URLS_PER_SITE, MIN_COUNTRY_IMPRESSIONS, MIN_SYNC_IMPRESSIONS, ROW_LIMIT_R2, SCHEMAS, TABLES_BY_SEARCH_TYPE, TABLE_METADATA, TABLE_TIERS, TIER_PRIORITY, WEIGHT_PRIORITY, allTables, assembleDatesRow, bindLiterals, canonicalEmptyParquetSchema, coerceRow, coerceRows, collectSpans, countries, createDuckDBCodec, createDuckDBExecutor, createIcebergResolverAdapter, createInMemorySink, createIngestAccumulator, createNoopIngestAccumulator, createParquetResolverAdapter, createQueryProfiler, createR2SqlResolverAdapter, createRowAccumulator, createSqlQuerySource, createStorageEngine, currentSchemaVersion, dates, dayPartition, dimensionToColumn, drizzleSchema, engineErrorToException, engineErrors, enumeratePartitions, fixedPolicy, formatEngineError, formatLiteral, getDateWeight, getTableTier, getTablesForTier, hourPartition, hourly_pages, inferLegacyTier, inferSearchType, inferTable, inspectionPolicy, isEngineError, objectKey, page_queries, pages, parseEnabledSearchTypes, pgResolverAdapter, queries, rebuildDailyFromHourly, resolveParquetSQL, sitemapPolicy, substituteNamedFiles, toPath, toSumPosition, transformGscRow, validateEnabledSearchTypes, validateEnabledSearchTypesResult };
318
+ export { DEFAULT_SEARCH_TYPE, ENGINE_QUERY_CAPABILITIES, FILES_PLACEHOLDER, MAX_DAY_BYTES, MAX_GSC_PAGES_R2, MAX_SITEMAP_URLS_PER_SITE, MAX_TRACKED_URLS_PER_SITE, MIN_COUNTRY_IMPRESSIONS, MIN_SYNC_IMPRESSIONS, ROW_LIMIT_R2, SCHEMAS, TABLES_BY_SEARCH_TYPE, TABLE_METADATA, TABLE_TIERS, TIER_PRIORITY, WEIGHT_PRIORITY, allTables, assembleDatesRow, bindLiterals, canonicalEmptyParquetSchema, coerceRow, coerceRows, collectSpans, countries, createDuckDBCodec, createDuckDBExecutor, createIcebergResolverAdapter, createInMemorySink, createIngestAccumulator, createParquetResolverAdapter, createQueryProfiler, createR2SqlResolverAdapter, createRowAccumulator, createSqlQuerySource, createStorageEngine, currentSchemaVersion, dates, dayPartition, dimensionToColumn, drizzleSchema, engineErrorToException, engineErrors, enumeratePartitions, fixedPolicy, formatLiteral, getDateWeight, getTableTier, getTablesForTier, hourPartition, hourly_pages, inferLegacyTier, inferSearchType, inferTable, inspectionPolicy, isEngineError, objectKey, page_queries, pages, parseEnabledSearchTypes, pgResolverAdapter, queries, rebuildDailyFromHourly, resolveParquetSQL, sitemapPolicy, substituteNamedFiles, toPath, toSumPosition, transformGscRow, validateEnabledSearchTypes, validateEnabledSearchTypesResult };
package/dist/ingest.d.mts CHANGED
@@ -16,8 +16,6 @@ interface GscApiRow {
16
16
  position: number;
17
17
  }
18
18
  interface IngestOptions {
19
- /** @deprecated Canonical query data is built through query_dim, not fact rows. */
20
- normalizeQuery?: (query: string) => string | null | undefined;
21
19
  /** Date for one-day `searchAppearance` total queries, whose keys omit date. */
22
20
  date?: string;
23
21
  /** Search appearance filter used for contextual second-step rows. */
@@ -1,2 +1,2 @@
1
- import { AnalysisPeriod, ComparisonMode, ComparisonPeriod, PadTimeseriesOptions, ResolveWindowOptions, ResolvedWindow, WindowPreset, comparisonOf, defaultEndDate, defaultStartDate, padTimeseries, periodOf, resolveWindow, windowToComparisonPeriod, windowToPeriod } from "../_chunks/index2.mjs";
2
- export { AnalysisPeriod, ComparisonMode, ComparisonPeriod, PadTimeseriesOptions, ResolveWindowOptions, ResolvedWindow, WindowPreset, comparisonOf, defaultEndDate, defaultStartDate, padTimeseries, periodOf, resolveWindow, windowToComparisonPeriod, windowToPeriod };
1
+ import { AnalysisPeriod, ComparisonMode, ComparisonPeriod, PadTimeseriesOptions, ResolveWindowOptions, ResolvedWindow, WindowPreset, comparisonOf, defaultEndDate, defaultStartDate, padTimeseries, periodOf, resolveWindow } from "../_chunks/index2.mjs";
2
+ export { AnalysisPeriod, ComparisonMode, ComparisonPeriod, PadTimeseriesOptions, ResolveWindowOptions, ResolvedWindow, WindowPreset, comparisonOf, defaultEndDate, defaultStartDate, padTimeseries, periodOf, resolveWindow };
@@ -96,25 +96,6 @@ function resolveWindow(opts) {
96
96
  }
97
97
  return result;
98
98
  }
99
- function windowToPeriod(w) {
100
- return {
101
- startDate: w.start,
102
- endDate: w.end
103
- };
104
- }
105
- function windowToComparisonPeriod(w) {
106
- if (!w.comparison) return void 0;
107
- return {
108
- current: {
109
- startDate: w.start,
110
- endDate: w.end
111
- },
112
- previous: {
113
- startDate: w.comparison.start,
114
- endDate: w.comparison.end
115
- }
116
- };
117
- }
118
99
  const DEFAULT_FILL = {
119
100
  clicks: 0,
120
101
  impressions: 0,
@@ -147,4 +128,4 @@ function padTimeseries(rows, options) {
147
128
  }
148
129
  return result;
149
130
  }
150
- export { comparisonOf, defaultEndDate, defaultStartDate, padTimeseries, periodOf, resolveWindow, windowToComparisonPeriod, windowToPeriod };
131
+ export { comparisonOf, defaultEndDate, defaultStartDate, padTimeseries, periodOf, resolveWindow };
@@ -48,8 +48,6 @@ interface SqlFragmentsConfig<TableKey extends string> {
48
48
  queryDimTableRef?: () => SQL;
49
49
  /** When true, also joins query_dim on site_id (SQLite/D1 dimension table). */
50
50
  queryDimSiteScoped?: boolean;
51
- /** @deprecated Canonical reads now derive from query_dim or canonical rollups. */
52
- canonicalFallback?: boolean;
53
51
  }
54
52
  interface SqlFragments<TableKey extends string> {
55
53
  METRIC_NAMES: Metric[];
@@ -175,11 +173,6 @@ interface ResolveExtraFn {
175
173
  interface RunOptimizedQueryOptions {
176
174
  /** Overlay tried per extra before the live SQL; absent → today's live path. */
177
175
  resolveExtra?: ResolveExtraFn;
178
- /**
179
- * Deprecated compatibility flag. Canonical reads now derive from query_dim,
180
- * not a nullable fact-table `query_canonical` column.
181
- */
182
- canonicalFallback?: boolean;
183
176
  /**
184
177
  * Versioned query dimension backing canonical reads over fact rows. Required
185
178
  * whenever a query groups or filters by `queryCanonical`; a canonical rollup
@@ -218,11 +211,6 @@ interface RunOptimizedQueryOptions {
218
211
  coversThrough?: string;
219
212
  queryDim?: CanonicalQueryDimSource;
220
213
  };
221
- /**
222
- * @deprecated Canonical-source misses are recorded on `source.fallbacks`;
223
- * raw daily fallback is controlled by `primarySourceFallback: 'raw'`.
224
- */
225
- canonicalSourceFallback?: 'raw';
226
214
  /** Optional version gates for the query dimension backing `canonicalSource`. */
227
215
  canonicalRequirements?: {
228
216
  normalizerVersion?: number;
package/dist/rollups.mjs CHANGED
@@ -195,26 +195,42 @@ function planRollupWindows(parts, clampRange, maxWindowDays) {
195
195
  });
196
196
  }
197
197
  if (spans.length === 0) return [];
198
- let rangeStartMs = Math.min(...spans.map((s) => s.startMs));
199
- let rangeEndMs = Math.max(...spans.map((s) => s.endMs));
198
+ let rangeStartMs = Number.POSITIVE_INFINITY;
199
+ let rangeEndMs = Number.NEGATIVE_INFINITY;
200
+ let totalBytes = 0;
201
+ for (const span of spans) {
202
+ if (span.startMs < rangeStartMs) rangeStartMs = span.startMs;
203
+ if (span.endMs > rangeEndMs) rangeEndMs = span.endMs;
204
+ totalBytes += span.bytes;
205
+ }
200
206
  if (clampStartMs !== void 0) rangeStartMs = Math.max(rangeStartMs, clampStartMs);
201
207
  if (clampEndMs !== void 0) rangeEndMs = Math.min(rangeEndMs, clampEndMs);
202
- const totalBytes = spans.reduce((a, s) => a + s.bytes, 0);
203
208
  const spanDays = Math.floor((rangeEndMs - rangeStartMs) / MS_PER_DAY) + 1;
204
209
  const bytesPerDay = Math.max(1, totalBytes / spanDays);
205
210
  const byteWindowDays = clamp(Math.floor(WINDOW_BYTE_BUDGET / bytesPerDay), 7, 400);
206
211
  const windowDays = maxWindowDays != null ? Math.max(1, Math.min(byteWindowDays, maxWindowDays)) : byteWindowDays;
212
+ if (!Number.isFinite(windowDays) || !Number.isFinite(rangeStartMs) || !Number.isFinite(rangeEndMs) || rangeEndMs < rangeStartMs) return [];
213
+ const windowWidthMs = windowDays * MS_PER_DAY;
214
+ const windowCount = Math.floor((rangeEndMs - rangeStartMs) / windowWidthMs) + 1;
215
+ const partitionsByWindow = Array.from({ length: windowCount }, () => []);
216
+ for (const span of spans) {
217
+ const overlapStartMs = Math.max(span.startMs, rangeStartMs);
218
+ const overlapEndMs = Math.min(span.endMs, rangeEndMs);
219
+ if (overlapStartMs > overlapEndMs) continue;
220
+ const firstWindow = Math.max(0, Math.ceil((overlapStartMs - rangeStartMs - (windowDays - 1) * MS_PER_DAY) / windowWidthMs));
221
+ const lastWindow = Math.min(windowCount - 1, Math.floor((overlapEndMs - rangeStartMs) / windowWidthMs));
222
+ for (let index = firstWindow; index <= lastWindow; index++) partitionsByWindow[index].push(span.partition);
223
+ }
207
224
  const windows = [];
208
- let cursorMs = rangeStartMs;
209
- while (cursorMs <= rangeEndMs) {
225
+ for (let index = 0; index < windowCount; index++) {
226
+ const cursorMs = rangeStartMs + index * windowWidthMs;
210
227
  const windowEndMs = Math.min(cursorMs + (windowDays - 1) * MS_PER_DAY, rangeEndMs);
211
- const partitions = spans.filter((s) => s.endMs >= cursorMs && s.startMs <= windowEndMs).map((s) => s.partition);
228
+ const partitions = partitionsByWindow[index];
212
229
  if (partitions.length > 0) windows.push({
213
230
  start: isoDate(cursorMs),
214
231
  end: isoDate(windowEndMs),
215
232
  partitions
216
233
  });
217
- cursorMs = windowEndMs + MS_PER_DAY;
218
234
  }
219
235
  return windows;
220
236
  }
package/dist/schema.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { ColumnDef, ColumnType, DrizzleSchema, SCHEMAS, TABLE_METADATA, TableSchema, allTables, countries, currentSchemaVersion, dateColumnsFor, dates, dedupeByNaturalKey, dimensionToColumn, drizzleSchema, hourly_pages, inferTable, naturalKeyColumns, page_queries, pages, queries, schemaFor, search_appearance, search_appearance_page_queries, search_appearance_pages, search_appearance_queries } from "./_chunks/schema.mjs";
2
- export { type ColumnDef, type ColumnType, type DrizzleSchema, SCHEMAS, TABLE_METADATA, type TableSchema, allTables, countries, currentSchemaVersion, dateColumnsFor, dates, dedupeByNaturalKey, dimensionToColumn, drizzleSchema, hourly_pages, inferTable, naturalKeyColumns, page_queries, pages, queries, schemaFor, search_appearance, search_appearance_page_queries, search_appearance_pages, search_appearance_queries };
1
+ import { ColumnDef, ColumnType, DrizzleSchema, SCHEMAS, TABLE_METADATA, TableSchema, allTables, countries, currentSchemaVersion, dateColumnsFor, dates, dedupeByNaturalKey, dimensionToColumn, drizzleSchema, hourly_pages, inferTable, naturalKeyColumns, page_queries, pages, queries, search_appearance, search_appearance_page_queries, search_appearance_pages, search_appearance_queries } from "./_chunks/schema.mjs";
2
+ export { type ColumnDef, type ColumnType, type DrizzleSchema, SCHEMAS, TABLE_METADATA, type TableSchema, allTables, countries, currentSchemaVersion, dateColumnsFor, dates, dedupeByNaturalKey, dimensionToColumn, drizzleSchema, hourly_pages, inferTable, naturalKeyColumns, page_queries, pages, queries, search_appearance, search_appearance_page_queries, search_appearance_pages, search_appearance_queries };
package/dist/schema.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { SCHEMAS, TABLE_METADATA, allTables, countries, currentSchemaVersion, dateColumnsFor, dates, dedupeByNaturalKey, dimensionToColumn, drizzleSchema, hourly_pages, inferTable, naturalKeyColumns, page_queries, pages, queries, schemaFor, search_appearance, search_appearance_page_queries, search_appearance_pages, search_appearance_queries } from "./_chunks/schema.mjs";
2
- export { SCHEMAS, TABLE_METADATA, allTables, countries, currentSchemaVersion, dateColumnsFor, dates, dedupeByNaturalKey, dimensionToColumn, drizzleSchema, hourly_pages, inferTable, naturalKeyColumns, page_queries, pages, queries, schemaFor, search_appearance, search_appearance_page_queries, search_appearance_pages, search_appearance_queries };
1
+ import { SCHEMAS, TABLE_METADATA, allTables, countries, currentSchemaVersion, dateColumnsFor, dates, dedupeByNaturalKey, dimensionToColumn, drizzleSchema, hourly_pages, inferTable, naturalKeyColumns, page_queries, pages, queries, search_appearance, search_appearance_page_queries, search_appearance_pages, search_appearance_queries } from "./_chunks/schema.mjs";
2
+ export { SCHEMAS, TABLE_METADATA, allTables, countries, currentSchemaVersion, dateColumnsFor, dates, dedupeByNaturalKey, dimensionToColumn, drizzleSchema, hourly_pages, inferTable, naturalKeyColumns, page_queries, pages, queries, search_appearance, search_appearance_page_queries, search_appearance_pages, search_appearance_queries };
@@ -17,9 +17,8 @@ interface OverwriteWriterCatalogConfig {
17
17
  catalogToken?: string;
18
18
  }
19
19
  /**
20
- * The JSON job wire-format shared with `scripts/iceberg-writer.py` — identical
21
- * to the shape `LocalIcebergSink` already emits, so one PyIceberg script backs
22
- * both the local sink and this writer. `op` is always `overwrite` here.
20
+ * The JSON job wire-format shared with `scripts/iceberg-writer.py`.
21
+ * `op` is always `overwrite` here.
23
22
  */
24
23
  interface OverwriteJob {
25
24
  op: 'overwrite';
@@ -1,3 +1,3 @@
1
1
  import { AnalysisQuerySource, AnalysisSourceKind, ExecuteSqlOptions, FileSet, QueryRow, SourceCapabilities } from "../_chunks/registry.mjs";
2
- import { AttachedTableMissingError, AttachedTableRunner, AttachedTableSourceOptions, CreateSqlQuerySourceOptions, ENGINE_QUERY_CAPABILITIES, EngineQuerySourceOptions, TypedQuery, createAttachedTableSource, createEngineQuerySource, createSqlQuerySource, queryComparisonRows, queryRows, rewriteForTableSource, runAnalyzerWithEngine, typedQuery } from "../_chunks/index.mjs";
3
- export { type AnalysisQuerySource, type AnalysisSourceKind, AttachedTableMissingError, type AttachedTableRunner, type AttachedTableSourceOptions, type CreateSqlQuerySourceOptions, ENGINE_QUERY_CAPABILITIES, EngineQuerySourceOptions, type ExecuteSqlOptions, type FileSet, type QueryRow, type SourceCapabilities, TypedQuery, createAttachedTableSource, createEngineQuerySource, createSqlQuerySource, queryComparisonRows, queryRows, rewriteForTableSource, runAnalyzerWithEngine, typedQuery };
2
+ import { AttachedTableMissingError, AttachedTableRunner, AttachedTableSourceOptions, CreateSqlQuerySourceOptions, ENGINE_QUERY_CAPABILITIES, EngineQuerySourceOptions, createAttachedTableSource, createEngineQuerySource, createSqlQuerySource, queryRows, rewriteForTableSource, runAnalyzerWithEngine } from "../_chunks/index.mjs";
3
+ export { type AnalysisQuerySource, type AnalysisSourceKind, AttachedTableMissingError, type AttachedTableRunner, type AttachedTableSourceOptions, type CreateSqlQuerySourceOptions, ENGINE_QUERY_CAPABILITIES, EngineQuerySourceOptions, type ExecuteSqlOptions, type FileSet, type QueryRow, type SourceCapabilities, createAttachedTableSource, createEngineQuerySource, createSqlQuerySource, queryRows, rewriteForTableSource, runAnalyzerWithEngine };
@@ -1,2 +1,2 @@
1
- import { AttachedTableMissingError, ENGINE_QUERY_CAPABILITIES, createAttachedTableSource, createEngineQuerySource, createSqlQuerySource, queryComparisonRows, queryRows, rewriteForTableSource, runAnalyzerWithEngine, typedQuery } from "../_chunks/source.mjs";
2
- export { AttachedTableMissingError, ENGINE_QUERY_CAPABILITIES, createAttachedTableSource, createEngineQuerySource, createSqlQuerySource, queryComparisonRows, queryRows, rewriteForTableSource, runAnalyzerWithEngine, typedQuery };
1
+ import { AttachedTableMissingError, ENGINE_QUERY_CAPABILITIES, createAttachedTableSource, createEngineQuerySource, createSqlQuerySource, queryRows, rewriteForTableSource, runAnalyzerWithEngine } from "../_chunks/source.mjs";
2
+ export { AttachedTableMissingError, ENGINE_QUERY_CAPABILITIES, createAttachedTableSource, createEngineQuerySource, createSqlQuerySource, queryRows, rewriteForTableSource, runAnalyzerWithEngine };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gscdump/engine",
3
3
  "type": "module",
4
- "version": "0.38.2",
4
+ "version": "0.40.1",
5
5
  "description": "Append-only Parquet/DuckDB storage engine + planner + adapters for the gscdump pipeline. Node + edge runtimes; opt-in heavy peers.",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",
@@ -181,9 +181,9 @@
181
181
  "dependencies": {
182
182
  "drizzle-orm": "1.0.0-rc.3",
183
183
  "proper-lockfile": "^4.1.2",
184
- "@gscdump/lakehouse": "0.38.2",
185
- "gscdump": "0.38.2",
186
- "@gscdump/contracts": "0.38.2"
184
+ "@gscdump/contracts": "0.40.1",
185
+ "@gscdump/lakehouse": "0.40.1",
186
+ "gscdump": "0.40.1"
187
187
  },
188
188
  "devDependencies": {
189
189
  "@duckdb/duckdb-wasm": "^1.32.0",