import { Row, TableName } from "./storage.mjs"; /** * Canonical GSC API dimension order per table. Consumers hitting the raw * `searchanalytics.query` endpoint must request dimensions in this order so * that `transformGscRow` / `createRowAccumulator` can decode the resulting * `keys[]` tuples. Storage-column names (e.g. `page` → `url`) are handled * inside `transformGscRow` — this record stays in GSC-API vocabulary. */ declare const TABLE_DIMS: Record; interface GscApiRow { keys: string[]; clicks: number; impressions: number; /** Unused by ingest — the `sum_position` column encodes weighted position. */ ctr?: number; position: number; } interface IngestOptions { /** Date for one-day `searchAppearance` total queries, whose keys omit date. */ date?: string; /** Search appearance filter used for contextual second-step rows. */ searchAppearance?: string; } /** * Strip a GSC URL to its pathname. Core analytics stores pages by path so * queries don't carry origin-prefix filters. */ declare function toPath(gscUrl: string): string; /** * Encode weighted average position as `sum_position`. The raw GSC position * is 1-indexed; subtract 1 and weight by impressions so a downstream * `SUM(sum_position) / SUM(impressions) + 1` recovers the true mean without * ever materialising per-row position values. */ declare function toSumPosition(apiPosition: number, impressions: number): number; /** * Map one GSC API row into `{ date, row }` for the given table, or null if * the row has no keys (GSC occasionally emits empty-keys placeholders). */ declare function transformGscRow(table: TableName, apiRow: GscApiRow, options?: IngestOptions): { date: string; row: Row; } | null; /** * Assemble one `dates` row for a single `date` from the two GSC queries that * back the table: * * - `totalsRow` — the GSC `['date']` query result: the TRUE site totals * (clicks/impressions/position), including anonymized impressions. * - `deviceRows` — the GSC `['date','device']` query results for that date: * one row per device, pivoted into the 9 `*_{device}` columns. * - `queryGrainedImpressions` — total impressions summed from the * `['query','date']` (or `['page','query','date']`) query for the same date, * used to derive `anonymized_impressions_pct`. * * `anonymized_impressions_pct = 1 - query_grained_impressions / * page_grained_impressions`, where the page/date totals come from `totalsRow`. * Mirrors the legacy `dailyTotalsRollup` formula. Clamped to `[0, 1]`. */ declare function assembleDatesRow(date: string, totalsRow: GscApiRow, deviceRows: readonly GscApiRow[], queryGrainedImpressions: number): { date: string; row: Row; }; interface RowAccumulator { /** * Push a batch of GSC API rows into the accumulator. Returns `false` if * the batch pushed total row count past `maxRows`; subsequent pushes * become no-ops until `drain()` is called. */ push: (table: TableName, rows: readonly GscApiRow[]) => boolean; /** * Consume accumulated rows, grouped by `table → date → rows`. Resets * internal state; subsequent pushes behave as on a fresh accumulator. */ drain: () => Map>; /** * Drain only buckets for dates strictly older than the most-recent date * seen for each table. Requires `trackDateBoundary` to be enabled — without * it, returns an empty map. GSC's date-as-dimension queries return rows * sorted by date, so any date older than the latest seen is logically * complete within the current job slice and safe to flush mid-job. * * Returned buckets are removed from internal state and `totalRows` is * decremented accordingly. Latest-date buckets stay in place for the * eventual `drain()` at job end. */ drainCompleted: () => Map>; /** Total row count across all tables/dates since last drain. */ readonly totalRows: number; /** Whether the accumulator has overflowed since last drain. */ readonly overflowed: boolean; } interface RowAccumulatorOptions extends IngestOptions { /** * Soft cap on total accumulated rows before `push` starts returning * `false` and dropping rows. Defaults to 500_000 — matches the * ~128 MB CF Workers isolate budget at ~200 bytes/row with headroom. */ maxRows?: number; /** * Track the most-recent date seen per table so `drainCompleted()` can * return older-date buckets mid-job. Off by default — callers that don't * stream-flush pay zero overhead for the bookkeeping. * * Caller contract: only safe when GSC dimensions include `date` so the * API returns rows in date-ascending order; without that ordering, * "older than latest" doesn't mean "complete" and partial buckets would * be flushed prematurely. */ trackDateBoundary?: boolean; } declare function createRowAccumulator(options?: RowAccumulatorOptions): RowAccumulator; export { GscApiRow, IngestOptions, RowAccumulator, RowAccumulatorOptions, TABLE_DIMS, assembleDatesRow, createRowAccumulator, toPath, toSumPosition, transformGscRow };