import { Row } from "../storage.mjs"; import { AnalysisParams } from "../analysis-types.mjs"; import { ResolverAdapter } from "../resolver/types.mjs"; import { FileSet, SourceCapabilities } from "../source/source-types.mjs"; import { BuilderState } from "gscdump/query"; /** * Capabilities a Plan may require of its host. Dispatch matches `requires` * against the source's declared `capabilities` (and the presence of * `executeSql`) and rejects mismatches. * * `'executeSql'` checks for the method on the source; the rest are flag keys * on `SourceCapabilities`. Single source of truth — adding a new capability * is one line in `SourceCapabilities`. */ type RequiredCapability = 'executeSql' | keyof SourceCapabilities; interface SqlExtraQuery { name: string; sql: string; params: unknown[]; } /** * SQL-native plan: SQL string + placeholders, with optional extra file sets * and follow-up queries. */ interface SqlPlan { kind: 'sql'; sql: string; params: unknown[]; current: FileSet; previous?: FileSet; extraFiles?: Record; extraQueries?: SqlExtraQuery[]; } interface TypedRowQuery { state: BuilderState; /** Optional type tag for downstream narrowing. */ rowType?: (row: Row) => T; } /** * Row-queries plan: a named set of typed `BuilderState` queries. A portable * dispatcher runs each against a source's `queryRows` and hands the row * collection to `reduce`. */ interface RowQueriesPlan { kind: 'rows'; queries: Record; } type Plan = SqlPlan | RowQueriesPlan; /** * Plan-build context. Surfaced from the source at dispatch time so analyzers * that compose SQL from a typed `BuilderState` can pick up the right dialect * adapter without importing one directly. Most SQL analyzers emit static SQL * and ignore this; only the BuilderState-driven `data-query` / `data-detail` * analyzers consume it today. * * `adapter` is optional on the type; analyzers that need it should call * `requireAdapter(ctx, id)` rather than non-null-asserting. Capability * declaration (`'adapter'` in `requires`) is the runtime guarantee; the * helper makes the failure mode loud if the contract is broken. */ interface BuildContext { adapter?: ResolverAdapter; siteId?: string | number; } /** * Throw a uniform error if a SQL analyzer declared the `'adapter'` capability * but the dispatcher handed it a context without one. Centralizes the assert * so analyzers don't repeat `ctx.adapter!` with explanatory comments. */ declare function requireAdapter(ctx: BuildContext, analyzerId: string): ResolverAdapter; interface ReduceContext { params: AnalysisParams; /** Extra SQL-query results keyed by `SqlExtraQuery.name`. */ extras?: Record; } /** * Unified analyzer contract. `TRow` lets authors narrow from the default * `Row = Record` to a typed row shape (e.g. `QueriesRow`) * when their reducer assumes specific columns exist — catches drift between * `build` (SELECT list) and `reduce` (column access) at compile time. */ interface Analyzer

{ /** Stable tool id (e.g. `striking-distance`, `opportunity`). */ id: string; /** Capabilities a host source must provide. */ requires: readonly RequiredCapability[]; /** Pure: params → plan. Snapshot-testable. `ctx` carries the source's dialect adapter when one is available. */ build: (params: P, ctx?: BuildContext) => Plan; /** Pure: rows + context → typed result + meta. */ reduce: (rows: TRow[] | Record, ctx: ReduceContext) => { results: R; meta?: Record; }; } export { Analyzer, BuildContext, Plan, ReduceContext, RequiredCapability, RowQueriesPlan, SqlExtraQuery, SqlPlan, TypedRowQuery, requireAdapter };