@gscdump/engine 0.18.6 → 0.19.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.
@@ -1,6 +1,6 @@
1
1
  import { r as currentSchemaVersion, t as SCHEMAS } from "./schema.mjs";
2
2
  import { a as inferSearchType, c as objectKey, d as tenantPrefix, n as dayPartition, r as hourPartition } from "./storage.mjs";
3
- import { i as substituteNamedFiles, n as compileLogicalQueryPlan, o as compactTieredImpl } from "./compiler.mjs";
3
+ import { c as dedupeOverlappingTiers, i as substituteNamedFiles, n as compileLogicalQueryPlan, o as compactTieredImpl } from "./parquet-plan.mjs";
4
4
  import { sqlEscape } from "../sql-bind.mjs";
5
5
  import { buildLogicalPlan } from "gscdump/query/plan";
6
6
  import { normalizeUrl } from "gscdump/normalize";
@@ -273,6 +273,23 @@ function normalizeRow(table, row) {
273
273
  url: normalized
274
274
  };
275
275
  }
276
+ const DAILY_PARTITION_RE = /^daily\/(\d{4}-\d{2}-\d{2})$/;
277
+ function queryRangeOf(partitions) {
278
+ if (!partitions) return void 0;
279
+ let min;
280
+ let max;
281
+ for (const p of partitions) {
282
+ const m = DAILY_PARTITION_RE.exec(p);
283
+ if (!m) continue;
284
+ const d = m[1];
285
+ if (min === void 0 || d < min) min = d;
286
+ if (max === void 0 || d > max) max = d;
287
+ }
288
+ return min !== void 0 ? {
289
+ start: min,
290
+ end: max
291
+ } : void 0;
292
+ }
276
293
  function createStorageEngine(opts) {
277
294
  const { dataSource, manifestStore, codec, executor } = opts;
278
295
  const defaultNow = opts.now ?? (() => Date.now());
@@ -400,13 +417,13 @@ function createStorageEngine(opts) {
400
417
  const entries = Object.entries(opts.fileSets);
401
418
  const perSet = await Promise.all(entries.map(async ([name, ref]) => {
402
419
  if (ref.keys !== void 0) return [name, ref.keys];
403
- return [name, (await manifestStore.listLive({
420
+ return [name, dedupeOverlappingTiers(await manifestStore.listLive({
404
421
  userId: opts.ctx.userId,
405
422
  siteId: opts.ctx.siteId,
406
423
  table: ref.table,
407
424
  partitions: ref.partitions,
408
425
  ...opts.searchType !== void 0 ? { searchType: opts.searchType } : {}
409
- })).map((e) => e.objectKey)];
426
+ }), queryRangeOf(ref.partitions)).map((e) => e.objectKey)];
410
427
  }));
411
428
  opts.signal?.throwIfAborted();
412
429
  const fileKeys = {};
@@ -6,6 +6,7 @@ import { buildLogicalPlan } from "gscdump/query/plan";
6
6
  const DAILY_PARTITION_RE = /^daily\/(\d{4}-\d{2}-\d{2})$/;
7
7
  const WEEKLY_PARTITION_RE = /^weekly\/(\d{4}-\d{2}-\d{2})$/;
8
8
  const MONTHLY_PARTITION_RE = /^monthly\/(\d{4}-\d{2})$/;
9
+ const QUARTERLY_PARTITION_RE = /^quarterly\/(\d{4})-Q([1-4])$/;
9
10
  const DEFAULT_THRESHOLDS = {
10
11
  raw: 7,
11
12
  d7: 30,
@@ -146,6 +147,96 @@ function enumeratePartitions(startDate, endDate) {
146
147
  }
147
148
  return out;
148
149
  }
150
+ function partitionSpan(partition) {
151
+ let m = partition.match(DAILY_PARTITION_RE);
152
+ if (m) {
153
+ const ms = Date.parse(`${m[1]}T00:00:00Z`);
154
+ return {
155
+ rank: 0,
156
+ startMs: ms,
157
+ endMs: ms
158
+ };
159
+ }
160
+ m = partition.match(WEEKLY_PARTITION_RE);
161
+ if (m) {
162
+ const ms = Date.parse(`${m[1]}T00:00:00Z`);
163
+ return {
164
+ rank: 1,
165
+ startMs: ms,
166
+ endMs: ms + 6 * MS_PER_DAY
167
+ };
168
+ }
169
+ m = partition.match(MONTHLY_PARTITION_RE);
170
+ if (m) {
171
+ const [y, mo] = m[1].split("-").map(Number);
172
+ return {
173
+ rank: 2,
174
+ startMs: Date.UTC(y, mo - 1, 1),
175
+ endMs: Date.UTC(y, mo, 0)
176
+ };
177
+ }
178
+ m = partition.match(QUARTERLY_PARTITION_RE);
179
+ if (m) {
180
+ const y = Number(m[1]);
181
+ const q = Number(m[2]);
182
+ return {
183
+ rank: 3,
184
+ startMs: Date.UTC(y, (q - 1) * 3, 1),
185
+ endMs: Date.UTC(y, q * 3, 0)
186
+ };
187
+ }
188
+ }
189
+ function splitOverlappingTiers(entries, queryRange) {
190
+ const rangeStartMs = queryRange ? Date.parse(`${queryRange.start}T00:00:00Z`) : void 0;
191
+ const rangeEndMs = queryRange ? Date.parse(`${queryRange.end}T00:00:00Z`) : void 0;
192
+ const spanned = [];
193
+ const kept = [];
194
+ const subsumed = [];
195
+ for (const entry of entries) {
196
+ const span = partitionSpan(entry.partition);
197
+ if (!span) {
198
+ kept.push(entry);
199
+ continue;
200
+ }
201
+ const days = [];
202
+ for (let t = span.startMs; t <= span.endMs; t += MS_PER_DAY) {
203
+ if (rangeStartMs !== void 0 && (t < rangeStartMs || t > rangeEndMs)) continue;
204
+ days.push(t);
205
+ }
206
+ if (queryRange && days.length === 0) {
207
+ subsumed.push(entry);
208
+ continue;
209
+ }
210
+ spanned.push({
211
+ entry,
212
+ rank: span.rank,
213
+ days
214
+ });
215
+ }
216
+ spanned.sort((a, b) => a.rank - b.rank || b.entry.createdAt - a.entry.createdAt);
217
+ const coveredBySearchType = /* @__PURE__ */ new Map();
218
+ for (const { entry, days } of spanned) {
219
+ const slice = inferSearchType(entry);
220
+ let covered = coveredBySearchType.get(slice);
221
+ if (!covered) {
222
+ covered = /* @__PURE__ */ new Set();
223
+ coveredBySearchType.set(slice, covered);
224
+ }
225
+ if (days.every((d) => covered.has(d))) {
226
+ subsumed.push(entry);
227
+ continue;
228
+ }
229
+ kept.push(entry);
230
+ for (const d of days) covered.add(d);
231
+ }
232
+ return {
233
+ kept,
234
+ subsumed
235
+ };
236
+ }
237
+ function dedupeOverlappingTiers(entries, queryRange) {
238
+ return splitOverlappingTiers(entries, queryRange).kept;
239
+ }
149
240
  function monthEndMs(month) {
150
241
  const [y, m] = month.split("-").map(Number);
151
242
  return Date.UTC(y, m, 0, 23, 59, 59, 999);
@@ -278,7 +369,7 @@ function compileLogicalQueryPlan(plan, table = plan.dataset) {
278
369
  filesPlaceholder: FILES_PLACEHOLDER
279
370
  };
280
371
  }
281
- function resolveToSQL(state, table) {
372
+ function resolveParquetSQL(state, table) {
282
373
  const plan = buildLogicalPlan(state, { regex: true });
283
374
  return compileLogicalQueryPlan(plan, table ?? plan.dataset);
284
375
  }
@@ -290,4 +381,4 @@ function substituteNamedFiles(sql, sets) {
290
381
  for (const [name, keys] of Object.entries(sets)) out = out.replace(new RegExp(`\\{\\{${name}\\}\\}`, "g"), fileList(keys));
291
382
  return out;
292
383
  }
293
- export { RAW_DAILY_COMPACT_THRESHOLD as a, enumeratePartitions as c, substituteNamedFiles as i, compileLogicalQueryPlan as n, compactTieredImpl as o, resolveToSQL as r, countRawDailies as s, FILES_PLACEHOLDER as t };
384
+ export { RAW_DAILY_COMPACT_THRESHOLD as a, dedupeOverlappingTiers as c, substituteNamedFiles as i, enumeratePartitions as l, compileLogicalQueryPlan as n, compactTieredImpl as o, resolveParquetSQL as r, countRawDailies as s, FILES_PLACEHOLDER as t, splitOverlappingTiers as u };
@@ -10,6 +10,6 @@ interface ResolvedQuery {
10
10
  }
11
11
  declare const FILES_PLACEHOLDER = "{{FILES}}";
12
12
  declare function compileLogicalQueryPlan(plan: LogicalQueryPlan, table?: TableName): ResolvedQuery;
13
- declare function resolveToSQL(state: BuilderState, table?: TableName): ResolvedQuery;
13
+ declare function resolveParquetSQL(state: BuilderState, table?: TableName): ResolvedQuery;
14
14
  declare function substituteNamedFiles(sql: string, sets: Record<string, string[]>): string;
15
- export { substituteNamedFiles as a, resolveToSQL as i, ResolvedQuery as n, compileLogicalQueryPlan as r, FILES_PLACEHOLDER as t };
15
+ export { substituteNamedFiles as a, resolveParquetSQL as i, ResolvedQuery as n, compileLogicalQueryPlan as r, FILES_PLACEHOLDER as t };
@@ -1,5 +1,5 @@
1
1
  import { t as SCHEMAS, u as drizzleSchema } from "./schema.mjs";
2
- import { c as enumeratePartitions } from "./compiler.mjs";
2
+ import { l as enumeratePartitions } from "./parquet-plan.mjs";
3
3
  import { escapeLike } from "../sql-fragments.mjs";
4
4
  import "../planner.mjs";
5
5
  import { PgDialect } from "drizzle-orm/pg-core";
@@ -99,7 +99,7 @@ function inferLogicalDataset(dimensions, filterDims = []) {
99
99
  if (has("page")) return "pages";
100
100
  if (has("country")) return "countries";
101
101
  if (has("device")) return "devices";
102
- return "keywords";
102
+ return "devices";
103
103
  }
104
104
  function dimensionColumn(dim, dataset) {
105
105
  return LOGICAL_DATASETS[dataset].dimensions[dim]?.column ?? dim;
@@ -145,7 +145,7 @@ function inferTable(dimensions) {
145
145
  if (dims.has("country")) return "countries";
146
146
  if (dims.has("device")) return "devices";
147
147
  if (dims.has("searchAppearance")) return "search_appearance";
148
- return "keywords";
148
+ return "devices";
149
149
  }
150
150
  function dimensionToColumn(dim, _table) {
151
151
  if (dim === "page") return "url";
@@ -17,6 +17,48 @@ declare function countRawDailies(entries: ReadonlyArray<{
17
17
  partition: string;
18
18
  }>): number;
19
19
  declare function enumeratePartitions(startDate: string, endDate: string): string[];
20
+ /**
21
+ * Split manifest entries into the set worth reading (`kept`) and the set whose
22
+ * every covered day is already served by a finer-or-newer live entry
23
+ * (`subsumed`).
24
+ *
25
+ * Tiered compaction (daily→weekly→monthly→quarterly) is meant to retire its
26
+ * inputs, but coarse files can outlive their finer counterparts: a D1→R2
27
+ * backfill writes daily files that compact to monthly while a later re-sync
28
+ * writes fresh daily/weekly for the same dates, and same-partition re-writes
29
+ * leave a stale prior version live. All stay live, the resolver unions every
30
+ * live tier whose partition intersects the range, and `union_by_name` sums the
31
+ * overlap — impressions/clicks double-count.
32
+ *
33
+ * Entries are walked finest-tier-first, newest-first within a tier, so a
34
+ * coarse or stale file is dropped only when every day it covers is already
35
+ * claimed. Subsumption is evaluated per searchType — a `web` monthly never
36
+ * cancels a `discover` weekly, they cover disjoint data. Partial
37
+ * month-boundary overlap (a weekly straddling two months alongside a kept
38
+ * monthly) still double-counts those boundary days — eliminating that needs
39
+ * per-file date predicates in the SQL, tracked separately. Unrecognised
40
+ * partition shapes (`hourly/`, sidecar keys) are always kept.
41
+ *
42
+ * `queryRange` clamps every entry's day-span to the window the caller will
43
+ * actually read. This is required when `entries` came from a partition-
44
+ * filtered `listLive` (`runSQL` enumerates only the partitions intersecting
45
+ * the query): a `monthly/2026-04` whose Apr 27-30 falls past the query end
46
+ * must not be judged "unsubsumed" just because `weekly/2026-04-27` wasn't
47
+ * enumerated — those out-of-window days are SQL-filtered to nothing anyway.
48
+ * Omit `queryRange` when `entries` is the full manifest (e.g. analysis-sources).
49
+ */
50
+ declare function splitOverlappingTiers(entries: ManifestEntry[], queryRange?: {
51
+ start: string;
52
+ end: string;
53
+ }): {
54
+ kept: ManifestEntry[];
55
+ subsumed: ManifestEntry[];
56
+ };
57
+ /** Entries worth reading — see {@link splitOverlappingTiers}. */
58
+ declare function dedupeOverlappingTiers(entries: ManifestEntry[], queryRange?: {
59
+ start: string;
60
+ end: string;
61
+ }): ManifestEntry[];
20
62
  /**
21
63
  * Default `searchType` for entries written before the field landed and for
22
64
  * sync paths that don't request a specific type. GSC's own default; the
@@ -508,4 +550,4 @@ declare function dayPartition(date: string): string;
508
550
  */
509
551
  declare function hourPartition(date: string): string;
510
552
  declare function objectKey(ctx: TenantCtx, table: TableName, partition: string, version: number, searchType?: SearchType): string;
511
- export { SyncStateKind as A, hourPartition as B, Row$1 as C, SyncState as D, StorageEngine as E, WatermarkFilter as F, RAW_DAILY_COMPACT_THRESHOLD as G, inferSearchType as H, WatermarkScope as I, countRawDailies as K, WriteCtx as L, TableName$1 as M, TenantCtx$1 as N, SyncStateDetail as O, Watermark as P, WriteResult as R, QueryResult as S, SearchType$1 as T, objectKey as U, inferLegacyTier as V, CompactionThresholds as W, PurgeUrlsResult as _, EngineOptions as a, QueryExecuteResult as b, Grain$1 as c, ManifestEntry as d, ManifestPurgeResult as f, PurgeResult as g, PurgeFilter as h, DataSource as i, SyncStateScope as j, SyncStateFilter as k, ListLiveFilter as l, ParquetCodec as m, CompactionTier as n, FileSetRef as o, ManifestStore as p, enumeratePartitions as q, DEFAULT_SEARCH_TYPE as r, GcCtx as s, CodecCtx as t, LockScope as u, QueryCtx as v, RunSQLOptions as w, QueryExecutor as x, QueryExecuteOptions as y, dayPartition as z };
553
+ export { SyncStateKind as A, hourPartition as B, Row$1 as C, SyncState as D, StorageEngine as E, WatermarkFilter as F, RAW_DAILY_COMPACT_THRESHOLD as G, inferSearchType as H, WatermarkScope as I, enumeratePartitions as J, countRawDailies as K, WriteCtx as L, TableName$1 as M, TenantCtx$1 as N, SyncStateDetail as O, Watermark as P, WriteResult as R, QueryResult as S, SearchType$1 as T, objectKey as U, inferLegacyTier as V, CompactionThresholds as W, splitOverlappingTiers as Y, PurgeUrlsResult as _, EngineOptions as a, QueryExecuteResult as b, Grain$1 as c, ManifestEntry as d, ManifestPurgeResult as f, PurgeResult as g, PurgeFilter as h, DataSource as i, SyncStateScope as j, SyncStateFilter as k, ListLiveFilter as l, ParquetCodec as m, CompactionTier as n, FileSetRef as o, ManifestStore as p, dedupeOverlappingTiers as q, DEFAULT_SEARCH_TYPE as r, GcCtx as s, CodecCtx as t, LockScope as u, QueryCtx as v, RunSQLOptions as w, QueryExecutor as x, QueryExecuteOptions as y, dayPartition as z };
@@ -81,6 +81,7 @@ declare function hashUrl(url: string): string;
81
81
  * `parquetUri`.
82
82
  */
83
83
  interface InspectionParquetRow {
84
+ [column: string]: string | number | null;
84
85
  urlHash: string;
85
86
  url: string;
86
87
  inspectedAt: string;
package/dist/index.d.mts CHANGED
@@ -1,9 +1,9 @@
1
- import { A as SyncStateKind, B as hourPartition, C as Row, D as SyncState, E as StorageEngine, F as WatermarkFilter, G as RAW_DAILY_COMPACT_THRESHOLD, H as inferSearchType, I as WatermarkScope, K as countRawDailies, L as WriteCtx, M as TableName, N as TenantCtx, O as SyncStateDetail, P as Watermark, R as WriteResult, S as QueryResult, T as SearchType, U as objectKey, V as inferLegacyTier, W as CompactionThresholds, _ as PurgeUrlsResult, a as EngineOptions, b as QueryExecuteResult, c as Grain, d as ManifestEntry, f as ManifestPurgeResult, g as PurgeResult, h as PurgeFilter, i as DataSource, j as SyncStateScope, k as SyncStateFilter, l as ListLiveFilter, m as ParquetCodec, n as CompactionTier, o as FileSetRef, p as ManifestStore, q as enumeratePartitions, r as DEFAULT_SEARCH_TYPE, s as GcCtx, t as CodecCtx, u as LockScope, v as QueryCtx, w as RunSQLOptions, x as QueryExecutor, y as QueryExecuteOptions, z as dayPartition } from "./_chunks/storage.mjs";
1
+ import { A as SyncStateKind, B as hourPartition, C as Row, D as SyncState, E as StorageEngine, F as WatermarkFilter, G as RAW_DAILY_COMPACT_THRESHOLD, H as inferSearchType, I as WatermarkScope, J as enumeratePartitions, K as countRawDailies, L as WriteCtx, M as TableName, N as TenantCtx, O as SyncStateDetail, P as Watermark, R as WriteResult, S as QueryResult, T as SearchType, U as objectKey, V as inferLegacyTier, W as CompactionThresholds, Y as splitOverlappingTiers, _ as PurgeUrlsResult, a as EngineOptions, b as QueryExecuteResult, c as Grain, d as ManifestEntry, f as ManifestPurgeResult, g as PurgeResult, h as PurgeFilter, i as DataSource, j as SyncStateScope, k as SyncStateFilter, l as ListLiveFilter, m as ParquetCodec, n as CompactionTier, o as FileSetRef, p as ManifestStore, q as dedupeOverlappingTiers, r as DEFAULT_SEARCH_TYPE, s as GcCtx, t as CodecCtx, u as LockScope, v as QueryCtx, w as RunSQLOptions, x as QueryExecutor, y as QueryExecuteOptions, z as dayPartition } from "./_chunks/storage.mjs";
2
2
  import { a as createDuckDBExecutor, i as createDuckDBCodec, n as DuckDBHandle, r as canonicalEmptyParquetSchema, t as DuckDBFactory } from "./_chunks/duckdb.mjs";
3
3
  import { _ as page_keywords, a as allTables, c as inferTable, d as TABLE_METADATA, f as countries, g as keywords, h as hourly_pages, i as TableSchema, m as drizzleSchema, n as ColumnType, o as currentSchemaVersion, p as devices, r as SCHEMAS, s as dimensionToColumn, t as ColumnDef, u as DrizzleSchema, v as pages } from "./_chunks/schema.mjs";
4
4
  import { InspectionVerdict, SchedulePolicy, ScheduleState, fixedPolicy, inspectionPolicy, sitemapPolicy } from "./schedule.mjs";
5
5
  import { GscApiRow, IngestOptions, RowAccumulator, RowAccumulatorOptions, createRowAccumulator, toPath, toSumPosition, transformGscRow } from "./ingest.mjs";
6
- import { a as substituteNamedFiles, i as resolveToSQL, n as ResolvedQuery, t as FILES_PLACEHOLDER } from "./_chunks/planner.mjs";
6
+ import { a as substituteNamedFiles, i as resolveParquetSQL, n as ResolvedQuery, t as FILES_PLACEHOLDER } from "./_chunks/planner.mjs";
7
7
  import { rebuildDailyFromHourly } from "./rollups.mjs";
8
8
  import { bindLiterals, formatLiteral } from "./sql-bind.mjs";
9
9
  import { Grain as Grain$1, Row as Row$1, TableName as TableName$1 } from "@gscdump/contracts";
@@ -147,4 +147,4 @@ declare const MIN_SYNC_IMPRESSIONS = 1;
147
147
  declare const MIN_COUNTRY_IMPRESSIONS = 10;
148
148
  declare const MAX_SITEMAP_URLS_PER_SITE = 50000;
149
149
  declare const MAX_TRACKED_URLS_PER_SITE = 200000;
150
- export { type CodecCtx, type ColumnDef, type ColumnType, type CompactionThresholds, type CompactionTier, type CreateIngestAccumulatorOptions, DEFAULT_SEARCH_TYPE, type DataSource, type DateWeight, type DrizzleSchema, type DuckDBFactory, type DuckDBHandle, type EngineOptions, FILES_PLACEHOLDER, type FileSetRef, type FinalizeOptions, type FinalizeResult, type GcCtx, type Grain, type GscApiRow, type IngestAccumulator, type IngestAccumulatorCtx, type IngestAccumulatorEngine, type IngestAccumulatorHooks, type IngestOptions, type InspectionVerdict, type ListLiveFilter, type LockScope, MAX_DAY_BYTES, MAX_GSC_PAGES_R2, MAX_SITEMAP_URLS_PER_SITE, MAX_TRACKED_URLS_PER_SITE, MIN_COUNTRY_IMPRESSIONS, MIN_SYNC_IMPRESSIONS, type ManifestEntry, type ManifestPurgeResult, type ManifestStore, type ParquetCodec, type PurgeFilter, type PurgeResult, type PurgeUrlsResult, type QueryCtx, type QueryExecuteOptions, type QueryExecuteResult, type QueryExecutor, type QueryResult, RAW_DAILY_COMPACT_THRESHOLD, ROW_LIMIT_R2, type ResolvedQuery, type Row, type RowAccumulator, type RowAccumulatorOptions, type RunSQLOptions, SCHEMAS, type SchedulePolicy, type ScheduleState, type SearchType, type StorageEngine, type SyncState, type SyncStateDetail, type SyncStateFilter, type SyncStateKind, type SyncStateScope, type SyncTableName, TABLES_BY_SEARCH_TYPE, TABLE_METADATA, TABLE_TIERS, TIER_PRIORITY, type TableName, type TableSchema, type TableTier, type TenantCtx, type TieredTableName, WEIGHT_PRIORITY, type Watermark, type WatermarkFilter, type WatermarkScope, type WriteCtx, type WriteResult, allTables, bindLiterals, canonicalEmptyParquetSchema, coerceRow, coerceRows, countRawDailies, countries, createDuckDBCodec, createDuckDBExecutor, createIngestAccumulator, createNoopIngestAccumulator, createRowAccumulator, createStorageEngine, currentSchemaVersion, dayPartition, devices, dimensionToColumn, drizzleSchema, enumeratePartitions, fixedPolicy, formatLiteral, gcOrphansImpl, getDateWeight, getTableTier, getTablesForTier, hourPartition, hourly_pages, inferLegacyTier, inferSearchType, inferTable, inspectionPolicy, keywords, objectKey, page_keywords, pages, parseEnabledSearchTypes, rebuildDailyFromHourly, resolveToSQL, sitemapPolicy, substituteNamedFiles, toPath, toSumPosition, transformGscRow, validateEnabledSearchTypes };
150
+ export { type CodecCtx, type ColumnDef, type ColumnType, type CompactionThresholds, type CompactionTier, type CreateIngestAccumulatorOptions, DEFAULT_SEARCH_TYPE, type DataSource, type DateWeight, type DrizzleSchema, type DuckDBFactory, type DuckDBHandle, type EngineOptions, FILES_PLACEHOLDER, type FileSetRef, type FinalizeOptions, type FinalizeResult, type GcCtx, type Grain, type GscApiRow, type IngestAccumulator, type IngestAccumulatorCtx, type IngestAccumulatorEngine, type IngestAccumulatorHooks, type IngestOptions, type InspectionVerdict, type ListLiveFilter, type LockScope, MAX_DAY_BYTES, MAX_GSC_PAGES_R2, MAX_SITEMAP_URLS_PER_SITE, MAX_TRACKED_URLS_PER_SITE, MIN_COUNTRY_IMPRESSIONS, MIN_SYNC_IMPRESSIONS, type ManifestEntry, type ManifestPurgeResult, type ManifestStore, type ParquetCodec, type PurgeFilter, type PurgeResult, type PurgeUrlsResult, type QueryCtx, type QueryExecuteOptions, type QueryExecuteResult, type QueryExecutor, type QueryResult, RAW_DAILY_COMPACT_THRESHOLD, ROW_LIMIT_R2, type ResolvedQuery, type Row, type RowAccumulator, type RowAccumulatorOptions, type RunSQLOptions, SCHEMAS, type SchedulePolicy, type ScheduleState, type SearchType, type StorageEngine, type SyncState, type SyncStateDetail, type SyncStateFilter, type SyncStateKind, type SyncStateScope, type SyncTableName, TABLES_BY_SEARCH_TYPE, TABLE_METADATA, TABLE_TIERS, TIER_PRIORITY, type TableName, type TableSchema, type TableTier, type TenantCtx, type TieredTableName, WEIGHT_PRIORITY, type Watermark, type WatermarkFilter, type WatermarkScope, type WriteCtx, type WriteResult, allTables, bindLiterals, canonicalEmptyParquetSchema, coerceRow, coerceRows, countRawDailies, countries, createDuckDBCodec, createDuckDBExecutor, createIngestAccumulator, createNoopIngestAccumulator, createRowAccumulator, createStorageEngine, currentSchemaVersion, dayPartition, dedupeOverlappingTiers, devices, dimensionToColumn, drizzleSchema, enumeratePartitions, fixedPolicy, formatLiteral, gcOrphansImpl, getDateWeight, getTableTier, getTablesForTier, hourPartition, hourly_pages, inferLegacyTier, inferSearchType, inferTable, inspectionPolicy, keywords, objectKey, page_keywords, pages, parseEnabledSearchTypes, rebuildDailyFromHourly, resolveParquetSQL, sitemapPolicy, splitOverlappingTiers, substituteNamedFiles, toPath, toSumPosition, transformGscRow, validateEnabledSearchTypes };
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { n as coerceRows, t as coerceRow } from "./_chunks/coerce.mjs";
2
2
  import { a as inferTable, c as countries, d as hourly_pages, f as keywords, i as dimensionToColumn, l as devices, m as pages, n as allTables, p as page_keywords, r as currentSchemaVersion, s as TABLE_METADATA, t as SCHEMAS, u as drizzleSchema } from "./_chunks/schema.mjs";
3
3
  import { a as inferSearchType, c as objectKey, i as inferLegacyTier, n as dayPartition, r as hourPartition, t as DEFAULT_SEARCH_TYPE } from "./_chunks/storage.mjs";
4
- import { a as RAW_DAILY_COMPACT_THRESHOLD, c as enumeratePartitions, i as substituteNamedFiles, r as resolveToSQL, s as countRawDailies, t as FILES_PLACEHOLDER } from "./_chunks/compiler.mjs";
4
+ import { a as RAW_DAILY_COMPACT_THRESHOLD, c as dedupeOverlappingTiers, i as substituteNamedFiles, l as enumeratePartitions, r as resolveParquetSQL, s as countRawDailies, t as FILES_PLACEHOLDER, u as splitOverlappingTiers } from "./_chunks/parquet-plan.mjs";
5
5
  import { bindLiterals, formatLiteral } from "./sql-bind.mjs";
6
6
  import { a as createDuckDBCodec, i as canonicalEmptyParquetSchema, n as createStorageEngine, o as createDuckDBExecutor, r as gcOrphansImpl, t as MAX_DAY_BYTES } from "./_chunks/engine.mjs";
7
7
  import { createRowAccumulator, toPath, toSumPosition, transformGscRow } from "./ingest.mjs";
@@ -215,4 +215,4 @@ const MIN_SYNC_IMPRESSIONS = 1;
215
215
  const MIN_COUNTRY_IMPRESSIONS = 10;
216
216
  const MAX_SITEMAP_URLS_PER_SITE = 5e4;
217
217
  const MAX_TRACKED_URLS_PER_SITE = 2e5;
218
- export { DEFAULT_SEARCH_TYPE, 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, RAW_DAILY_COMPACT_THRESHOLD, ROW_LIMIT_R2, SCHEMAS, TABLES_BY_SEARCH_TYPE, TABLE_METADATA, TABLE_TIERS, TIER_PRIORITY, WEIGHT_PRIORITY, allTables, bindLiterals, canonicalEmptyParquetSchema, coerceRow, coerceRows, countRawDailies, countries, createDuckDBCodec, createDuckDBExecutor, createIngestAccumulator, createNoopIngestAccumulator, createRowAccumulator, createStorageEngine, currentSchemaVersion, dayPartition, devices, dimensionToColumn, drizzleSchema, enumeratePartitions, fixedPolicy, formatLiteral, gcOrphansImpl, getDateWeight, getTableTier, getTablesForTier, hourPartition, hourly_pages, inferLegacyTier, inferSearchType, inferTable, inspectionPolicy, keywords, objectKey, page_keywords, pages, parseEnabledSearchTypes, rebuildDailyFromHourly, resolveToSQL, sitemapPolicy, substituteNamedFiles, toPath, toSumPosition, transformGscRow, validateEnabledSearchTypes };
218
+ export { DEFAULT_SEARCH_TYPE, 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, RAW_DAILY_COMPACT_THRESHOLD, ROW_LIMIT_R2, SCHEMAS, TABLES_BY_SEARCH_TYPE, TABLE_METADATA, TABLE_TIERS, TIER_PRIORITY, WEIGHT_PRIORITY, allTables, bindLiterals, canonicalEmptyParquetSchema, coerceRow, coerceRows, countRawDailies, countries, createDuckDBCodec, createDuckDBExecutor, createIngestAccumulator, createNoopIngestAccumulator, createRowAccumulator, createStorageEngine, currentSchemaVersion, dayPartition, dedupeOverlappingTiers, devices, dimensionToColumn, drizzleSchema, enumeratePartitions, fixedPolicy, formatLiteral, gcOrphansImpl, getDateWeight, getTableTier, getTablesForTier, hourPartition, hourly_pages, inferLegacyTier, inferSearchType, inferTable, inspectionPolicy, keywords, objectKey, page_keywords, pages, parseEnabledSearchTypes, rebuildDailyFromHourly, resolveParquetSQL, sitemapPolicy, splitOverlappingTiers, substituteNamedFiles, toPath, toSumPosition, transformGscRow, validateEnabledSearchTypes };
@@ -1,3 +1,3 @@
1
- import { q as enumeratePartitions } from "./_chunks/storage.mjs";
2
- import { a as substituteNamedFiles, i as resolveToSQL, n as ResolvedQuery, r as compileLogicalQueryPlan, t as FILES_PLACEHOLDER } from "./_chunks/planner.mjs";
3
- export { FILES_PLACEHOLDER, type ResolvedQuery, compileLogicalQueryPlan, enumeratePartitions, resolveToSQL, substituteNamedFiles };
1
+ import { J as enumeratePartitions } from "./_chunks/storage.mjs";
2
+ import { a as substituteNamedFiles, i as resolveParquetSQL, n as ResolvedQuery, r as compileLogicalQueryPlan, t as FILES_PLACEHOLDER } from "./_chunks/planner.mjs";
3
+ export { FILES_PLACEHOLDER, type ResolvedQuery, compileLogicalQueryPlan, enumeratePartitions, resolveParquetSQL, substituteNamedFiles };
package/dist/planner.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { c as enumeratePartitions, i as substituteNamedFiles, n as compileLogicalQueryPlan, r as resolveToSQL, t as FILES_PLACEHOLDER } from "./_chunks/compiler.mjs";
2
- export { FILES_PLACEHOLDER, compileLogicalQueryPlan, enumeratePartitions, resolveToSQL, substituteNamedFiles };
1
+ import { i as substituteNamedFiles, l as enumeratePartitions, n as compileLogicalQueryPlan, r as resolveParquetSQL, t as FILES_PLACEHOLDER } from "./_chunks/parquet-plan.mjs";
2
+ export { FILES_PLACEHOLDER, compileLogicalQueryPlan, enumeratePartitions, resolveParquetSQL, substituteNamedFiles };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gscdump/engine",
3
3
  "type": "module",
4
- "version": "0.18.6",
4
+ "version": "0.19.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",
@@ -169,8 +169,8 @@
169
169
  "dependencies": {
170
170
  "drizzle-orm": "^0.45.2",
171
171
  "proper-lockfile": "^4.1.2",
172
- "@gscdump/contracts": "0.18.6",
173
- "gscdump": "0.18.6"
172
+ "gscdump": "0.19.1",
173
+ "@gscdump/contracts": "0.19.1"
174
174
  },
175
175
  "devDependencies": {
176
176
  "@duckdb/duckdb-wasm": "^1.32.0",