import type { IndexerAdapter, IndexerDocument, IndexerSlice } from "@voyant-travel/catalog-contracts/indexer/contract"; export interface IndexerReconciliationTarget { /** A configured slice whose complete expected document set is supplied. */ slice: IndexerSlice; /** * Creates a fresh document stream for every reconciliation attempt. Batches * are applied sequentially; repeated IDs within a batch collapse to its last * occurrence, and later batches replace earlier ones. Retrying converges. */ loadDocuments(): AsyncIterable | Iterable; } export interface IndexerReconciliationOwnership { /** Whether this reconciliation owns the entire lifecycle of a slice. */ ownsSlice(slice: IndexerSlice): boolean; /** Whether an indexed document may be deleted when it is not expected. */ ownsDocument(slice: IndexerSlice, document: IndexerDocument): boolean; } /** Adapter and configuration exposed only while the caller's lock is held. */ export interface IndexerReconciliationExclusiveContext { readonly adapter: IndexerAdapter; readonly configuredSlices: readonly IndexerSlice[]; ensureCollections(slices: readonly IndexerSlice[]): Promise; } /** * Deployment-owned reconciliation authority. `runExclusive` must acquire a * long-lived backend or distributed write lock shared by every index mutation * path in every process before exposing the callback context. A process-local * mutex or an authority created per IndexerService is insufficient. This * package intentionally provides no default implementation or generic * conformance assertion: deployments must verify exclusion with a * process-separated, backend-specific integration test. */ export interface IndexerReconciliationAuthority { runExclusive(operation: (context: IndexerReconciliationExclusiveContext) => Promise): Promise; } /** Partitioned state for one target slice during one reconciliation attempt. */ export interface IndexerReconciliationState { writeExpectedIds(ids: readonly string[]): Promise; writeCandidateIds(ids: readonly string[]): Promise; /** Prevent further writes before stale bucket reads begin. */ seal(): Promise; staleIdBatches(batchSize: number): AsyncIterable; /** Release all state for this attempt. Must be idempotent and retryable. */ dispose(): Promise; } /** Creates isolated, disposable state for each reconciled slice. */ export interface IndexerReconciliationStateStore { create(slice: IndexerSlice): Promise; } export interface FileIndexerReconciliationStateStoreOptions { /** Parent directory for temporary state. Defaults to the operating-system temp directory. */ directory?: string; /** Number of expected/candidate hash buckets. Defaults to 256; maximum 4096. */ buckets?: number; } /** * Create the default Node reconciliation state store. IDs are grouped into * append-and-close writes, then partitions are processed one bucket at a time * after the provider scan closes. Memory is partition-bounded rather than * globally bounded: one heavily skewed bucket can grow with the corpus. */ export declare function createFileIndexerReconciliationStateStore(options?: FileIndexerReconciliationStateStoreOptions): IndexerReconciliationStateStore; export interface ReconcileIndexerOptions { /** * Required deployment authority for adapter/config access and a distributed * exclusive write boundary. The package does not provide an in-process default. */ authority: IndexerReconciliationAuthority; targets: ReadonlyArray; /** Explicit, owned, no-longer-configured slices that may be dropped. */ obsoleteSlices?: ReadonlyArray; ownership: IndexerReconciliationOwnership; /** Preferred upsert, scan, spool, and delete batch size. Defaults to 250. */ batchSize?: number; /** Partitioned reconciliation state. Defaults to a temporary filesystem store. */ stateStore?: IndexerReconciliationStateStore; /** * `error` prevents any mutation when maintenance APIs are unavailable. * `upsert-only` explicitly permits non-destructive document convergence. */ onMissingAdmin?: "error" | "upsert-only"; } export interface IndexerReconciliationResult { mode: "full" | "upsert-only"; indexedDocuments: number; deletedDocuments: number; droppedSlices: number; } export declare class IndexerAdminUnavailableError extends Error { constructor(); } /** * Converges engine state within the caller's deployment-wide exclusive write * boundary. Obsolete slices are considered only when explicitly supplied. */ export declare function reconcileIndexer(options: ReconcileIndexerOptions): Promise;