@topgunbuild/core 0.8.1 → 0.10.0
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/LICENSE +97 -0
- package/dist/index.d.mts +873 -9
- package/dist/index.d.ts +873 -9
- package/dist/index.js +691 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +662 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -11
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/HLC.ts","../src/utils/hash.ts","../src/MerkleTree.ts","../src/LWWMap.ts","../src/ORMapMerkle.ts","../src/ORMapMerkleTree.ts","../src/ORMap.ts","../src/serializer.ts","../src/PNCounter.ts","../src/Ringbuffer.ts","../src/EventJournal.ts","../src/EntryProcessor.ts","../src/ConflictResolver.ts","../src/predicate.ts","../src/schemas.ts","../src/types/WriteConcern.ts","../src/types/cluster.ts","../src/query/ds/SortedMap.ts","../src/query/ds/types.ts","../src/query/Attribute.ts","../src/query/resultset/SetResultSet.ts","../src/query/indexes/HashIndex.ts","../src/query/resultset/LazyResultSet.ts","../src/query/indexes/NavigableIndex.ts","../src/query/indexes/FallbackIndex.ts","../src/query/QueryTypes.ts","../src/query/indexes/StandingQueryIndex.ts","../src/query/tokenization/Tokenizer.ts","../src/query/tokenization/TokenFilter.ts","../src/query/tokenization/TokenizationPipeline.ts","../src/query/indexes/InvertedIndex.ts","../src/query/indexes/CompoundIndex.ts","../src/query/indexes/lazy/LazyHashIndex.ts","../src/query/indexes/lazy/LazyNavigableIndex.ts","../src/query/indexes/lazy/LazyInvertedIndex.ts","../src/query/resultset/IntersectionResultSet.ts","../src/query/resultset/UnionResultSet.ts","../src/query/resultset/FilteringResultSet.ts","../src/query/resultset/SortedResultSet.ts","../src/query/resultset/LimitResultSet.ts","../src/query/IndexRegistry.ts","../src/query/QueryOptimizer.ts","../src/query/StandingQueryRegistry.ts","../src/query/LiveQueryManager.ts","../src/query/adaptive/types.ts","../src/query/adaptive/QueryPatternTracker.ts","../src/query/adaptive/IndexAdvisor.ts","../src/query/adaptive/AutoIndexManager.ts","../src/query/adaptive/DefaultIndexingStrategy.ts","../src/search/ReciprocalRankFusion.ts","../src/IndexedLWWMap.ts","../src/query/tokenization/stopwords.ts","../src/query/tokenization/porter-stemmer.ts","../src/fts/Tokenizer.ts","../src/fts/BM25InvertedIndex.ts","../src/fts/BM25Scorer.ts","../src/fts/IndexSerializer.ts","../src/fts/FullTextIndex.ts","../src/IndexedORMap.ts"],"sourcesContent":["import { HLC, Timestamp } from './HLC';\nimport { LWWMap, LWWRecord } from './LWWMap';\nimport { ORMap, ORMapRecord, MergeKeyResult, ORMapSnapshot } from './ORMap';\nimport { MerkleTree } from './MerkleTree';\nimport { ORMapMerkleTree, ORMapMerkleNode } from './ORMapMerkleTree';\nimport { hashORMapEntry, hashORMapRecord, timestampToString, compareTimestamps } from './ORMapMerkle';\nimport { PNCounterImpl } from './PNCounter';\nimport type { PNCounter, PNCounterState, PNCounterStateObject, PNCounterConfig } from './PNCounter';\nimport { Ringbuffer } from './Ringbuffer';\nimport { EventJournalImpl, DEFAULT_EVENT_JOURNAL_CONFIG } from './EventJournal';\nimport type {\n EventJournal,\n EventJournalConfig,\n JournalEvent,\n JournalEventInput,\n JournalEventType,\n JournalEventListener,\n} from './EventJournal';\n\nexport { HLC, LWWMap, ORMap, MerkleTree, ORMapMerkleTree, PNCounterImpl };\nexport { hashORMapEntry, hashORMapRecord, timestampToString, compareTimestamps };\nexport type { PNCounter, PNCounterState, PNCounterStateObject, PNCounterConfig };\n\n// Event Journal exports (Phase 5.04)\nexport { Ringbuffer, EventJournalImpl, DEFAULT_EVENT_JOURNAL_CONFIG };\nexport type {\n EventJournal,\n EventJournalConfig,\n JournalEvent,\n JournalEventInput,\n JournalEventType,\n JournalEventListener,\n};\n\n// Entry Processor exports (Phase 5.03)\nexport {\n EntryProcessorDefSchema,\n validateProcessorCode,\n BuiltInProcessors,\n FORBIDDEN_PATTERNS,\n DEFAULT_PROCESSOR_RATE_LIMITS,\n} from './EntryProcessor';\nexport type {\n EntryProcessorFn,\n EntryProcessorDef,\n EntryProcessorResult,\n ProcessorRateLimitConfig,\n} from './EntryProcessor';\n\n// Conflict Resolver exports (Phase 5.05)\nexport {\n ConflictResolverDefSchema,\n validateResolverCode,\n BuiltInResolvers,\n RESOLVER_FORBIDDEN_PATTERNS,\n DEFAULT_RESOLVER_RATE_LIMITS,\n compareHLCTimestamps,\n deepMerge,\n} from './ConflictResolver';\nexport type {\n MergeContext,\n MergeResult,\n ConflictResolverFn,\n ConflictResolverDef,\n ResolverRateLimitConfig,\n MergeRejection,\n} from './ConflictResolver';\n\nexport * from './utils/hash';\nexport * from './serializer';\nexport * from './predicate';\nexport * from './security';\nexport * from './schemas';\nexport type { Timestamp, LWWRecord, ORMapRecord, MergeKeyResult, ORMapSnapshot, ORMapMerkleNode };\n\n// Re-export heartbeat types for convenience\nexport type { PingMessage, PongMessage } from './schemas';\n\n// Write Concern exports (Phase 5.01)\nexport {\n WriteConcern,\n WriteOptions,\n WriteResult,\n PendingWrite,\n WRITE_CONCERN_ORDER,\n DEFAULT_WRITE_CONCERN_TIMEOUT,\n isWriteConcernAchieved,\n getHighestWriteConcernLevel,\n} from './types/WriteConcern';\nexport type { WriteConcernValue } from './schemas';\n\n// Cluster types exports (Phase 4)\nexport type {\n NodeStatus,\n NodeInfo,\n PartitionInfo,\n PartitionMap,\n PartitionMapMessage,\n PartitionMapRequestMessage,\n PartitionChange,\n PartitionMapDeltaMessage,\n NotOwnerError,\n StaleMapError,\n RoutingError,\n ConnectionPoolConfig,\n PartitionRouterConfig,\n ClusterClientConfig,\n CircuitBreakerConfig,\n ConnectionState,\n NodeHealth,\n ClusterEvents,\n // Migration types (Task 03)\n PartitionMigration,\n MigrationConfig,\n MigrationStatus,\n MigrationMetrics,\n MigrationStartMessage,\n MigrationChunkMessage,\n MigrationChunkAckMessage,\n MigrationCompleteMessage,\n MigrationVerifyMessage,\n MigrationMessage,\n // Replication types (Task 04)\n WriteOptions as ClusterWriteOptions,\n ReadOptions as ClusterReadOptions,\n ReplicationConfig,\n ReplicationTask,\n ReplicationLag,\n ReplicationHealth,\n ReplicationResult,\n ReplicationMessage,\n ReplicationBatchMessage,\n ReplicationAckMessage,\n ReplicationBatchAckMessage,\n ReplicationProtocolMessage,\n} from './types/cluster';\nexport {\n DEFAULT_CONNECTION_POOL_CONFIG,\n DEFAULT_PARTITION_ROUTER_CONFIG,\n DEFAULT_CIRCUIT_BREAKER_CONFIG,\n PARTITION_COUNT,\n DEFAULT_BACKUP_COUNT,\n // Migration exports (Task 03)\n PartitionState,\n DEFAULT_MIGRATION_CONFIG,\n // Replication exports (Task 04)\n ConsistencyLevel,\n DEFAULT_REPLICATION_CONFIG,\n} from './types/cluster';\n\n// Query Engine exports (Phase 7 + Phase 8.01)\n// Note: Query from schemas conflicts with Query from query/QueryTypes\n// We rename query engine Query to QueryExpression to avoid conflict\nexport {\n // Data structures\n SortedMap,\n // Attribute system\n SimpleAttribute,\n MultiValueAttribute,\n simpleAttribute,\n multiAttribute,\n // Indexes\n HashIndex,\n NavigableIndex,\n StandingQueryIndex,\n FallbackIndex,\n createPredicateMatcher,\n InvertedIndex,\n // Tokenization (Phase 8.01)\n TokenizationPipeline,\n WhitespaceTokenizer,\n WordBoundaryTokenizer,\n NGramTokenizer,\n LowercaseFilter,\n StopWordFilter,\n MinLengthFilter,\n MaxLengthFilter,\n TrimFilter,\n UniqueFilter,\n DEFAULT_STOP_WORDS,\n // ResultSet\n SetResultSet,\n LazyResultSet,\n IntersectionResultSet,\n UnionResultSet,\n FilteringResultSet,\n SortedResultSet,\n createFieldComparator,\n LimitResultSet,\n // Type Guards\n isSimpleQuery,\n isLogicalQuery,\n // Index Registry\n IndexRegistry,\n // Query Optimizer\n QueryOptimizer,\n // Standing Query Registry\n StandingQueryRegistry,\n // Live Query Manager\n LiveQueryManager,\n} from './query';\n\nexport type {\n // Attribute system\n Attribute,\n // Indexes\n StandingQueryChange,\n StandingQueryIndexOptions,\n Index,\n IndexQuery,\n IndexStats,\n InvertedIndexStats,\n // Tokenization (Phase 8.01)\n Tokenizer,\n TokenFilter,\n TokenizationPipelineOptions,\n // ResultSet\n ResultSet,\n IteratorFactory,\n PredicateFn,\n CompareFn,\n // Query Types (renamed to avoid conflict with schemas.Query)\n QueryNode,\n SimpleQueryNode,\n LogicalQueryNode,\n QueryOptions,\n PlanStep,\n IndexScanStep,\n FullScanStep,\n IntersectionStep,\n UnionStep,\n FilterStep,\n NotStep,\n QueryPlan,\n // Index Registry\n IndexRegistryStats,\n // Query Optimizer\n QueryOptimizerOptions,\n // Standing Query Registry\n StandingQueryRegistryOptions,\n StandingQueryRegistryStats,\n // Live Query Manager\n LiveQueryManagerOptions,\n LiveQueryManagerStats,\n LiveQueryCallback,\n LiveQueryEvent,\n LiveQueryInitialEvent,\n LiveQueryDeltaEvent,\n} from './query';\n\n// Re-export Query from query module as QueryExpression to avoid conflict\nexport type { Query as QueryExpression } from './query';\n\n// Indexed CRDT exports (Phase 7.07)\nexport { IndexedLWWMap } from './IndexedLWWMap';\nexport { IndexedORMap, type ORMapQueryResult, type ORMapSearchResult } from './IndexedORMap';\n\n// Full-Text Search exports (Phase 11)\nexport {\n // Tokenizer\n Tokenizer as FTSTokenizer,\n ENGLISH_STOPWORDS,\n porterStem,\n // Inverted Index\n InvertedIndex as FTSInvertedIndex,\n // BM25 Scorer\n BM25Scorer,\n // Full-Text Index (high-level integration)\n FullTextIndex,\n} from './fts';\nexport type {\n // Types\n TokenizerOptions as FTSTokenizerOptions,\n TermInfo,\n Posting,\n BM25Options,\n ScoredDocument,\n FullTextIndexConfig,\n SearchOptions as FTSSearchOptions,\n SearchResult as FTSSearchResult,\n SerializedIndex,\n} from './fts';\n\n// Search utilities exports (Phase 12)\nexport {\n ReciprocalRankFusion,\n} from './search';\nexport type {\n RankedResult,\n RRFConfig,\n MergedResult,\n} from './search';\n","export interface Timestamp {\n millis: number;\n counter: number;\n nodeId: string;\n}\n\nexport class HLC {\n private lastMillis: number;\n private lastCounter: number;\n private readonly nodeId: string;\n\n // Max allowable drift in milliseconds (1 minute)\n private static readonly MAX_DRIFT = 60000;\n\n constructor(nodeId: string) {\n this.nodeId = nodeId;\n this.lastMillis = 0;\n this.lastCounter = 0;\n }\n\n public get getNodeId(): string {\n return this.nodeId;\n }\n\n /**\n * Generates a new unique timestamp for a local event.\n * Ensures monotonicity: always greater than any previously generated or received timestamp.\n */\n public now(): Timestamp {\n const systemTime = Date.now();\n \n // If local physical time catches up to logical time, reset counter\n if (systemTime > this.lastMillis) {\n this.lastMillis = systemTime;\n this.lastCounter = 0;\n } else {\n // Else, just increment the logical counter\n this.lastCounter++;\n }\n\n return {\n millis: this.lastMillis,\n counter: this.lastCounter,\n nodeId: this.nodeId\n };\n }\n\n /**\n * Updates the local clock based on a received remote timestamp.\n * Must be called whenever a message/event is received from another node.\n */\n public update(remote: Timestamp): void {\n const systemTime = Date.now();\n\n // Validate drift (optional but good practice)\n if (remote.millis > systemTime + HLC.MAX_DRIFT) {\n console.warn(`Clock drift detected: Remote time ${remote.millis} is far ahead of local ${systemTime}`);\n // In strict systems we might reject, but in AP systems we usually accept and fast-forward\n }\n\n const maxMillis = Math.max(this.lastMillis, systemTime, remote.millis);\n\n if (maxMillis === this.lastMillis && maxMillis === remote.millis) {\n // Both clocks are on the same millisecond, take max counter\n this.lastCounter = Math.max(this.lastCounter, remote.counter) + 1;\n } else if (maxMillis === this.lastMillis) {\n // Local logical clock is ahead in millis (or same as remote but remote millis < local)\n this.lastCounter++;\n } else if (maxMillis === remote.millis) {\n // Remote clock is ahead, fast-forward local\n this.lastCounter = remote.counter + 1;\n } else {\n // System time is ahead of both\n this.lastCounter = 0;\n }\n\n this.lastMillis = maxMillis;\n }\n\n /**\n * Compares two timestamps.\n * Returns -1 if a < b, 1 if a > b, 0 if equal.\n */\n public static compare(a: Timestamp, b: Timestamp): number {\n if (a.millis !== b.millis) {\n return a.millis - b.millis;\n }\n if (a.counter !== b.counter) {\n return a.counter - b.counter;\n }\n return a.nodeId.localeCompare(b.nodeId);\n }\n\n /**\n * Serializes timestamp to a string representation (e.g., for storage/network).\n * Format: \"<millis>:<counter>:<nodeId>\"\n */\n public static toString(ts: Timestamp): string {\n return `${ts.millis}:${ts.counter}:${ts.nodeId}`;\n }\n\n /**\n * Parses a string representation back to a Timestamp object.\n */\n public static parse(str: string): Timestamp {\n const parts = str.split(':');\n if (parts.length !== 3) {\n throw new Error(`Invalid timestamp format: ${str}`);\n }\n return {\n millis: parseInt(parts[0], 10),\n counter: parseInt(parts[1], 10),\n nodeId: parts[2]\n };\n }\n}\n","/**\n * Hash utilities for TopGun\n *\n * Uses native xxHash64 when available (via @topgunbuild/native),\n * falls back to FNV-1a for JS-only environments.\n *\n * Phase 3.05: Native Hash Integration\n */\n\n// Try to load native hash module\nlet nativeHash: {\n hashString: (str: string) => number;\n isNativeHashAvailable: () => boolean;\n} | null = null;\n\nlet nativeLoadAttempted = false;\n\nfunction tryLoadNative(): void {\n if (nativeLoadAttempted) return;\n nativeLoadAttempted = true;\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n nativeHash = require('@topgunbuild/native');\n } catch {\n // Native module not available, will use FNV-1a fallback\n }\n}\n\n/**\n * FNV-1a Hash implementation for strings.\n * Fast, non-cryptographic, synchronous.\n * Used as fallback when native module is unavailable.\n */\nfunction fnv1aHash(str: string): number {\n let hash = 0x811c9dc5;\n for (let i = 0; i < str.length; i++) {\n hash ^= str.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return hash >>> 0; // Ensure positive 32-bit integer\n}\n\n/**\n * Hash a string to a 32-bit unsigned integer.\n *\n * Uses native xxHash64 (truncated to 32 bits) when available,\n * otherwise falls back to FNV-1a.\n *\n * @param str - String to hash\n * @returns 32-bit unsigned integer hash\n */\nexport function hashString(str: string): number {\n tryLoadNative();\n\n if (nativeHash && nativeHash.isNativeHashAvailable()) {\n return nativeHash.hashString(str);\n }\n\n return fnv1aHash(str);\n}\n\n/**\n * Combines multiple hash numbers into one order-independent hash.\n * Used for combining bucket hashes in Merkle trees.\n *\n * Uses simple sum (with overflow handling) for order-independence.\n *\n * @param hashes - Array of hash values to combine\n * @returns Combined hash as 32-bit unsigned integer\n */\nexport function combineHashes(hashes: number[]): number {\n let result = 0;\n for (const h of hashes) {\n result = (result + h) | 0; // Simple sum with overflow\n }\n return result >>> 0;\n}\n\n/**\n * Check if native hash module is being used.\n * Useful for diagnostics and testing.\n */\nexport function isUsingNativeHash(): boolean {\n tryLoadNative();\n return nativeHash?.isNativeHashAvailable() === true;\n}\n\n/**\n * Force use of FNV-1a hash (for testing/compatibility).\n * After calling this, hashString will always use FNV-1a.\n */\nexport function disableNativeHash(): void {\n nativeHash = null;\n nativeLoadAttempted = true;\n}\n\n/**\n * Re-enable native hash loading (for testing).\n * Resets the load state so native module can be loaded again.\n */\nexport function resetNativeHash(): void {\n nativeHash = null;\n nativeLoadAttempted = false;\n}\n","import { LWWRecord } from './LWWMap';\nimport { hashString } from './utils/hash';\n\nexport interface MerkleNode {\n hash: number;\n children?: { [key: string]: MerkleNode }; // Keyed by bucket index (hex char)\n entries?: Map<string, number>; // Leaf node: Key -> ContentHash\n}\n\n/**\n * A specific implementation of Merkle Tree for syncing LWW-Maps.\n * It uses a Prefix Trie structure based on the hash of the Record Key.\n * \n * Structure:\n * - Level 0: Root\n * - Level 1..N: Buckets based on hex digits of Key Hash.\n * \n * This allows us to quickly identify which \"bucket\" of keys is out of sync.\n */\nexport class MerkleTree {\n private root: MerkleNode;\n private readonly depth: number;\n\n constructor(records: Map<string, LWWRecord<any>> = new Map(), depth: number = 3) {\n this.depth = depth;\n this.root = { hash: 0, children: {} };\n // Build initial tree\n for (const [key, record] of records) {\n this.update(key, record);\n }\n }\n\n /**\n * Incrementally updates the Merkle Tree with a single record.\n * @param key The key of the record\n * @param record The record (value + timestamp)\n */\n public update(key: string, record: LWWRecord<any>) {\n const itemHash = hashString(`${key}:${record.timestamp.millis}:${record.timestamp.counter}:${record.timestamp.nodeId}`);\n // We use the hash of the KEY for routing, so the record stays in the same bucket\n // regardless of timestamp changes.\n const pathHash = hashString(key).toString(16).padStart(8, '0'); \n \n this.updateNode(this.root, key, itemHash, pathHash, 0);\n }\n\n /**\n * Removes a key from the Merkle Tree.\n * Necessary for Garbage Collection of tombstones.\n */\n public remove(key: string) {\n const pathHash = hashString(key).toString(16).padStart(8, '0');\n this.removeNode(this.root, key, pathHash, 0);\n }\n\n private removeNode(node: MerkleNode, key: string, pathHash: string, level: number): number {\n // Leaf Node Logic\n if (level >= this.depth) {\n if (node.entries) {\n node.entries.delete(key);\n \n // Recalculate leaf hash\n let h = 0;\n for (const val of node.entries.values()) {\n h = (h + val) | 0;\n }\n node.hash = h >>> 0;\n }\n return node.hash;\n }\n\n // Intermediate Node Logic\n const bucketChar = pathHash[level];\n if (node.children && node.children[bucketChar]) {\n const childHash = this.removeNode(node.children[bucketChar], key, pathHash, level + 1);\n \n // Optimization: if child is empty/zero, we might want to remove it, but for now just recalc.\n }\n \n // Recalculate this node's hash from children\n let h = 0;\n if (node.children) {\n for (const child of Object.values(node.children)) {\n h = (h + child.hash) | 0;\n }\n }\n node.hash = h >>> 0;\n return node.hash;\n }\n\n private updateNode(node: MerkleNode, key: string, itemHash: number, pathHash: string, level: number): number {\n // Leaf Node Logic\n if (level >= this.depth) {\n if (!node.entries) node.entries = new Map();\n node.entries.set(key, itemHash);\n \n // Recalculate leaf hash (Sum of item hashes)\n let h = 0;\n for (const val of node.entries.values()) {\n h = (h + val) | 0;\n }\n node.hash = h >>> 0;\n return node.hash;\n }\n\n // Intermediate Node Logic\n const bucketChar = pathHash[level];\n if (!node.children) node.children = {};\n \n if (!node.children[bucketChar]) {\n node.children[bucketChar] = { hash: 0 };\n }\n \n this.updateNode(node.children[bucketChar], key, itemHash, pathHash, level + 1);\n \n // Recalculate this node's hash from children\n let h = 0;\n for (const child of Object.values(node.children)) {\n h = (h + child.hash) | 0;\n }\n node.hash = h >>> 0;\n return node.hash;\n }\n\n public getRootHash(): number {\n return this.root.hash;\n }\n\n public getNode(path: string): MerkleNode | undefined {\n let current = this.root;\n for (const char of path) {\n if (!current.children || !current.children[char]) {\n return undefined;\n }\n current = current.children[char];\n }\n return current;\n }\n\n /**\n * Returns the hashes of the children at the given path.\n * Used by the client/server to compare buckets.\n */\n public getBuckets(path: string): Record<string, number> {\n const node = this.getNode(path);\n if (!node || !node.children) return {};\n \n const result: Record<string, number> = {};\n for (const [key, child] of Object.entries(node.children)) {\n result[key] = child.hash;\n }\n return result;\n }\n\n /**\n * For a leaf node (bucket), returns the actual keys it contains.\n * Used to request specific keys when a bucket differs.\n */\n public getKeysInBucket(path: string): string[] {\n const node = this.getNode(path);\n if (!node || !node.entries) return [];\n return Array.from(node.entries.keys());\n }\n}\n","import { HLC, Timestamp } from './HLC';\nimport { MerkleTree } from './MerkleTree';\n\n/**\n * A record in the LWW-Map.\n * Can represent a value or a deletion (tombstone).\n */\nexport interface LWWRecord<V> {\n value: V | null;\n timestamp: Timestamp;\n ttlMs?: number;\n}\n\n/**\n * Last-Write-Wins Map Implementation.\n * This structure guarantees convergence by always keeping the entry with the highest timestamp.\n */\nexport class LWWMap<K, V> {\n private data: Map<K, LWWRecord<V>>;\n private readonly hlc: HLC;\n private listeners: Array<() => void> = [];\n private merkleTree: MerkleTree;\n\n constructor(hlc: HLC) {\n this.hlc = hlc;\n this.data = new Map();\n this.merkleTree = new MerkleTree();\n }\n\n public onChange(callback: () => void): () => void {\n this.listeners.push(callback);\n return () => {\n this.listeners = this.listeners.filter(cb => cb !== callback);\n };\n }\n\n private notify(): void {\n this.listeners.forEach(cb => cb());\n }\n\n public getMerkleTree(): MerkleTree {\n return this.merkleTree;\n }\n\n public get size(): number {\n return this.data.size;\n }\n\n /**\n * Sets a value for a key.\n * Generates a new timestamp using the local HLC.\n */\n public set(key: K, value: V, ttlMs?: number): LWWRecord<V> {\n const timestamp = this.hlc.now();\n const record: LWWRecord<V> = { value, timestamp };\n \n if (ttlMs !== undefined) {\n if (typeof ttlMs !== 'number' || ttlMs <= 0 || !Number.isFinite(ttlMs)) {\n // We could throw, but to be resilient we might just ignore invalid TTL or log warning.\n // Given this is core lib, throwing is safer to alert dev.\n throw new Error('TTL must be a positive finite number');\n }\n record.ttlMs = ttlMs;\n }\n \n // We assume K is string for MerkleTree compatibility in this system\n // If K is not string, we might need to stringify it.\n // The project seems to use string keys for maps.\n this.data.set(key, record);\n this.merkleTree.update(String(key), record);\n \n this.notify();\n return record;\n }\n\n /**\n * Retrieves the value for a key.\n * Returns undefined if key doesn't exist, is a tombstone, or is expired.\n */\n public get(key: K): V | undefined {\n const record = this.data.get(key);\n if (!record || record.value === null) {\n return undefined;\n }\n\n // Check for expiration\n if (record.ttlMs) {\n const now = Date.now();\n if (record.timestamp.millis + record.ttlMs < now) {\n return undefined;\n }\n }\n\n return record.value;\n }\n\n /**\n * Returns the full record (including timestamp).\n * Useful for synchronization.\n */\n public getRecord(key: K): LWWRecord<V> | undefined {\n return this.data.get(key);\n }\n\n /**\n * Removes a key (creates a tombstone).\n */\n public remove(key: K): LWWRecord<V> {\n const timestamp = this.hlc.now();\n const tombstone: LWWRecord<V> = { value: null, timestamp };\n \n this.data.set(key, tombstone);\n this.merkleTree.update(String(key), tombstone);\n \n this.notify();\n return tombstone;\n }\n\n /**\n * Merges a record from a remote source.\n * Returns true if the local state was updated.\n */\n public merge(key: K, remoteRecord: LWWRecord<V>): boolean {\n // Update our clock to ensure causality for future events\n this.hlc.update(remoteRecord.timestamp);\n\n const localRecord = this.data.get(key);\n\n // LWW Logic:\n // 1. If no local record, accept remote.\n // 2. If remote is strictly greater than local, accept remote.\n // 3. If equal, we can arbitrarily choose (e.g. by NodeID) to ensure convergence, \n // but HLC.compare handles nodeId tie-breaking already.\n \n if (!localRecord || HLC.compare(remoteRecord.timestamp, localRecord.timestamp) > 0) {\n this.data.set(key, remoteRecord);\n this.merkleTree.update(String(key), remoteRecord);\n \n this.notify();\n return true;\n }\n\n return false;\n }\n\n /**\n * Garbage Collection: Prunes tombstones older than the specified timestamp.\n * Only removes records that are tombstones (deleted) AND older than the threshold.\n * \n * @param olderThan The timestamp threshold. Tombstones older than this will be removed.\n * @returns The number of tombstones removed.\n */\n public prune(olderThan: Timestamp): K[] {\n const removedKeys: K[] = [];\n \n for (const [key, record] of this.data.entries()) {\n // Only prune tombstones (value === null)\n if (record.value === null) {\n // Check if timestamp is strictly older than the threshold\n // HLC.compare(a, b) returns < 0 if a < b\n if (HLC.compare(record.timestamp, olderThan) < 0) {\n this.data.delete(key);\n this.merkleTree.remove(String(key));\n removedKeys.push(key);\n }\n }\n }\n\n if (removedKeys.length > 0) {\n this.notify();\n }\n\n return removedKeys;\n }\n\n /**\n * Clears all data and tombstones.\n * Resets the MerkleTree.\n */\n public clear(): void {\n this.data.clear();\n this.merkleTree = new MerkleTree();\n this.notify();\n }\n\n /**\n * Returns an iterator over all non-deleted entries.\n */\n public entries(): IterableIterator<[K, V]> {\n const iterator = this.data.entries();\n const now = Date.now();\n \n return {\n [Symbol.iterator]() { return this; },\n next: () => {\n let result = iterator.next();\n while (!result.done) {\n const [key, record] = result.value;\n if (record.value !== null) {\n // Check TTL\n if (record.ttlMs && record.timestamp.millis + record.ttlMs < now) {\n result = iterator.next();\n continue;\n }\n return { value: [key, record.value], done: false };\n }\n result = iterator.next();\n }\n return { value: undefined, done: true };\n }\n };\n }\n\n /**\n * Returns all keys (including tombstones).\n */\n public allKeys(): IterableIterator<K> {\n return this.data.keys();\n }\n}\n","import { ORMapRecord } from './ORMap';\nimport { Timestamp } from './HLC';\nimport { hashString } from './utils/hash';\n\n/**\n * Convert Timestamp to deterministic string for hashing.\n * Format: millis:counter:nodeId\n */\nexport function timestampToString(ts: Timestamp): string {\n return `${ts.millis}:${ts.counter}:${ts.nodeId}`;\n}\n\n/**\n * Stringify a value in a deterministic way for hashing.\n */\nfunction stringifyValue(value: unknown): string {\n if (value === null || value === undefined) {\n return String(value);\n }\n if (typeof value === 'object') {\n // Sort object keys for deterministic JSON\n return JSON.stringify(value, Object.keys(value as Record<string, unknown>).sort());\n }\n return String(value);\n}\n\n/**\n * Hash an ORMap entry (key + all its records).\n * Must be deterministic regardless of insertion order.\n *\n * @param key The key of the entry\n * @param records Map of tag -> record for this key\n * @returns Hash as a number (FNV-1a hash)\n */\nexport function hashORMapEntry<V>(\n key: string,\n records: Map<string, ORMapRecord<V>>\n): number {\n // Sort records by tag for deterministic ordering\n const sortedTags = Array.from(records.keys()).sort();\n\n // Build deterministic string representation\n const parts: string[] = [`key:${key}`];\n\n for (const tag of sortedTags) {\n const record = records.get(tag)!;\n // Include tag, value (JSON-stringified), timestamp, and ttl if present\n const valuePart = stringifyValue(record.value);\n\n let recordStr = `${tag}:${valuePart}:${timestampToString(record.timestamp)}`;\n if (record.ttlMs !== undefined) {\n recordStr += `:ttl=${record.ttlMs}`;\n }\n parts.push(recordStr);\n }\n\n return hashString(parts.join('|'));\n}\n\n/**\n * Hash a single ORMapRecord for comparison.\n * Used when comparing individual records during merge.\n */\nexport function hashORMapRecord<V>(record: ORMapRecord<V>): number {\n const valuePart = stringifyValue(record.value);\n\n let str = `${record.tag}:${valuePart}:${timestampToString(record.timestamp)}`;\n if (record.ttlMs !== undefined) {\n str += `:ttl=${record.ttlMs}`;\n }\n\n return hashString(str);\n}\n\n/**\n * Compare two timestamps.\n * Returns:\n * < 0 if a < b\n * > 0 if a > b\n * = 0 if a == b\n */\nexport function compareTimestamps(a: Timestamp, b: Timestamp): number {\n if (a.millis !== b.millis) {\n return a.millis - b.millis;\n }\n if (a.counter !== b.counter) {\n return a.counter - b.counter;\n }\n return a.nodeId.localeCompare(b.nodeId);\n}\n","import { ORMap, ORMapRecord } from './ORMap';\nimport { hashString, combineHashes } from './utils/hash';\nimport { hashORMapEntry } from './ORMapMerkle';\n\n/**\n * Merkle Node for ORMap.\n * Uses a prefix trie structure based on key hash (similar to LWWMap MerkleTree).\n */\nexport interface ORMapMerkleNode {\n hash: number;\n children?: { [key: string]: ORMapMerkleNode }; // Keyed by bucket index (hex char)\n entries?: Map<string, number>; // Leaf node: Key -> ContentHash\n}\n\n/**\n * A Merkle Tree implementation specifically for ORMap synchronization.\n * Uses a Prefix Trie structure based on the hash of the Record Key.\n *\n * Structure:\n * - Level 0: Root\n * - Level 1..N: Buckets based on hex digits of Key Hash.\n *\n * Key difference from LWWMap MerkleTree:\n * - Each key can have multiple records (tags), so the entry hash includes all records for that key.\n */\nexport class ORMapMerkleTree {\n private root: ORMapMerkleNode;\n private readonly depth: number;\n\n constructor(depth: number = 3) {\n this.depth = depth;\n this.root = { hash: 0, children: {} };\n }\n\n /**\n * Update tree from ORMap data.\n * Rebuilds hashes for all entries in the map.\n */\n updateFromORMap<K, V>(map: ORMap<K, V>): void {\n // Clear and rebuild\n this.root = { hash: 0, children: {} };\n\n // Access internal items through available methods\n // We need to iterate over all keys and get their records\n const snapshot = map.getSnapshot();\n\n for (const [key, records] of snapshot.items) {\n if (records.size > 0) {\n const keyStr = String(key);\n const entryHash = hashORMapEntry(keyStr, records);\n const pathHash = hashString(keyStr).toString(16).padStart(8, '0');\n this.updateNode(this.root, keyStr, entryHash, pathHash, 0);\n }\n }\n }\n\n /**\n * Incrementally update a single key's hash.\n * Call this when records for a key change.\n */\n update<V>(key: string, records: Map<string, ORMapRecord<V>>): void {\n const pathHash = hashString(key).toString(16).padStart(8, '0');\n\n if (records.size === 0) {\n // Key has no records, remove from tree\n this.removeNode(this.root, key, pathHash, 0);\n } else {\n const entryHash = hashORMapEntry(key, records);\n this.updateNode(this.root, key, entryHash, pathHash, 0);\n }\n }\n\n /**\n * Remove a key from the tree.\n * Called when all records for a key are removed.\n */\n remove(key: string): void {\n const pathHash = hashString(key).toString(16).padStart(8, '0');\n this.removeNode(this.root, key, pathHash, 0);\n }\n\n private updateNode(\n node: ORMapMerkleNode,\n key: string,\n entryHash: number,\n pathHash: string,\n level: number\n ): number {\n // Leaf Node Logic\n if (level >= this.depth) {\n if (!node.entries) node.entries = new Map();\n node.entries.set(key, entryHash);\n\n // Recalculate leaf hash (Sum of entry hashes)\n let h = 0;\n for (const val of node.entries.values()) {\n h = (h + val) | 0;\n }\n node.hash = h >>> 0;\n return node.hash;\n }\n\n // Intermediate Node Logic\n const bucketChar = pathHash[level];\n if (!node.children) node.children = {};\n\n if (!node.children[bucketChar]) {\n node.children[bucketChar] = { hash: 0 };\n }\n\n this.updateNode(node.children[bucketChar], key, entryHash, pathHash, level + 1);\n\n // Recalculate this node's hash from children\n let h = 0;\n for (const child of Object.values(node.children)) {\n h = (h + child.hash) | 0;\n }\n node.hash = h >>> 0;\n return node.hash;\n }\n\n private removeNode(\n node: ORMapMerkleNode,\n key: string,\n pathHash: string,\n level: number\n ): number {\n // Leaf Node Logic\n if (level >= this.depth) {\n if (node.entries) {\n node.entries.delete(key);\n\n // Recalculate leaf hash\n let h = 0;\n for (const val of node.entries.values()) {\n h = (h + val) | 0;\n }\n node.hash = h >>> 0;\n }\n return node.hash;\n }\n\n // Intermediate Node Logic\n const bucketChar = pathHash[level];\n if (node.children && node.children[bucketChar]) {\n this.removeNode(node.children[bucketChar], key, pathHash, level + 1);\n }\n\n // Recalculate this node's hash from children\n let h = 0;\n if (node.children) {\n for (const child of Object.values(node.children)) {\n h = (h + child.hash) | 0;\n }\n }\n node.hash = h >>> 0;\n return node.hash;\n }\n\n /**\n * Get the root hash for quick comparison.\n */\n getRootHash(): number {\n return this.root.hash;\n }\n\n /**\n * Get node at a specific path.\n */\n getNode(path: string): ORMapMerkleNode | undefined {\n let current = this.root;\n for (const char of path) {\n if (!current.children || !current.children[char]) {\n return undefined;\n }\n current = current.children[char];\n }\n return current;\n }\n\n /**\n * Returns the hashes of the children at the given path.\n * Used by the client/server to compare buckets.\n */\n getBuckets(path: string): Record<string, number> {\n const node = this.getNode(path);\n if (!node || !node.children) return {};\n\n const result: Record<string, number> = {};\n for (const [key, child] of Object.entries(node.children)) {\n result[key] = child.hash;\n }\n return result;\n }\n\n /**\n * For a leaf node (bucket), returns the actual keys it contains.\n * Used to request specific keys when a bucket differs.\n */\n getKeysInBucket(path: string): string[] {\n const node = this.getNode(path);\n if (!node || !node.entries) return [];\n return Array.from(node.entries.keys());\n }\n\n /**\n * Find keys that differ between this tree and bucket info from remote.\n * Returns keys that:\n * - Exist locally but have different hash on remote\n * - Exist on remote but not locally\n * - Exist locally but not on remote\n */\n findDiffKeys(path: string, remoteEntries: Map<string, number>): Set<string> {\n const diffKeys = new Set<string>();\n const node = this.getNode(path);\n const localEntries = node?.entries || new Map();\n\n // Keys in local but not remote, or different hash\n for (const [key, hash] of localEntries) {\n const remoteHash = remoteEntries.get(key);\n if (remoteHash === undefined || remoteHash !== hash) {\n diffKeys.add(key);\n }\n }\n\n // Keys in remote but not local\n for (const key of remoteEntries.keys()) {\n if (!localEntries.has(key)) {\n diffKeys.add(key);\n }\n }\n\n return diffKeys;\n }\n\n /**\n * Get all entry hashes at a leaf path.\n * Used when sending bucket details to remote.\n */\n getEntryHashes(path: string): Map<string, number> {\n const node = this.getNode(path);\n return node?.entries || new Map();\n }\n\n /**\n * Check if a path leads to a leaf node.\n */\n isLeaf(path: string): boolean {\n const node = this.getNode(path);\n return node !== undefined && node.entries !== undefined && node.entries.size > 0;\n }\n}\n","import { HLC, Timestamp } from './HLC';\nimport { ORMapMerkleTree } from './ORMapMerkleTree';\nimport { compareTimestamps } from './ORMapMerkle';\n\n/**\n * A record in the OR-Map (Observed-Remove Map).\n * Represents a single value instance with a unique tag.\n */\nexport interface ORMapRecord<V> {\n value: V;\n timestamp: Timestamp;\n tag: string; // Unique identifier (UUID + Timestamp)\n ttlMs?: number;\n}\n\n/**\n * Result of merging records for a key.\n */\nexport interface MergeKeyResult {\n added: number;\n updated: number;\n}\n\n/**\n * Snapshot of ORMap internal state for Merkle Tree synchronization.\n */\nexport interface ORMapSnapshot<K, V> {\n items: Map<K, Map<string, ORMapRecord<V>>>;\n tombstones: Set<string>;\n}\n\n/**\n * OR-Map (Observed-Remove Map) Implementation.\n * \n * Acts as a Multimap where each Key holds a Set of Values.\n * Supports concurrent additions to the same key without data loss.\n * \n * Logic:\n * - Add(K, V): Generates a unique tag. Stores (V, tag) under K.\n * - Remove(K, V): Finds all *currently observed* tags for V under K, and moves them to a Remove Set (Tombstones).\n * - Merge: Union of items minus Union of tombstones.\n */\nexport class ORMap<K, V> {\n // Key -> Map<Tag, Record>\n // Stores active records.\n private items: Map<K, Map<string, ORMapRecord<V>>>;\n\n // Set of removed tags (Tombstones).\n private tombstones: Set<string>;\n\n // Set of expired tags (Local only cache for fast filtering)\n // Note: We don't persist this directly, but rely on filtering.\n // For now, we will just filter on get()\n\n private readonly hlc: HLC;\n\n // Merkle Tree for efficient sync\n private merkleTree: ORMapMerkleTree;\n\n constructor(hlc: HLC) {\n this.hlc = hlc;\n this.items = new Map();\n this.tombstones = new Set();\n this.merkleTree = new ORMapMerkleTree();\n }\n\n private listeners: Array<() => void> = [];\n\n public onChange(callback: () => void): () => void {\n this.listeners.push(callback);\n return () => {\n this.listeners = this.listeners.filter(cb => cb !== callback);\n };\n }\n\n private notify(): void {\n this.listeners.forEach(cb => cb());\n }\n\n public get size(): number {\n return this.items.size;\n }\n\n public get totalRecords(): number {\n let count = 0;\n for (const keyMap of this.items.values()) {\n count += keyMap.size;\n }\n return count;\n }\n\n /**\n * Adds a value to the set associated with the key.\n * Generates a unique tag for this specific addition.\n */\n public add(key: K, value: V, ttlMs?: number): ORMapRecord<V> {\n const timestamp = this.hlc.now();\n // Tag must be unique globally. HLC.toString() provides unique string per node+time.\n const tag = HLC.toString(timestamp);\n\n const record: ORMapRecord<V> = {\n value,\n timestamp,\n tag\n };\n\n if (ttlMs !== undefined) {\n if (typeof ttlMs !== 'number' || ttlMs <= 0 || !Number.isFinite(ttlMs)) {\n throw new Error('TTL must be a positive finite number');\n }\n record.ttlMs = ttlMs;\n }\n\n let keyMap = this.items.get(key);\n if (!keyMap) {\n keyMap = new Map();\n this.items.set(key, keyMap);\n }\n\n keyMap.set(tag, record);\n this.updateMerkleTree(key);\n this.notify();\n return record;\n }\n\n /**\n * Removes a specific value from the set associated with the key.\n * Marks all *currently observed* instances of this value as removed (tombstones).\n * Returns the list of tags that were removed (useful for sync).\n */\n public remove(key: K, value: V): string[] {\n const keyMap = this.items.get(key);\n if (!keyMap) return [];\n\n // Find all tags for this value\n const tagsToRemove: string[] = [];\n\n for (const [tag, record] of keyMap.entries()) {\n // Using strict equality. For objects, this requires the exact instance.\n if (record.value === value) {\n tagsToRemove.push(tag);\n }\n }\n\n for (const tag of tagsToRemove) {\n this.tombstones.add(tag);\n keyMap.delete(tag);\n }\n\n if (keyMap.size === 0) {\n this.items.delete(key);\n }\n\n this.updateMerkleTree(key);\n this.notify();\n return tagsToRemove;\n }\n\n /**\n * Clears all data and tombstones.\n */\n public clear(): void {\n this.items.clear();\n this.tombstones.clear();\n this.merkleTree = new ORMapMerkleTree();\n this.notify();\n }\n\n /**\n * Returns all active values for a key.\n * Filters out expired records.\n */\n public get(key: K): V[] {\n const keyMap = this.items.get(key);\n if (!keyMap) return [];\n\n const values: V[] = [];\n const now = Date.now();\n\n for (const [tag, record] of keyMap.entries()) {\n if (!this.tombstones.has(tag)) {\n // Check expiration\n if (record.ttlMs && record.timestamp.millis + record.ttlMs < now) {\n continue;\n }\n values.push(record.value);\n }\n }\n return values;\n }\n\n /**\n * Returns all active records for a key.\n * Useful for persistence and sync.\n * Filters out expired records.\n */\n public getRecords(key: K): ORMapRecord<V>[] {\n const keyMap = this.items.get(key);\n if (!keyMap) return [];\n\n const records: ORMapRecord<V>[] = [];\n const now = Date.now();\n\n for (const [tag, record] of keyMap.entries()) {\n if (!this.tombstones.has(tag)) {\n // Check expiration\n if (record.ttlMs && record.timestamp.millis + record.ttlMs < now) {\n continue;\n }\n records.push(record);\n }\n }\n return records;\n }\n\n /**\n * Returns all tombstone tags.\n */\n public getTombstones(): string[] {\n return Array.from(this.tombstones);\n }\n\n /**\n * Applies a record from a remote source (Sync).\n * Returns true if the record was applied (not tombstoned).\n */\n public apply(key: K, record: ORMapRecord<V>): boolean {\n if (this.tombstones.has(record.tag)) return false;\n\n let keyMap = this.items.get(key);\n if (!keyMap) {\n keyMap = new Map();\n this.items.set(key, keyMap);\n }\n keyMap.set(record.tag, record);\n this.hlc.update(record.timestamp);\n this.updateMerkleTree(key);\n this.notify();\n return true;\n }\n\n /**\n * Applies a tombstone (deletion) from a remote source.\n */\n public applyTombstone(tag: string): void {\n this.tombstones.add(tag);\n // Cleanup active items if present\n for (const [key, keyMap] of this.items) {\n if (keyMap.has(tag)) {\n keyMap.delete(tag);\n if (keyMap.size === 0) this.items.delete(key);\n this.updateMerkleTree(key);\n // We found it, so we can stop searching (tag is unique globally)\n break;\n }\n }\n this.notify();\n }\n\n /**\n * Merges state from another ORMap.\n * - Adds all new tombstones from 'other'.\n * - Adds all new items from 'other' that are not in tombstones.\n * - Updates HLC with observed timestamps.\n */\n public merge(other: ORMap<K, V>): void {\n const changedKeys = new Set<K>();\n\n // 1. Merge tombstones\n for (const tag of other.tombstones) {\n this.tombstones.add(tag);\n }\n\n // 2. Merge items\n for (const [key, otherKeyMap] of other.items) {\n let localKeyMap = this.items.get(key);\n if (!localKeyMap) {\n localKeyMap = new Map();\n this.items.set(key, localKeyMap);\n }\n\n for (const [tag, record] of otherKeyMap) {\n // Only accept if not deleted\n if (!this.tombstones.has(tag)) {\n if (!localKeyMap.has(tag)) {\n localKeyMap.set(tag, record);\n changedKeys.add(key);\n }\n // Always update causality\n this.hlc.update(record.timestamp);\n }\n }\n }\n\n // 3. Cleanup: Remove any local items that are now in the merged tombstones\n for (const [key, localKeyMap] of this.items) {\n for (const tag of localKeyMap.keys()) {\n if (this.tombstones.has(tag)) {\n localKeyMap.delete(tag);\n changedKeys.add(key);\n }\n }\n if (localKeyMap.size === 0) {\n this.items.delete(key);\n }\n }\n\n // Update Merkle Tree for changed keys\n for (const key of changedKeys) {\n this.updateMerkleTree(key);\n }\n\n this.notify();\n }\n\n /**\n * Garbage Collection: Prunes tombstones older than the specified timestamp.\n */\n public prune(olderThan: Timestamp): string[] {\n const removedTags: string[] = [];\n\n for (const tag of this.tombstones) {\n try {\n const timestamp = HLC.parse(tag);\n if (HLC.compare(timestamp, olderThan) < 0) {\n this.tombstones.delete(tag);\n removedTags.push(tag);\n }\n } catch (e) {\n // Ignore invalid tags\n }\n }\n\n return removedTags;\n }\n\n // ============ Merkle Sync Methods ============\n\n /**\n * Get the Merkle Tree for this ORMap.\n * Used for efficient synchronization.\n */\n public getMerkleTree(): ORMapMerkleTree {\n return this.merkleTree;\n }\n\n /**\n * Get a snapshot of internal state for Merkle Tree synchronization.\n * Returns references to internal structures - do not modify!\n */\n public getSnapshot(): ORMapSnapshot<K, V> {\n return {\n items: this.items,\n tombstones: this.tombstones\n };\n }\n\n /**\n * Get all keys in this ORMap.\n */\n public allKeys(): K[] {\n return Array.from(this.items.keys());\n }\n\n /**\n * Get the internal records map for a key.\n * Returns Map<tag, record> or undefined if key doesn't exist.\n * Used for Merkle sync.\n */\n public getRecordsMap(key: K): Map<string, ORMapRecord<V>> | undefined {\n return this.items.get(key);\n }\n\n /**\n * Merge remote records for a specific key into local state.\n * Implements Observed-Remove CRDT semantics.\n * Used during Merkle Tree synchronization.\n *\n * @param key The key to merge\n * @param remoteRecords Array of records from remote\n * @param remoteTombstones Array of tombstone tags from remote\n * @returns Result with count of added and updated records\n */\n public mergeKey(\n key: K,\n remoteRecords: ORMapRecord<V>[],\n remoteTombstones: string[] = []\n ): MergeKeyResult {\n let added = 0;\n let updated = 0;\n\n // First apply remote tombstones\n for (const tag of remoteTombstones) {\n if (!this.tombstones.has(tag)) {\n this.tombstones.add(tag);\n }\n }\n\n // Get or create local key map\n let localKeyMap = this.items.get(key);\n if (!localKeyMap) {\n localKeyMap = new Map();\n this.items.set(key, localKeyMap);\n }\n\n // Remove any local records that are now tombstoned\n for (const tag of localKeyMap.keys()) {\n if (this.tombstones.has(tag)) {\n localKeyMap.delete(tag);\n }\n }\n\n // Merge remote records\n for (const remoteRecord of remoteRecords) {\n // Skip if tombstoned\n if (this.tombstones.has(remoteRecord.tag)) {\n continue;\n }\n\n const localRecord = localKeyMap.get(remoteRecord.tag);\n\n if (!localRecord) {\n // New record - add it\n localKeyMap.set(remoteRecord.tag, remoteRecord);\n added++;\n } else if (compareTimestamps(remoteRecord.timestamp, localRecord.timestamp) > 0) {\n // Remote is newer - update\n localKeyMap.set(remoteRecord.tag, remoteRecord);\n updated++;\n }\n // Else: local is newer or equal, keep local\n\n // Always update causality\n this.hlc.update(remoteRecord.timestamp);\n }\n\n // Cleanup empty key map\n if (localKeyMap.size === 0) {\n this.items.delete(key);\n }\n\n // Update Merkle Tree\n this.updateMerkleTree(key);\n\n if (added > 0 || updated > 0) {\n this.notify();\n }\n\n return { added, updated };\n }\n\n /**\n * Check if a tag is tombstoned.\n */\n public isTombstoned(tag: string): boolean {\n return this.tombstones.has(tag);\n }\n\n /**\n * Update the Merkle Tree for a specific key.\n * Called internally after any modification.\n */\n private updateMerkleTree(key: K): void {\n const keyStr = String(key);\n const keyMap = this.items.get(key);\n\n if (!keyMap || keyMap.size === 0) {\n this.merkleTree.remove(keyStr);\n } else {\n this.merkleTree.update(keyStr, keyMap);\n }\n }\n}\n","import { pack, unpack } from 'msgpackr';\n\n/**\n * Serializes a JavaScript object to MessagePack binary format.\n * Uses msgpackr for 2-5x faster serialization compared to @msgpack/msgpack.\n * @param data The data to serialize.\n * @returns A Uint8Array containing the serialized data.\n */\nexport function serialize(data: unknown): Uint8Array {\n return pack(data);\n}\n\n/**\n * Deserializes MessagePack binary data to a JavaScript object.\n * Uses msgpackr for 2-5x faster deserialization compared to @msgpack/msgpack.\n * @param data The binary data to deserialize (Uint8Array or ArrayBuffer).\n * @returns The deserialized object.\n */\nexport function deserialize<T = unknown>(data: Uint8Array | ArrayBuffer): T {\n // msgpackr unpack accepts Uint8Array, Buffer, ArrayBuffer\n const buffer = data instanceof ArrayBuffer ? new Uint8Array(data) : data;\n return unpack(buffer) as T;\n}\n\n","import { serialize, deserialize } from './serializer';\n\n/**\n * State of a PN Counter CRDT.\n * Tracks positive and negative increments per node for convergence.\n */\nexport interface PNCounterState {\n /** Positive increments per node */\n positive: Map<string, number>;\n /** Negative increments per node */\n negative: Map<string, number>;\n}\n\n/**\n * Serializable form of PNCounterState for network/storage.\n */\nexport interface PNCounterStateObject {\n /** Positive increments per node as object */\n p: Record<string, number>;\n /** Negative increments per node as object */\n n: Record<string, number>;\n}\n\n/**\n * Configuration for creating a PN Counter.\n */\nexport interface PNCounterConfig {\n /** Unique node identifier for this counter instance */\n nodeId: string;\n /** Initial state to restore from */\n initialState?: PNCounterState;\n}\n\n/**\n * Interface for PN Counter CRDT.\n */\nexport interface PNCounter {\n /** Get current value */\n get(): number;\n\n /** Increment by 1, return new value */\n increment(): number;\n\n /** Decrement by 1, return new value */\n decrement(): number;\n\n /** Add delta (positive or negative), return new value */\n addAndGet(delta: number): number;\n\n /** Get state for sync */\n getState(): PNCounterState;\n\n /** Merge remote state */\n merge(remote: PNCounterState): void;\n\n /** Subscribe to value changes */\n subscribe(listener: (value: number) => void): () => void;\n}\n\n/**\n * Positive-Negative Counter CRDT implementation.\n *\n * A PN Counter is a CRDT that supports increment and decrement operations\n * on any node, works offline, and guarantees convergence without coordination.\n *\n * How it works:\n * - Tracks positive increments per node in a G-Counter\n * - Tracks negative increments per node in another G-Counter\n * - Value = sum(positive) - sum(negative)\n * - Merge takes max for each node in both counters\n *\n * @example\n * ```typescript\n * const counter = new PNCounterImpl({ nodeId: 'node-1' });\n * counter.increment(); // 1\n * counter.increment(); // 2\n * counter.decrement(); // 1\n * counter.addAndGet(5); // 6\n * ```\n */\nexport class PNCounterImpl implements PNCounter {\n private readonly nodeId: string;\n private state: PNCounterState;\n private listeners: Set<(value: number) => void> = new Set();\n\n constructor(config: PNCounterConfig) {\n this.nodeId = config.nodeId;\n this.state = config.initialState ?? {\n positive: new Map(),\n negative: new Map(),\n };\n }\n\n /**\n * Get the current counter value.\n * Value = sum(positive) - sum(negative)\n */\n get(): number {\n let sum = 0;\n for (const v of this.state.positive.values()) sum += v;\n for (const v of this.state.negative.values()) sum -= v;\n return sum;\n }\n\n /**\n * Increment by 1 and return the new value.\n */\n increment(): number {\n return this.addAndGet(1);\n }\n\n /**\n * Decrement by 1 and return the new value.\n */\n decrement(): number {\n return this.addAndGet(-1);\n }\n\n /**\n * Add a delta (positive or negative) and return the new value.\n * @param delta The amount to add (can be negative)\n */\n addAndGet(delta: number): number {\n if (delta === 0) return this.get();\n\n if (delta > 0) {\n const current = this.state.positive.get(this.nodeId) ?? 0;\n this.state.positive.set(this.nodeId, current + delta);\n } else {\n const current = this.state.negative.get(this.nodeId) ?? 0;\n this.state.negative.set(this.nodeId, current + Math.abs(delta));\n }\n\n const newValue = this.get();\n this.notifyListeners(newValue);\n return newValue;\n }\n\n /**\n * Get a copy of the current state for synchronization.\n */\n getState(): PNCounterState {\n return {\n positive: new Map(this.state.positive),\n negative: new Map(this.state.negative),\n };\n }\n\n /**\n * Merge remote state into this counter.\n * Takes the maximum value for each node in both positive and negative counters.\n * This operation is commutative, associative, and idempotent (CRDT properties).\n *\n * @param remote The remote state to merge\n */\n merge(remote: PNCounterState): void {\n let changed = false;\n\n // Merge positive: take max for each node\n for (const [nodeId, value] of remote.positive) {\n const current = this.state.positive.get(nodeId) ?? 0;\n if (value > current) {\n this.state.positive.set(nodeId, value);\n changed = true;\n }\n }\n\n // Merge negative: take max for each node\n for (const [nodeId, value] of remote.negative) {\n const current = this.state.negative.get(nodeId) ?? 0;\n if (value > current) {\n this.state.negative.set(nodeId, value);\n changed = true;\n }\n }\n\n if (changed) {\n this.notifyListeners(this.get());\n }\n }\n\n /**\n * Subscribe to value changes.\n * The listener is immediately called with the current value.\n *\n * @param listener Callback function receiving the new value\n * @returns Unsubscribe function\n */\n subscribe(listener: (value: number) => void): () => void {\n this.listeners.add(listener);\n // Immediately notify with current value\n listener(this.get());\n return () => this.listeners.delete(listener);\n }\n\n private notifyListeners(value: number): void {\n for (const listener of this.listeners) {\n try {\n listener(value);\n } catch (e) {\n // Silently catch listener errors to prevent breaking other listeners\n }\n }\n }\n\n /**\n * Get the node ID of this counter instance.\n */\n getNodeId(): string {\n return this.nodeId;\n }\n\n // ============================================\n // Serialization\n // ============================================\n\n /**\n * Serialize state to binary format (msgpack).\n */\n static serialize(state: PNCounterState): Uint8Array {\n const obj: PNCounterStateObject = {\n p: Object.fromEntries(state.positive),\n n: Object.fromEntries(state.negative),\n };\n return serialize(obj);\n }\n\n /**\n * Deserialize binary data to state.\n */\n static deserialize(data: Uint8Array): PNCounterState {\n const obj = deserialize<PNCounterStateObject>(data);\n return {\n positive: new Map(Object.entries(obj.p)),\n negative: new Map(Object.entries(obj.n)),\n };\n }\n\n /**\n * Convert state to plain object (for JSON/network).\n */\n static stateToObject(state: PNCounterState): PNCounterStateObject {\n return {\n p: Object.fromEntries(state.positive),\n n: Object.fromEntries(state.negative),\n };\n }\n\n /**\n * Convert plain object to state.\n */\n static objectToState(obj: PNCounterStateObject): PNCounterState {\n return {\n positive: new Map(Object.entries(obj.p)),\n negative: new Map(Object.entries(obj.n)),\n };\n }\n}\n","/**\n * Fixed-size circular buffer with sequence numbers.\n * Older entries are overwritten when capacity is reached.\n *\n * @template T - Type of items stored in the buffer\n */\nexport class Ringbuffer<T> {\n private buffer: (T | undefined)[];\n private readonly _capacity: number;\n private headSequence: bigint = 0n; // Oldest available sequence\n private tailSequence: bigint = 0n; // Next sequence to write\n\n constructor(capacity: number) {\n if (capacity < 1) {\n throw new Error('Capacity must be >= 1');\n }\n this._capacity = capacity;\n this.buffer = new Array(capacity);\n }\n\n /**\n * Add item to buffer, returns sequence number.\n */\n add(item: T): bigint {\n const sequence = this.tailSequence;\n const index = Number(sequence % BigInt(this._capacity));\n\n this.buffer[index] = item;\n this.tailSequence++;\n\n // Advance head if we overwrote oldest\n if (this.tailSequence - this.headSequence > this._capacity) {\n this.headSequence = this.tailSequence - BigInt(this._capacity);\n }\n\n return sequence;\n }\n\n /**\n * Read item at sequence.\n * Returns undefined if sequence is out of range.\n */\n read(sequence: bigint): T | undefined {\n if (sequence < this.headSequence || sequence >= this.tailSequence) {\n return undefined;\n }\n const index = Number(sequence % BigInt(this._capacity));\n return this.buffer[index];\n }\n\n /**\n * Read range of items (inclusive).\n * Automatically clamps to available range.\n */\n readRange(startSeq: bigint, endSeq: bigint): T[] {\n const items: T[] = [];\n const actualStart = startSeq < this.headSequence ? this.headSequence : startSeq;\n const actualEnd = endSeq >= this.tailSequence ? this.tailSequence - 1n : endSeq;\n\n for (let seq = actualStart; seq <= actualEnd; seq++) {\n const item = this.read(seq);\n if (item !== undefined) {\n items.push(item);\n }\n }\n\n return items;\n }\n\n /**\n * Read from sequence with limit.\n */\n readFrom(startSeq: bigint, limit: number = 100): T[] {\n const endSeq = startSeq + BigInt(limit) - 1n;\n return this.readRange(startSeq, endSeq);\n }\n\n /**\n * Get the oldest available sequence number.\n */\n getHeadSequence(): bigint {\n return this.headSequence;\n }\n\n /**\n * Get the next sequence number to be written.\n */\n getTailSequence(): bigint {\n return this.tailSequence;\n }\n\n /**\n * Get the number of items currently in the buffer.\n */\n size(): number {\n return Number(this.tailSequence - this.headSequence);\n }\n\n /**\n * Get the maximum capacity of the buffer.\n */\n getCapacity(): number {\n return this._capacity;\n }\n\n /**\n * Clear all items from the buffer.\n */\n clear(): void {\n this.buffer = new Array(this._capacity);\n this.headSequence = 0n;\n this.tailSequence = 0n;\n }\n\n /**\n * Check if a sequence is available in the buffer.\n */\n isAvailable(sequence: bigint): boolean {\n return sequence >= this.headSequence && sequence < this.tailSequence;\n }\n\n /**\n * Get remaining capacity before oldest entries are overwritten.\n */\n remainingCapacity(): number {\n return this._capacity - this.size();\n }\n}\n","import { Ringbuffer } from './Ringbuffer';\nimport type { Timestamp } from './HLC';\n\n/**\n * Type of journal event.\n */\nexport type JournalEventType = 'PUT' | 'UPDATE' | 'DELETE';\n\n/**\n * Single event in the journal.\n */\nexport interface JournalEvent<V = unknown> {\n /** Monotonically increasing sequence number */\n sequence: bigint;\n\n /** Event type */\n type: JournalEventType;\n\n /** Map name */\n mapName: string;\n\n /** Entry key */\n key: string;\n\n /** New value (undefined for DELETE) */\n value?: V;\n\n /** Previous value (for UPDATE and DELETE) */\n previousValue?: V;\n\n /** HLC timestamp */\n timestamp: Timestamp;\n\n /** Node that made the change */\n nodeId: string;\n\n /** Optional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Input for appending events (without sequence).\n */\nexport type JournalEventInput<V = unknown> = Omit<JournalEvent<V>, 'sequence'>;\n\n/**\n * Event Journal configuration.\n */\nexport interface EventJournalConfig {\n /** Maximum number of events to keep in memory */\n capacity: number;\n\n /** Time-to-live for events (ms), 0 = infinite */\n ttlMs: number;\n\n /** Persist to storage adapter */\n persistent: boolean;\n\n /** Maps to include (empty = all) */\n includeMaps?: string[];\n\n /** Maps to exclude */\n excludeMaps?: string[];\n}\n\n/**\n * Default configuration for Event Journal.\n */\nexport const DEFAULT_EVENT_JOURNAL_CONFIG: EventJournalConfig = {\n capacity: 10000,\n ttlMs: 0, // Infinite\n persistent: true,\n includeMaps: [],\n excludeMaps: [],\n};\n\n/**\n * Event Journal interface.\n */\nexport interface EventJournal {\n /** Append event to journal */\n append<V>(event: JournalEventInput<V>): JournalEvent<V>;\n\n /** Read events from sequence (inclusive) */\n readFrom(sequence: bigint, limit?: number): JournalEvent[];\n\n /** Read events in range */\n readRange(startSeq: bigint, endSeq: bigint): JournalEvent[];\n\n /** Get latest sequence number */\n getLatestSequence(): bigint;\n\n /** Get oldest sequence number (after compaction) */\n getOldestSequence(): bigint;\n\n /** Subscribe to new events */\n subscribe(\n listener: (event: JournalEvent) => void,\n fromSequence?: bigint\n ): () => void;\n\n /** Get capacity info */\n getCapacity(): { used: number; total: number };\n\n /** Force compaction */\n compact(): Promise<void>;\n\n /** Dispose resources */\n dispose(): void;\n}\n\n/**\n * Journal event listener type.\n */\nexport type JournalEventListener = (event: JournalEvent) => void;\n\n/**\n * Event Journal implementation using Ringbuffer.\n * Records all Map changes as an append-only log.\n */\nexport class EventJournalImpl implements EventJournal {\n private readonly config: EventJournalConfig;\n private readonly buffer: Ringbuffer<JournalEvent>;\n private readonly listeners: Set<JournalEventListener> = new Set();\n private ttlTimer?: ReturnType<typeof setInterval>;\n\n constructor(config: Partial<EventJournalConfig> = {}) {\n this.config = { ...DEFAULT_EVENT_JOURNAL_CONFIG, ...config };\n this.buffer = new Ringbuffer(this.config.capacity);\n\n if (this.config.ttlMs > 0) {\n this.startTTLCleanup();\n }\n }\n\n /**\n * Append event to journal.\n * Returns the event with assigned sequence number.\n * Returns event with sequence -1n if map is filtered out.\n */\n append<V>(eventData: JournalEventInput<V>): JournalEvent<V> {\n // Check map filters\n if (!this.shouldCapture(eventData.mapName)) {\n return { ...eventData, sequence: -1n } as JournalEvent<V>;\n }\n\n const event: JournalEvent<V> = {\n ...eventData,\n sequence: 0n, // Will be set by buffer\n };\n\n const sequence = this.buffer.add(event);\n event.sequence = sequence;\n\n // Notify listeners\n for (const listener of this.listeners) {\n try {\n listener(event);\n } catch (e) {\n console.error('EventJournal listener error:', e);\n }\n }\n\n return event;\n }\n\n /**\n * Read events from sequence with optional limit.\n */\n readFrom(sequence: bigint, limit: number = 100): JournalEvent[] {\n return this.buffer.readFrom(sequence, limit);\n }\n\n /**\n * Read events in range (inclusive).\n */\n readRange(startSeq: bigint, endSeq: bigint): JournalEvent[] {\n return this.buffer.readRange(startSeq, endSeq);\n }\n\n /**\n * Get latest sequence number.\n * Returns 0n if no events have been added.\n */\n getLatestSequence(): bigint {\n const tail = this.buffer.getTailSequence();\n return tail > 0n ? tail - 1n : 0n;\n }\n\n /**\n * Get oldest available sequence number.\n */\n getOldestSequence(): bigint {\n return this.buffer.getHeadSequence();\n }\n\n /**\n * Subscribe to new events.\n * Optionally replay events from a specific sequence.\n *\n * @param listener Callback for each event\n * @param fromSequence Optional sequence to start replay from\n * @returns Unsubscribe function\n */\n subscribe(\n listener: JournalEventListener,\n fromSequence?: bigint\n ): () => void {\n // Replay events if fromSequence is specified\n if (fromSequence !== undefined) {\n const events = this.readFrom(fromSequence, this.config.capacity);\n for (const event of events) {\n try {\n listener(event);\n } catch (e) {\n console.error('EventJournal replay error:', e);\n }\n }\n }\n\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Get capacity information.\n */\n getCapacity(): { used: number; total: number } {\n return {\n used: this.buffer.size(),\n total: this.buffer.getCapacity(),\n };\n }\n\n /**\n * Force compaction.\n * Note: The ringbuffer handles eviction automatically.\n * This method is provided for explicit cleanup of old events.\n */\n async compact(): Promise<void> {\n // The ringbuffer automatically evicts old entries when full.\n // TTL-based cleanup is handled by the timer.\n // This method can be extended for additional cleanup logic.\n }\n\n /**\n * Check if a map should be captured.\n */\n private shouldCapture(mapName: string): boolean {\n const { includeMaps, excludeMaps } = this.config;\n\n if (excludeMaps && excludeMaps.includes(mapName)) {\n return false;\n }\n\n if (includeMaps && includeMaps.length > 0) {\n return includeMaps.includes(mapName);\n }\n\n return true;\n }\n\n /**\n * Start TTL cleanup timer.\n */\n private startTTLCleanup(): void {\n const interval = Math.min(this.config.ttlMs, 60000); // At least every minute\n this.ttlTimer = setInterval(() => {\n this.compact();\n }, interval);\n }\n\n /**\n * Dispose resources.\n */\n dispose(): void {\n if (this.ttlTimer) {\n clearInterval(this.ttlTimer);\n this.ttlTimer = undefined;\n }\n this.listeners.clear();\n }\n\n /**\n * Get all current listeners count (for testing).\n */\n getListenerCount(): number {\n return this.listeners.size;\n }\n\n /**\n * Get configuration (for testing).\n */\n getConfig(): EventJournalConfig {\n return { ...this.config };\n }\n}\n","import { z } from 'zod';\n\n// --- Entry Processor Types ---\n\n/**\n * Function executed on the server against a single entry.\n * Receives the current value (or undefined if key doesn't exist).\n * Returns the new value (or undefined to delete the entry).\n */\nexport type EntryProcessorFn<V, R = V> = (\n value: V | undefined,\n key: string,\n args?: unknown,\n) => { value: V | undefined; result?: R };\n\n/**\n * Zod schema for entry processor definition validation.\n */\nexport const EntryProcessorDefSchema = z.object({\n name: z.string().min(1).max(100),\n code: z.string().min(1).max(10000), // Max 10KB code\n args: z.unknown().optional(),\n});\n\n/**\n * Serializable entry processor definition.\n * Code is sent as string and executed in isolated sandbox.\n */\nexport interface EntryProcessorDef<V = unknown, R = V> {\n /** Unique processor name for caching compiled code */\n name: string;\n\n /** JavaScript function body as string */\n code: string;\n\n /** Optional arguments passed to the processor */\n args?: unknown;\n\n /** Type markers (not serialized) */\n __valueType?: V;\n __resultType?: R;\n}\n\n/**\n * Result of entry processor execution.\n */\nexport interface EntryProcessorResult<R = unknown> {\n /** Whether the operation succeeded */\n success: boolean;\n\n /** Custom result returned by processor */\n result?: R;\n\n /** Error message if failed */\n error?: string;\n\n /** New value after processing (for client cache update) */\n newValue?: unknown;\n}\n\n// --- Security: Forbidden Patterns ---\n\n/**\n * Patterns that are denied in processor code for security reasons.\n */\nexport const FORBIDDEN_PATTERNS = [\n /\\beval\\b/,\n /\\bFunction\\b/,\n /\\bprocess\\b/,\n /\\bglobal\\b/,\n /\\brequire\\b/,\n /\\bimport\\b/,\n /\\bfetch\\b/,\n /\\bXMLHttpRequest\\b/,\n /\\bsetTimeout\\b/,\n /\\bsetInterval\\b/,\n /\\bsetImmediate\\b/,\n];\n\n/**\n * Validates processor code against forbidden patterns.\n * Returns true if code is safe, false otherwise.\n */\nexport function validateProcessorCode(code: string): {\n valid: boolean;\n error?: string;\n} {\n for (const pattern of FORBIDDEN_PATTERNS) {\n if (pattern.test(code)) {\n return {\n valid: false,\n error: `Forbidden pattern detected: ${pattern.source}`,\n };\n }\n }\n return { valid: true };\n}\n\n// --- Built-in Processors ---\n\n/**\n * Built-in processors for common operations.\n * These are type-safe and pre-validated.\n */\nexport const BuiltInProcessors = {\n /**\n * Increment numeric value by delta.\n * If value doesn't exist, starts from 0.\n */\n INCREMENT: (delta: number = 1): EntryProcessorDef<number, number> => ({\n name: 'builtin:increment',\n code: `\n const current = value ?? 0;\n const newValue = current + args;\n return { value: newValue, result: newValue };\n `,\n args: delta,\n }),\n\n /**\n * Decrement numeric value by delta.\n * If value doesn't exist, starts from 0.\n */\n DECREMENT: (delta: number = 1): EntryProcessorDef<number, number> => ({\n name: 'builtin:decrement',\n code: `\n const current = value ?? 0;\n const newValue = current - args;\n return { value: newValue, result: newValue };\n `,\n args: delta,\n }),\n\n /**\n * Decrement with floor (won't go below 0).\n * Returns both the new value and whether it was floored.\n */\n DECREMENT_FLOOR: (\n delta: number = 1,\n ): EntryProcessorDef<number, { newValue: number; wasFloored: boolean }> => ({\n name: 'builtin:decrement_floor',\n code: `\n const current = value ?? 0;\n const target = current - args;\n const newValue = Math.max(0, target);\n return {\n value: newValue,\n result: { newValue, wasFloored: target < 0 }\n };\n `,\n args: delta,\n }),\n\n /**\n * Multiply numeric value by factor.\n * If value doesn't exist, starts from 1.\n */\n MULTIPLY: (factor: number): EntryProcessorDef<number, number> => ({\n name: 'builtin:multiply',\n code: `\n const current = value ?? 1;\n const newValue = current * args;\n return { value: newValue, result: newValue };\n `,\n args: factor,\n }),\n\n /**\n * Set value only if key doesn't exist.\n * Returns true if value was set, false if key already existed.\n */\n PUT_IF_ABSENT: <V>(newValue: V): EntryProcessorDef<V, boolean> => ({\n name: 'builtin:put_if_absent',\n code: `\n if (value !== undefined) {\n return { value, result: false };\n }\n return { value: args, result: true };\n `,\n args: newValue,\n }),\n\n /**\n * Replace value only if key exists.\n * Returns the old value if replaced, undefined otherwise.\n */\n REPLACE: <V>(newValue: V): EntryProcessorDef<V, V | undefined> => ({\n name: 'builtin:replace',\n code: `\n if (value === undefined) {\n return { value: undefined, result: undefined };\n }\n return { value: args, result: value };\n `,\n args: newValue,\n }),\n\n /**\n * Replace value only if it matches expected value.\n * Returns true if replaced, false otherwise.\n */\n REPLACE_IF_EQUALS: <V>(\n expectedValue: V,\n newValue: V,\n ): EntryProcessorDef<V, boolean> => ({\n name: 'builtin:replace_if_equals',\n code: `\n if (JSON.stringify(value) === JSON.stringify(args.expected)) {\n return { value: args.newValue, result: true };\n }\n return { value, result: false };\n `,\n args: { expected: expectedValue, newValue },\n }),\n\n /**\n * Delete entry only if value matches.\n * Returns true if deleted, false otherwise.\n */\n DELETE_IF_EQUALS: <V>(expectedValue: V): EntryProcessorDef<V, boolean> => ({\n name: 'builtin:delete_if_equals',\n code: `\n if (JSON.stringify(value) === JSON.stringify(args)) {\n return { value: undefined, result: true };\n }\n return { value, result: false };\n `,\n args: expectedValue,\n }),\n\n /**\n * Append item to array.\n * Creates array if it doesn't exist.\n * Returns new array length.\n */\n ARRAY_PUSH: <T>(item: T): EntryProcessorDef<T[], number> => ({\n name: 'builtin:array_push',\n code: `\n const arr = value ?? [];\n arr.push(args);\n return { value: arr, result: arr.length };\n `,\n args: item,\n }),\n\n /**\n * Remove last item from array.\n * Returns the removed item or undefined.\n */\n ARRAY_POP: <T>(): EntryProcessorDef<T[], T | undefined> => ({\n name: 'builtin:array_pop',\n code: `\n if (!value || value.length === 0) {\n return { value: value ?? [], result: undefined };\n }\n const removed = value.pop();\n return { value, result: removed };\n `,\n }),\n\n /**\n * Remove item from array by value (first occurrence).\n * Returns true if item was found and removed.\n */\n ARRAY_REMOVE: <T>(item: T): EntryProcessorDef<T[], boolean> => ({\n name: 'builtin:array_remove',\n code: `\n if (!value) {\n return { value: [], result: false };\n }\n const idx = value.findIndex(v => JSON.stringify(v) === JSON.stringify(args));\n if (idx === -1) {\n return { value, result: false };\n }\n value.splice(idx, 1);\n return { value, result: true };\n `,\n args: item,\n }),\n\n /**\n * Update nested property using dot notation path.\n * Creates intermediate objects if they don't exist.\n */\n SET_PROPERTY: <V>(\n path: string,\n propValue: unknown,\n ): EntryProcessorDef<V, V> => ({\n name: 'builtin:set_property',\n code: `\n const obj = value ?? {};\n const parts = args.path.split('.');\n let current = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n current[parts[i]] = current[parts[i]] ?? {};\n current = current[parts[i]];\n }\n current[parts[parts.length - 1]] = args.value;\n return { value: obj, result: obj };\n `,\n args: { path, value: propValue },\n }),\n\n /**\n * Delete nested property using dot notation path.\n * Returns the deleted value or undefined.\n */\n DELETE_PROPERTY: <V>(path: string): EntryProcessorDef<V, unknown> => ({\n name: 'builtin:delete_property',\n code: `\n if (!value) {\n return { value, result: undefined };\n }\n const parts = args.split('.');\n let current = value;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) {\n return { value, result: undefined };\n }\n current = current[parts[i]];\n }\n const lastKey = parts[parts.length - 1];\n const deleted = current[lastKey];\n delete current[lastKey];\n return { value, result: deleted };\n `,\n args: path,\n }),\n\n /**\n * Get current value without modifying it.\n * Useful for conditional reads.\n */\n GET: <V>(): EntryProcessorDef<V, V | undefined> => ({\n name: 'builtin:get',\n code: `\n return { value, result: value };\n `,\n }),\n\n /**\n * Conditional update based on version/timestamp.\n * Only updates if current version matches expected.\n * Useful for optimistic locking.\n */\n CONDITIONAL_UPDATE: <V extends { version?: number }>(\n expectedVersion: number,\n newData: Partial<V>,\n ): EntryProcessorDef<V, { updated: boolean; conflict: boolean }> => ({\n name: 'builtin:conditional_update',\n code: `\n if (!value || value.version !== args.expectedVersion) {\n return {\n value,\n result: { updated: false, conflict: true }\n };\n }\n const updated = {\n ...value,\n ...args.newData,\n version: (value.version ?? 0) + 1,\n };\n return {\n value: updated,\n result: { updated: true, conflict: false }\n };\n `,\n args: { expectedVersion, newData },\n }),\n\n /**\n * Merge object properties into existing value.\n * Shallow merge only.\n */\n MERGE: <V extends Record<string, unknown>>(\n properties: Partial<V>,\n ): EntryProcessorDef<V, V> => ({\n name: 'builtin:merge',\n code: `\n const merged = { ...(value ?? {}), ...args };\n return { value: merged, result: merged };\n `,\n args: properties,\n }),\n};\n\n// --- Rate Limiting Configuration ---\n\n/**\n * Rate limiting configuration for processor execution.\n */\nexport interface ProcessorRateLimitConfig {\n /** Max processor executions per second per client */\n maxExecutionsPerSecond: number;\n\n /** Max processor code size in bytes */\n maxCodeSizeBytes: number;\n\n /** Max args size in bytes (JSON stringified) */\n maxArgsSizeBytes: number;\n}\n\n/**\n * Default rate limit configuration.\n */\nexport const DEFAULT_PROCESSOR_RATE_LIMITS: ProcessorRateLimitConfig = {\n maxExecutionsPerSecond: 100,\n maxCodeSizeBytes: 10240, // 10KB\n maxArgsSizeBytes: 1048576, // 1MB\n};\n","import { z } from 'zod';\nimport { Timestamp, HLC } from './HLC';\n\n// --- Merge Context ---\n\n/**\n * Context provided to a conflict resolver during merge operations.\n */\nexport interface MergeContext<V = unknown> {\n /** Map name being modified */\n mapName: string;\n\n /** Entry key being modified */\n key: string;\n\n /** Current server/local value (undefined if key doesn't exist) */\n localValue: V | undefined;\n\n /** Incoming client/remote value */\n remoteValue: V;\n\n /** Local HLC timestamp (undefined if key doesn't exist) */\n localTimestamp?: Timestamp;\n\n /** Remote HLC timestamp */\n remoteTimestamp: Timestamp;\n\n /** Client/node ID that sent the update */\n remoteNodeId: string;\n\n /** Authentication context (optional) */\n auth?: {\n userId?: string;\n roles?: string[];\n metadata?: Record<string, unknown>;\n };\n\n /** Read other entries for cross-key validation */\n readEntry: (key: string) => V | undefined;\n}\n\n// --- Merge Result ---\n\n/**\n * Result of conflict resolution.\n */\nexport type MergeResult<V = unknown> =\n | { action: 'accept'; value: V } // Accept remote value\n | { action: 'reject'; reason: string } // Reject with error\n | { action: 'merge'; value: V } // Custom merged value\n | { action: 'local' }; // Keep local value\n\n// --- Conflict Resolver Function ---\n\n/**\n * Conflict resolver function signature.\n */\nexport type ConflictResolverFn<V = unknown> = (\n context: MergeContext<V>,\n) => MergeResult<V> | Promise<MergeResult<V>>;\n\n// --- Conflict Resolver Definition ---\n\n/**\n * Conflict resolver definition (can be native function or sandboxed code).\n */\nexport interface ConflictResolverDef<V = unknown> {\n /** Unique resolver name */\n name: string;\n\n /** JavaScript function body as string (for sandboxed execution) */\n code?: string;\n\n /** Native function (for trusted server-side resolvers) */\n fn?: ConflictResolverFn<V>;\n\n /** Priority (higher = runs first, default 50) */\n priority?: number;\n\n /** Apply only to specific keys (glob pattern) */\n keyPattern?: string;\n}\n\n// --- Zod Schema for Wire Format ---\n\n/**\n * Zod schema for validating conflict resolver definitions from network.\n */\nexport const ConflictResolverDefSchema = z.object({\n name: z.string().min(1).max(100),\n code: z.string().max(50000).optional(),\n priority: z.number().int().min(0).max(100).default(50),\n keyPattern: z.string().optional(),\n});\n\n// --- Security: Forbidden Patterns ---\n\n/**\n * Patterns that are denied in resolver code for security reasons.\n * Same patterns as EntryProcessor for consistency.\n */\nexport const RESOLVER_FORBIDDEN_PATTERNS = [\n /\\beval\\b/,\n /\\bFunction\\b/,\n /\\bprocess\\b/,\n /\\bglobal\\b/,\n /\\brequire\\b/,\n /\\bimport\\b/,\n /\\bfetch\\b/,\n /\\bXMLHttpRequest\\b/,\n /\\bsetTimeout\\b/,\n /\\bsetInterval\\b/,\n /\\bsetImmediate\\b/,\n];\n\n/**\n * Validates resolver code against forbidden patterns.\n */\nexport function validateResolverCode(code: string): {\n valid: boolean;\n error?: string;\n} {\n for (const pattern of RESOLVER_FORBIDDEN_PATTERNS) {\n if (pattern.test(code)) {\n return {\n valid: false,\n error: `Forbidden pattern detected: ${pattern.source}`,\n };\n }\n }\n return { valid: true };\n}\n\n// --- Rate Limiting Configuration ---\n\n/**\n * Rate limiting configuration for resolver registration.\n */\nexport interface ResolverRateLimitConfig {\n /** Max resolver registrations per client */\n maxResolversPerClient: number;\n\n /** Max resolver code size in bytes */\n maxCodeSizeBytes: number;\n}\n\n/**\n * Default rate limit configuration.\n */\nexport const DEFAULT_RESOLVER_RATE_LIMITS: ResolverRateLimitConfig = {\n maxResolversPerClient: 50,\n maxCodeSizeBytes: 50000, // 50KB\n};\n\n// --- Helper Functions ---\n\n/**\n * Compares two HLC timestamps.\n * Returns negative if a < b, positive if a > b, 0 if equal.\n */\nexport function compareHLCTimestamps(a: Timestamp, b: Timestamp): number {\n return HLC.compare(a, b);\n}\n\n/**\n * Deep merges two objects.\n * Remote values take precedence at each level.\n */\nexport function deepMerge<T extends object>(target: T, source: T): T {\n const result = { ...target };\n\n for (const key of Object.keys(source) as (keyof T)[]) {\n const sourceVal = source[key];\n const targetVal = target[key];\n\n if (\n typeof sourceVal === 'object' &&\n sourceVal !== null &&\n typeof targetVal === 'object' &&\n targetVal !== null &&\n !Array.isArray(sourceVal)\n ) {\n (result as Record<string, unknown>)[key as string] = deepMerge(\n targetVal as object,\n sourceVal as object,\n );\n } else {\n (result as Record<string, unknown>)[key as string] = sourceVal;\n }\n }\n\n return result;\n}\n\n// --- Built-in Resolvers ---\n\n/**\n * Built-in conflict resolvers for common patterns.\n * These are type-safe and pre-validated.\n */\nexport const BuiltInResolvers = {\n /**\n * Standard Last-Write-Wins - accept if remote timestamp is newer.\n */\n LWW: <V>(): ConflictResolverDef<V> => ({\n name: 'builtin:lww',\n fn: (ctx) => {\n if (!ctx.localTimestamp) {\n return { action: 'accept', value: ctx.remoteValue };\n }\n\n const cmp = compareHLCTimestamps(ctx.remoteTimestamp, ctx.localTimestamp);\n if (cmp > 0) {\n return { action: 'accept', value: ctx.remoteValue };\n }\n return { action: 'local' };\n },\n priority: 0, // Lowest priority - fallback\n }),\n\n /**\n * First-Write-Wins - reject if local value exists.\n * Useful for booking systems, unique constraints.\n */\n FIRST_WRITE_WINS: <V>(): ConflictResolverDef<V> => ({\n name: 'builtin:first_write_wins',\n fn: (ctx) => {\n if (ctx.localValue !== undefined) {\n return { action: 'reject', reason: 'Entry already exists' };\n }\n return { action: 'accept', value: ctx.remoteValue };\n },\n priority: 100,\n }),\n\n /**\n * Numeric minimum - keep lowest value.\n * Useful for auction systems (lowest bid wins).\n */\n NUMERIC_MIN: (): ConflictResolverDef<number> => ({\n name: 'builtin:numeric_min',\n fn: (ctx) => {\n const local = ctx.localValue ?? Infinity;\n const remote = ctx.remoteValue;\n return { action: 'merge', value: Math.min(local, remote) };\n },\n priority: 50,\n }),\n\n /**\n * Numeric maximum - keep highest value.\n * Useful for high score tracking.\n */\n NUMERIC_MAX: (): ConflictResolverDef<number> => ({\n name: 'builtin:numeric_max',\n fn: (ctx) => {\n const local = ctx.localValue ?? -Infinity;\n const remote = ctx.remoteValue;\n return { action: 'merge', value: Math.max(local, remote) };\n },\n priority: 50,\n }),\n\n /**\n * Non-negative - reject if value would be negative.\n * Useful for inventory systems.\n */\n NON_NEGATIVE: (): ConflictResolverDef<number> => ({\n name: 'builtin:non_negative',\n fn: (ctx) => {\n if (typeof ctx.remoteValue !== 'number' || ctx.remoteValue < 0) {\n return { action: 'reject', reason: 'Value cannot be negative' };\n }\n return { action: 'accept', value: ctx.remoteValue };\n },\n priority: 90,\n }),\n\n /**\n * Array union - merge arrays by taking union of elements.\n * Useful for tags, categories.\n */\n ARRAY_UNION: <T>(): ConflictResolverDef<T[]> => ({\n name: 'builtin:array_union',\n fn: (ctx) => {\n const local = ctx.localValue ?? [];\n const remote = ctx.remoteValue ?? [];\n const merged = [...new Set([...local, ...remote])];\n return { action: 'merge', value: merged };\n },\n priority: 50,\n }),\n\n /**\n * Deep merge - recursively merge objects.\n * Remote values take precedence at leaf level.\n */\n DEEP_MERGE: <V extends object>(): ConflictResolverDef<V> => ({\n name: 'builtin:deep_merge',\n fn: (ctx) => {\n const local = (ctx.localValue ?? {}) as V;\n const remote = ctx.remoteValue;\n const merged = deepMerge(local, remote);\n return { action: 'merge', value: merged };\n },\n priority: 50,\n }),\n\n /**\n * Server-only - reject all client writes.\n * Useful for server-controlled state.\n */\n SERVER_ONLY: <V>(): ConflictResolverDef<V> => ({\n name: 'builtin:server_only',\n fn: (ctx) => {\n // Server writes have a special node ID or auth role\n if (ctx.auth?.roles?.includes('server') || ctx.remoteNodeId.startsWith('server:')) {\n return { action: 'accept', value: ctx.remoteValue };\n }\n return { action: 'reject', reason: 'Only server can write to this entry' };\n },\n priority: 100,\n }),\n\n /**\n * Owner-only - only the original creator can modify.\n * Requires value to have an `ownerId` property.\n */\n OWNER_ONLY: <V extends { ownerId?: string }>(): ConflictResolverDef<V> => ({\n name: 'builtin:owner_only',\n fn: (ctx) => {\n // If no local value, accept (first write sets owner)\n if (!ctx.localValue) {\n return { action: 'accept', value: ctx.remoteValue };\n }\n\n // Check if remote is from owner\n const ownerId = ctx.localValue.ownerId;\n if (ownerId && ctx.auth?.userId !== ownerId) {\n return { action: 'reject', reason: 'Only owner can modify this entry' };\n }\n\n return { action: 'accept', value: ctx.remoteValue };\n },\n priority: 95,\n }),\n\n /**\n * Immutable - reject any modifications after initial write.\n */\n IMMUTABLE: <V>(): ConflictResolverDef<V> => ({\n name: 'builtin:immutable',\n fn: (ctx) => {\n if (ctx.localValue !== undefined) {\n return { action: 'reject', reason: 'Entry is immutable' };\n }\n return { action: 'accept', value: ctx.remoteValue };\n },\n priority: 100,\n }),\n\n /**\n * Version check - only accept if version increments by 1.\n * Useful for optimistic locking.\n */\n VERSION_INCREMENT: <V extends { version?: number }>(): ConflictResolverDef<V> => ({\n name: 'builtin:version_increment',\n fn: (ctx) => {\n const localVersion = ctx.localValue?.version ?? 0;\n const remoteVersion = ctx.remoteValue?.version ?? 0;\n\n if (remoteVersion !== localVersion + 1) {\n return {\n action: 'reject',\n reason: `Version conflict: expected ${localVersion + 1}, got ${remoteVersion}`,\n };\n }\n return { action: 'accept', value: ctx.remoteValue };\n },\n priority: 90,\n }),\n};\n\n// --- Merge Rejection Event ---\n\n/**\n * Event emitted when a merge is rejected.\n */\nexport interface MergeRejection {\n mapName: string;\n key: string;\n attemptedValue: unknown;\n reason: string;\n timestamp: Timestamp;\n nodeId: string;\n}\n","\nexport type PredicateOp =\n | 'eq' | 'neq'\n | 'gt' | 'gte'\n | 'lt' | 'lte'\n | 'like' | 'regex'\n | 'contains' | 'containsAll' | 'containsAny'\n | 'and' | 'or' | 'not'\n // Full-Text Search predicates (Phase 12)\n | 'match' | 'matchPhrase' | 'matchPrefix';\n\n/**\n * Options for full-text search match predicate.\n */\nexport interface MatchOptions {\n /** Minimum BM25 score threshold */\n minScore?: number;\n /** Boost factor for this field */\n boost?: number;\n /** Operator for multi-term queries: 'and' requires all terms, 'or' requires any */\n operator?: 'and' | 'or';\n /** Fuzziness level for typo tolerance (0 = exact, 1 = 1 edit, 2 = 2 edits) */\n fuzziness?: number;\n}\n\nexport interface PredicateNode {\n op: PredicateOp;\n attribute?: string;\n value?: any;\n children?: PredicateNode[];\n /** FTS-specific: search query string */\n query?: string;\n /** FTS-specific: match options */\n matchOptions?: MatchOptions;\n /** FTS-specific: phrase slop (word distance tolerance) */\n slop?: number;\n /** FTS-specific: prefix for matchPrefix */\n prefix?: string;\n /** FTS-specific: max prefix expansions */\n maxExpansions?: number;\n}\n\nexport class Predicates {\n static equal(attribute: string, value: any): PredicateNode { \n return { op: 'eq', attribute, value }; \n }\n \n static notEqual(attribute: string, value: any): PredicateNode { \n return { op: 'neq', attribute, value }; \n }\n \n static greaterThan(attribute: string, value: any): PredicateNode { \n return { op: 'gt', attribute, value }; \n }\n \n static greaterThanOrEqual(attribute: string, value: any): PredicateNode { \n return { op: 'gte', attribute, value }; \n }\n \n static lessThan(attribute: string, value: any): PredicateNode { \n return { op: 'lt', attribute, value }; \n }\n \n static lessThanOrEqual(attribute: string, value: any): PredicateNode { \n return { op: 'lte', attribute, value }; \n }\n \n static like(attribute: string, pattern: string): PredicateNode { \n return { op: 'like', attribute, value: pattern }; \n }\n \n static regex(attribute: string, pattern: string): PredicateNode { \n return { op: 'regex', attribute, value: pattern }; \n }\n\n static between(attribute: string, from: any, to: any): PredicateNode {\n return {\n op: 'and',\n children: [\n { op: 'gte', attribute, value: from },\n { op: 'lte', attribute, value: to }\n ]\n };\n }\n\n static and(...predicates: PredicateNode[]): PredicateNode { \n return { op: 'and', children: predicates }; \n }\n \n static or(...predicates: PredicateNode[]): PredicateNode { \n return { op: 'or', children: predicates }; \n }\n \n static not(predicate: PredicateNode): PredicateNode {\n return { op: 'not', children: [predicate] };\n }\n\n /**\n * Create a 'contains' predicate for text search.\n * Matches if attribute value contains the search text.\n *\n * @param attribute - Attribute name\n * @param value - Text to search for\n */\n static contains(attribute: string, value: string): PredicateNode {\n return { op: 'contains', attribute, value };\n }\n\n /**\n * Create a 'containsAll' predicate for text search.\n * Matches if attribute value contains ALL search values.\n *\n * @param attribute - Attribute name\n * @param values - Text values that must all be present\n */\n static containsAll(attribute: string, values: string[]): PredicateNode {\n return { op: 'containsAll', attribute, value: values };\n }\n\n /**\n * Create a 'containsAny' predicate for text search.\n * Matches if attribute value contains ANY search value.\n *\n * @param attribute - Attribute name\n * @param values - Text values, any of which can match\n */\n static containsAny(attribute: string, values: string[]): PredicateNode {\n return { op: 'containsAny', attribute, value: values };\n }\n\n // ============== Full-Text Search Predicates (Phase 12) ==============\n\n /**\n * Create a 'match' predicate for full-text search.\n * Uses BM25 scoring to find relevant documents.\n *\n * @param attribute - Field to search in\n * @param query - Search query string\n * @param options - Match options (minScore, boost, operator, fuzziness)\n *\n * @example\n * ```typescript\n * // Simple match\n * Predicates.match('title', 'machine learning')\n *\n * // With options\n * Predicates.match('body', 'neural networks', { minScore: 1.0, boost: 2.0 })\n * ```\n */\n static match(attribute: string, query: string, options?: MatchOptions): PredicateNode {\n return { op: 'match', attribute, query, matchOptions: options };\n }\n\n /**\n * Create a 'matchPhrase' predicate for exact phrase matching.\n * Matches documents containing the exact phrase (words in order).\n *\n * @param attribute - Field to search in\n * @param query - Phrase to match\n * @param slop - Word distance tolerance (0 = exact, 1 = allow 1 word between)\n *\n * @example\n * ```typescript\n * // Exact phrase\n * Predicates.matchPhrase('body', 'machine learning')\n *\n * // With slop (allows \"machine deep learning\")\n * Predicates.matchPhrase('body', 'machine learning', 1)\n * ```\n */\n static matchPhrase(attribute: string, query: string, slop?: number): PredicateNode {\n return { op: 'matchPhrase', attribute, query, slop };\n }\n\n /**\n * Create a 'matchPrefix' predicate for prefix matching.\n * Matches documents where field starts with the given prefix.\n *\n * @param attribute - Field to search in\n * @param prefix - Prefix to match\n * @param maxExpansions - Maximum number of term expansions\n *\n * @example\n * ```typescript\n * // Match titles starting with \"mach\"\n * Predicates.matchPrefix('title', 'mach')\n *\n * // Limit expansions for performance\n * Predicates.matchPrefix('title', 'mach', 50)\n * ```\n */\n static matchPrefix(attribute: string, prefix: string, maxExpansions?: number): PredicateNode {\n return { op: 'matchPrefix', attribute, prefix, maxExpansions };\n }\n\n /**\n * Create a multi-field match predicate.\n * Searches across multiple fields with optional per-field boosting.\n *\n * @param attributes - Fields to search in\n * @param query - Search query string\n * @param options - Options including per-field boost factors\n *\n * @example\n * ```typescript\n * // Search title and body\n * Predicates.multiMatch(['title', 'body'], 'machine learning')\n *\n * // With boosting (title 2x more important)\n * Predicates.multiMatch(['title', 'body'], 'machine learning', {\n * boost: { title: 2.0, body: 1.0 }\n * })\n * ```\n */\n static multiMatch(\n attributes: string[],\n query: string,\n options?: { boost?: Record<string, number> }\n ): PredicateNode {\n const children = attributes.map((attr) => ({\n op: 'match' as const,\n attribute: attr,\n query,\n matchOptions: options?.boost?.[attr] ? { boost: options.boost[attr] } : undefined,\n }));\n return { op: 'or', children };\n }\n}\n\nexport function evaluatePredicate(predicate: PredicateNode, data: any): boolean {\n if (!data) return false;\n \n switch (predicate.op) {\n case 'and':\n return (predicate.children || []).every(p => evaluatePredicate(p, data));\n case 'or':\n return (predicate.children || []).some(p => evaluatePredicate(p, data));\n case 'not': {\n const child = (predicate.children || [])[0];\n if (!child) return true; // NOT of nothing is true (vacuous)\n return !evaluatePredicate(child, data);\n }\n }\n\n // Leaf nodes require an attribute\n if (!predicate.attribute) return false;\n \n const value = data[predicate.attribute];\n const target = predicate.value;\n\n switch (predicate.op) {\n case 'eq':\n return value === target;\n case 'neq':\n return value !== target;\n case 'gt':\n return value > target;\n case 'gte':\n return value >= target;\n case 'lt':\n return value < target;\n case 'lte':\n return value <= target;\n case 'like':\n if (typeof value !== 'string' || typeof target !== 'string') return false;\n const pattern = target\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n .replace(/%/g, '.*')\n .replace(/_/g, '.');\n return new RegExp(`^${pattern}$`, 'i').test(value);\n case 'regex':\n if (typeof value !== 'string' || typeof target !== 'string') return false;\n return new RegExp(target).test(value);\n case 'contains':\n if (typeof value !== 'string' || typeof target !== 'string') return false;\n return value.toLowerCase().includes(target.toLowerCase());\n case 'containsAll':\n if (typeof value !== 'string' || !Array.isArray(target)) return false;\n return target.every(\n (t) => typeof t === 'string' && value.toLowerCase().includes(t.toLowerCase())\n );\n case 'containsAny':\n if (typeof value !== 'string' || !Array.isArray(target)) return false;\n return target.some(\n (t) => typeof t === 'string' && value.toLowerCase().includes(t.toLowerCase())\n );\n default:\n return false;\n }\n}\n","import { z } from 'zod';\n\n// --- Write Concern Types ---\n\n/**\n * Write Concern schema - defines when an operation is considered acknowledged.\n */\nexport const WriteConcernSchema = z.enum([\n 'FIRE_AND_FORGET',\n 'MEMORY',\n 'APPLIED',\n 'REPLICATED',\n 'PERSISTED',\n]);\n\nexport type WriteConcernValue = z.infer<typeof WriteConcernSchema>;\n\n// --- Basic Types ---\n\nexport const TimestampSchema = z.object({\n millis: z.union([z.number(), z.bigint()]).transform(Number),\n counter: z.union([z.number(), z.bigint()]).transform(Number),\n nodeId: z.string(),\n});\n\nexport const LWWRecordSchema = z.object({\n value: z.any().nullable(),\n timestamp: TimestampSchema,\n ttlMs: z.number().optional(),\n});\n\nexport const ORMapRecordSchema = z.object({\n value: z.any(),\n timestamp: TimestampSchema,\n tag: z.string(),\n ttlMs: z.number().optional(),\n});\n\n// --- Predicate Types ---\n\nexport const PredicateOpSchema = z.enum([\n 'eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'like', 'regex', 'and', 'or', 'not'\n]);\n\n// Recursive schema for PredicateNode\nexport const PredicateNodeSchema: z.ZodType<any> = z.lazy(() => z.object({\n op: PredicateOpSchema,\n attribute: z.string().optional(),\n value: z.any().optional(),\n children: z.array(PredicateNodeSchema).optional(),\n}));\n\n// --- Query Types ---\n\nexport const QuerySchema = z.object({\n where: z.record(z.string(), z.any()).optional(),\n predicate: PredicateNodeSchema.optional(),\n sort: z.record(z.string(), z.enum(['asc', 'desc'])).optional(),\n limit: z.number().optional(),\n offset: z.number().optional(),\n});\n\n// --- Client Operation Types ---\n\nexport const ClientOpSchema = z.object({\n id: z.string().optional(),\n mapName: z.string(),\n key: z.string(),\n // Permissive opType to match ServerCoordinator behavior logic\n // It can be 'REMOVE', 'OR_ADD', 'OR_REMOVE' or undefined/other (implies PUT/LWW)\n opType: z.string().optional(),\n record: LWWRecordSchema.nullable().optional(),\n orRecord: ORMapRecordSchema.nullable().optional(),\n orTag: z.string().nullable().optional(),\n // Write Concern fields (Phase 5.01)\n writeConcern: WriteConcernSchema.optional(),\n timeout: z.number().optional(),\n});\n\n// --- Message Schemas ---\n\nexport const AuthMessageSchema = z.object({\n type: z.literal('AUTH'),\n token: z.string(),\n});\n\nexport const QuerySubMessageSchema = z.object({\n type: z.literal('QUERY_SUB'),\n payload: z.object({\n queryId: z.string(),\n mapName: z.string(),\n query: QuerySchema,\n }),\n});\n\nexport const QueryUnsubMessageSchema = z.object({\n type: z.literal('QUERY_UNSUB'),\n payload: z.object({\n queryId: z.string(),\n }),\n});\n\nexport const ClientOpMessageSchema = z.object({\n type: z.literal('CLIENT_OP'),\n payload: ClientOpSchema,\n});\n\nexport const OpBatchMessageSchema = z.object({\n type: z.literal('OP_BATCH'),\n payload: z.object({\n ops: z.array(ClientOpSchema),\n // Batch-level Write Concern (can be overridden per-op)\n writeConcern: WriteConcernSchema.optional(),\n timeout: z.number().optional(),\n }),\n});\n\nexport const SyncInitMessageSchema = z.object({\n type: z.literal('SYNC_INIT'),\n mapName: z.string(),\n lastSyncTimestamp: z.number().optional(),\n});\n\nexport const SyncRespRootMessageSchema = z.object({\n type: z.literal('SYNC_RESP_ROOT'),\n payload: z.object({\n mapName: z.string(),\n rootHash: z.number(),\n timestamp: TimestampSchema,\n }),\n});\n\nexport const SyncRespBucketsMessageSchema = z.object({\n type: z.literal('SYNC_RESP_BUCKETS'),\n payload: z.object({\n mapName: z.string(),\n path: z.string(),\n buckets: z.record(z.string(), z.number()),\n }),\n});\n\nexport const SyncRespLeafMessageSchema = z.object({\n type: z.literal('SYNC_RESP_LEAF'),\n payload: z.object({\n mapName: z.string(),\n path: z.string(),\n records: z.array(z.object({\n key: z.string(),\n record: LWWRecordSchema,\n })),\n }),\n});\n\nexport const MerkleReqBucketMessageSchema = z.object({\n type: z.literal('MERKLE_REQ_BUCKET'),\n payload: z.object({\n mapName: z.string(),\n path: z.string(),\n }),\n});\n\nexport const LockRequestSchema = z.object({\n type: z.literal('LOCK_REQUEST'),\n payload: z.object({\n requestId: z.string(),\n name: z.string(),\n ttl: z.number().optional(),\n }),\n});\n\nexport const LockReleaseSchema = z.object({\n type: z.literal('LOCK_RELEASE'),\n payload: z.object({\n requestId: z.string().optional(),\n name: z.string(),\n fencingToken: z.number(),\n }),\n});\n\n// --- Topic Messages ---\n\nexport const TopicSubSchema = z.object({\n type: z.literal('TOPIC_SUB'),\n payload: z.object({\n topic: z.string(),\n }),\n});\n\nexport const TopicUnsubSchema = z.object({\n type: z.literal('TOPIC_UNSUB'),\n payload: z.object({\n topic: z.string(),\n }),\n});\n\nexport const TopicPubSchema = z.object({\n type: z.literal('TOPIC_PUB'),\n payload: z.object({\n topic: z.string(),\n data: z.any(),\n }),\n});\n\nexport const TopicMessageEventSchema = z.object({\n type: z.literal('TOPIC_MESSAGE'),\n payload: z.object({\n topic: z.string(),\n data: z.any(),\n publisherId: z.string().optional(),\n timestamp: z.number(),\n }),\n});\n\n// --- PN Counter Messages (Phase 5.2) ---\n\nexport const PNCounterStateObjectSchema = z.object({\n p: z.record(z.string(), z.number()), // positive counts per node\n n: z.record(z.string(), z.number()), // negative counts per node\n});\n\nexport const CounterRequestSchema = z.object({\n type: z.literal('COUNTER_REQUEST'),\n payload: z.object({\n name: z.string(),\n }),\n});\n\nexport const CounterSyncSchema = z.object({\n type: z.literal('COUNTER_SYNC'),\n payload: z.object({\n name: z.string(),\n state: PNCounterStateObjectSchema,\n }),\n});\n\nexport const CounterResponseSchema = z.object({\n type: z.literal('COUNTER_RESPONSE'),\n payload: z.object({\n name: z.string(),\n state: PNCounterStateObjectSchema,\n }),\n});\n\nexport const CounterUpdateSchema = z.object({\n type: z.literal('COUNTER_UPDATE'),\n payload: z.object({\n name: z.string(),\n state: PNCounterStateObjectSchema,\n }),\n});\n\n// --- Heartbeat Messages ---\n\nexport const PingMessageSchema = z.object({\n type: z.literal('PING'),\n timestamp: z.number(), // Client's Date.now()\n});\n\nexport const PongMessageSchema = z.object({\n type: z.literal('PONG'),\n timestamp: z.number(), // Echo back client's timestamp\n serverTime: z.number(), // Server's Date.now() (for clock skew detection)\n});\n\n// --- Batched Messages ---\n\n/**\n * BATCH: Server sends multiple messages batched together.\n * Uses length-prefixed binary format for efficiency.\n * Format: [4 bytes: count][4 bytes: len1][msg1][4 bytes: len2][msg2]...\n */\nexport const BatchMessageSchema = z.object({\n type: z.literal('BATCH'),\n count: z.number(),\n data: z.instanceof(Uint8Array),\n});\n\n// --- ORMap Sync Messages ---\n\n/**\n * ORMAP_SYNC_INIT: Client initiates ORMap sync\n * Sends root hash and bucket hashes to server\n */\nexport const ORMapSyncInitSchema = z.object({\n type: z.literal('ORMAP_SYNC_INIT'),\n mapName: z.string(),\n rootHash: z.number(),\n bucketHashes: z.record(z.string(), z.number()), // path -> hash\n lastSyncTimestamp: z.number().optional(),\n});\n\n/**\n * ORMAP_SYNC_RESP_ROOT: Server responds with its root hash\n */\nexport const ORMapSyncRespRootSchema = z.object({\n type: z.literal('ORMAP_SYNC_RESP_ROOT'),\n payload: z.object({\n mapName: z.string(),\n rootHash: z.number(),\n timestamp: TimestampSchema,\n }),\n});\n\n/**\n * ORMAP_SYNC_RESP_BUCKETS: Server sends bucket hashes for comparison\n */\nexport const ORMapSyncRespBucketsSchema = z.object({\n type: z.literal('ORMAP_SYNC_RESP_BUCKETS'),\n payload: z.object({\n mapName: z.string(),\n path: z.string(),\n buckets: z.record(z.string(), z.number()),\n }),\n});\n\n/**\n * ORMAP_MERKLE_REQ_BUCKET: Client requests bucket details\n */\nexport const ORMapMerkleReqBucketSchema = z.object({\n type: z.literal('ORMAP_MERKLE_REQ_BUCKET'),\n payload: z.object({\n mapName: z.string(),\n path: z.string(),\n }),\n});\n\n/**\n * ORMAP_SYNC_RESP_LEAF: Server sends actual records for differing keys\n */\nexport const ORMapSyncRespLeafSchema = z.object({\n type: z.literal('ORMAP_SYNC_RESP_LEAF'),\n payload: z.object({\n mapName: z.string(),\n path: z.string(),\n entries: z.array(z.object({\n key: z.string(),\n records: z.array(ORMapRecordSchema),\n tombstones: z.array(z.string()), // Tombstone tags for this key's records\n })),\n }),\n});\n\n/**\n * ORMAP_DIFF_REQUEST: Client requests data for specific keys\n */\nexport const ORMapDiffRequestSchema = z.object({\n type: z.literal('ORMAP_DIFF_REQUEST'),\n payload: z.object({\n mapName: z.string(),\n keys: z.array(z.string()),\n }),\n});\n\n/**\n * ORMAP_DIFF_RESPONSE: Server responds with data for requested keys\n */\nexport const ORMapDiffResponseSchema = z.object({\n type: z.literal('ORMAP_DIFF_RESPONSE'),\n payload: z.object({\n mapName: z.string(),\n entries: z.array(z.object({\n key: z.string(),\n records: z.array(ORMapRecordSchema),\n tombstones: z.array(z.string()),\n })),\n }),\n});\n\n/**\n * ORMAP_PUSH_DIFF: Client pushes local diffs to server\n */\nexport const ORMapPushDiffSchema = z.object({\n type: z.literal('ORMAP_PUSH_DIFF'),\n payload: z.object({\n mapName: z.string(),\n entries: z.array(z.object({\n key: z.string(),\n records: z.array(ORMapRecordSchema),\n tombstones: z.array(z.string()),\n })),\n }),\n});\n\n// --- Phase 4: Partition Map Schemas ---\n\n/**\n * PARTITION_MAP_REQUEST: Client requests current partition map\n */\nexport const PartitionMapRequestSchema = z.object({\n type: z.literal('PARTITION_MAP_REQUEST'),\n payload: z.object({\n currentVersion: z.number().optional(),\n }).optional(),\n});\n\n// --- Entry Processor Messages (Phase 5.03) ---\n\n/**\n * Entry processor definition schema.\n */\nexport const EntryProcessorSchema = z.object({\n name: z.string().min(1).max(100),\n code: z.string().min(1).max(10000),\n args: z.unknown().optional(),\n});\n\n/**\n * ENTRY_PROCESS: Client requests atomic operation on single key.\n */\nexport const EntryProcessRequestSchema = z.object({\n type: z.literal('ENTRY_PROCESS'),\n requestId: z.string(),\n mapName: z.string(),\n key: z.string(),\n processor: EntryProcessorSchema,\n});\n\n/**\n * ENTRY_PROCESS_BATCH: Client requests atomic operation on multiple keys.\n */\nexport const EntryProcessBatchRequestSchema = z.object({\n type: z.literal('ENTRY_PROCESS_BATCH'),\n requestId: z.string(),\n mapName: z.string(),\n keys: z.array(z.string()),\n processor: EntryProcessorSchema,\n});\n\n/**\n * ENTRY_PROCESS_RESPONSE: Server responds to single-key processor request.\n */\nexport const EntryProcessResponseSchema = z.object({\n type: z.literal('ENTRY_PROCESS_RESPONSE'),\n requestId: z.string(),\n success: z.boolean(),\n result: z.unknown().optional(),\n newValue: z.unknown().optional(),\n error: z.string().optional(),\n});\n\n/**\n * Individual key result in batch response.\n */\nexport const EntryProcessKeyResultSchema = z.object({\n success: z.boolean(),\n result: z.unknown().optional(),\n newValue: z.unknown().optional(),\n error: z.string().optional(),\n});\n\n/**\n * ENTRY_PROCESS_BATCH_RESPONSE: Server responds to multi-key processor request.\n */\nexport const EntryProcessBatchResponseSchema = z.object({\n type: z.literal('ENTRY_PROCESS_BATCH_RESPONSE'),\n requestId: z.string(),\n results: z.record(z.string(), EntryProcessKeyResultSchema),\n});\n\n// --- Event Journal Messages (Phase 5.04) ---\n\n/**\n * Journal event type schema.\n */\nexport const JournalEventTypeSchema = z.enum(['PUT', 'UPDATE', 'DELETE']);\n\n/**\n * Journal event data (serialized for network).\n */\nexport const JournalEventDataSchema = z.object({\n sequence: z.string(), // bigint as string\n type: JournalEventTypeSchema,\n mapName: z.string(),\n key: z.string(),\n value: z.unknown().optional(),\n previousValue: z.unknown().optional(),\n timestamp: TimestampSchema,\n nodeId: z.string(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * JOURNAL_SUBSCRIBE: Client subscribes to journal events.\n */\nexport const JournalSubscribeRequestSchema = z.object({\n type: z.literal('JOURNAL_SUBSCRIBE'),\n requestId: z.string(),\n fromSequence: z.string().optional(), // bigint as string\n mapName: z.string().optional(),\n types: z.array(JournalEventTypeSchema).optional(),\n});\n\n/**\n * JOURNAL_UNSUBSCRIBE: Client unsubscribes from journal events.\n */\nexport const JournalUnsubscribeRequestSchema = z.object({\n type: z.literal('JOURNAL_UNSUBSCRIBE'),\n subscriptionId: z.string(),\n});\n\n/**\n * JOURNAL_EVENT: Server sends journal event to client.\n */\nexport const JournalEventMessageSchema = z.object({\n type: z.literal('JOURNAL_EVENT'),\n event: JournalEventDataSchema,\n});\n\n/**\n * JOURNAL_READ: Client requests events from journal.\n */\nexport const JournalReadRequestSchema = z.object({\n type: z.literal('JOURNAL_READ'),\n requestId: z.string(),\n fromSequence: z.string(),\n limit: z.number().optional(),\n mapName: z.string().optional(),\n});\n\n/**\n * JOURNAL_READ_RESPONSE: Server responds with journal events.\n */\nexport const JournalReadResponseSchema = z.object({\n type: z.literal('JOURNAL_READ_RESPONSE'),\n requestId: z.string(),\n events: z.array(JournalEventDataSchema),\n hasMore: z.boolean(),\n});\n\n// --- Full-Text Search Messages (Phase 11.1) ---\n\n/**\n * Search options schema for FTS queries.\n */\nexport const SearchOptionsSchema = z.object({\n limit: z.number().optional(),\n minScore: z.number().optional(),\n boost: z.record(z.string(), z.number()).optional(),\n});\n\n/**\n * SEARCH: Client requests one-shot BM25 search.\n */\nexport const SearchPayloadSchema = z.object({\n requestId: z.string(),\n mapName: z.string(),\n query: z.string(),\n options: SearchOptionsSchema.optional(),\n});\n\nexport const SearchMessageSchema = z.object({\n type: z.literal('SEARCH'),\n payload: SearchPayloadSchema,\n});\n\n/**\n * SEARCH_RESP: Server responds with search results.\n */\nexport const SearchRespPayloadSchema = z.object({\n requestId: z.string(),\n results: z.array(z.object({\n key: z.string(),\n value: z.unknown(),\n score: z.number(),\n matchedTerms: z.array(z.string()),\n })),\n totalCount: z.number(),\n error: z.string().optional(),\n});\n\nexport const SearchRespMessageSchema = z.object({\n type: z.literal('SEARCH_RESP'),\n payload: SearchRespPayloadSchema,\n});\n\n// --- Live Search Subscription Messages (Phase 11.1b) ---\n\n/**\n * Search delta update type.\n * - ENTER: Document entered the result set (new or score exceeded minScore)\n * - UPDATE: Document score changed while remaining in result set\n * - LEAVE: Document left the result set (removed or score dropped below minScore)\n */\nexport const SearchUpdateTypeSchema = z.enum(['ENTER', 'UPDATE', 'LEAVE']);\n\n/**\n * SEARCH_SUB: Client subscribes to live search results.\n */\nexport const SearchSubPayloadSchema = z.object({\n subscriptionId: z.string(),\n mapName: z.string(),\n query: z.string(),\n options: SearchOptionsSchema.optional(),\n});\n\nexport const SearchSubMessageSchema = z.object({\n type: z.literal('SEARCH_SUB'),\n payload: SearchSubPayloadSchema,\n});\n\n/**\n * SEARCH_UPDATE: Server sends delta update for a subscribed search.\n */\nexport const SearchUpdatePayloadSchema = z.object({\n subscriptionId: z.string(),\n key: z.string(),\n value: z.unknown(),\n score: z.number(),\n matchedTerms: z.array(z.string()),\n type: SearchUpdateTypeSchema,\n});\n\nexport const SearchUpdateMessageSchema = z.object({\n type: z.literal('SEARCH_UPDATE'),\n payload: SearchUpdatePayloadSchema,\n});\n\n/**\n * SEARCH_UNSUB: Client unsubscribes from live search.\n */\nexport const SearchUnsubPayloadSchema = z.object({\n subscriptionId: z.string(),\n});\n\nexport const SearchUnsubMessageSchema = z.object({\n type: z.literal('SEARCH_UNSUB'),\n payload: SearchUnsubPayloadSchema,\n});\n\n// --- Conflict Resolver Messages (Phase 5.05) ---\n\n/**\n * Conflict resolver definition schema (wire format).\n */\nexport const ConflictResolverSchema = z.object({\n name: z.string().min(1).max(100),\n code: z.string().max(50000),\n priority: z.number().int().min(0).max(100).optional(),\n keyPattern: z.string().optional(),\n});\n\n/**\n * REGISTER_RESOLVER: Client registers a conflict resolver on server.\n */\nexport const RegisterResolverRequestSchema = z.object({\n type: z.literal('REGISTER_RESOLVER'),\n requestId: z.string(),\n mapName: z.string(),\n resolver: ConflictResolverSchema,\n});\n\n/**\n * REGISTER_RESOLVER_RESPONSE: Server acknowledges resolver registration.\n */\nexport const RegisterResolverResponseSchema = z.object({\n type: z.literal('REGISTER_RESOLVER_RESPONSE'),\n requestId: z.string(),\n success: z.boolean(),\n error: z.string().optional(),\n});\n\n/**\n * UNREGISTER_RESOLVER: Client unregisters a conflict resolver.\n */\nexport const UnregisterResolverRequestSchema = z.object({\n type: z.literal('UNREGISTER_RESOLVER'),\n requestId: z.string(),\n mapName: z.string(),\n resolverName: z.string(),\n});\n\n/**\n * UNREGISTER_RESOLVER_RESPONSE: Server acknowledges resolver unregistration.\n */\nexport const UnregisterResolverResponseSchema = z.object({\n type: z.literal('UNREGISTER_RESOLVER_RESPONSE'),\n requestId: z.string(),\n success: z.boolean(),\n error: z.string().optional(),\n});\n\n/**\n * MERGE_REJECTED: Server notifies client that a merge was rejected.\n */\nexport const MergeRejectedMessageSchema = z.object({\n type: z.literal('MERGE_REJECTED'),\n mapName: z.string(),\n key: z.string(),\n attemptedValue: z.unknown(),\n reason: z.string(),\n timestamp: TimestampSchema,\n});\n\n/**\n * LIST_RESOLVERS: Client requests list of registered resolvers.\n */\nexport const ListResolversRequestSchema = z.object({\n type: z.literal('LIST_RESOLVERS'),\n requestId: z.string(),\n mapName: z.string().optional(),\n});\n\n/**\n * LIST_RESOLVERS_RESPONSE: Server responds with registered resolvers.\n */\nexport const ListResolversResponseSchema = z.object({\n type: z.literal('LIST_RESOLVERS_RESPONSE'),\n requestId: z.string(),\n resolvers: z.array(z.object({\n mapName: z.string(),\n name: z.string(),\n priority: z.number().optional(),\n keyPattern: z.string().optional(),\n })),\n});\n\n// --- Write Concern Response Schemas (Phase 5.01) ---\n\n/**\n * Individual operation result within a batch ACK\n */\nexport const OpResultSchema = z.object({\n opId: z.string(),\n success: z.boolean(),\n achievedLevel: WriteConcernSchema,\n error: z.string().optional(),\n});\n\n/**\n * OP_ACK: Server acknowledges write operations\n * Extended to support Write Concern levels\n */\nexport const OpAckMessageSchema = z.object({\n type: z.literal('OP_ACK'),\n payload: z.object({\n /** ID of the last operation in the batch (for backwards compatibility) */\n lastId: z.string(),\n /** Write Concern level achieved (for simple ACKs) */\n achievedLevel: WriteConcernSchema.optional(),\n /** Per-operation results (for batch operations with mixed Write Concern) */\n results: z.array(OpResultSchema).optional(),\n }),\n});\n\n/**\n * OP_REJECTED: Server rejects a write operation\n */\nexport const OpRejectedMessageSchema = z.object({\n type: z.literal('OP_REJECTED'),\n payload: z.object({\n /** Operation ID that was rejected */\n opId: z.string(),\n /** Reason for rejection */\n reason: z.string(),\n /** Error code */\n code: z.number().optional(),\n }),\n});\n\n// --- Union Schema ---\n\nexport const MessageSchema = z.discriminatedUnion('type', [\n AuthMessageSchema,\n QuerySubMessageSchema,\n QueryUnsubMessageSchema,\n ClientOpMessageSchema,\n OpBatchMessageSchema,\n SyncInitMessageSchema,\n SyncRespRootMessageSchema,\n SyncRespBucketsMessageSchema,\n SyncRespLeafMessageSchema,\n MerkleReqBucketMessageSchema,\n LockRequestSchema,\n LockReleaseSchema,\n TopicSubSchema,\n TopicUnsubSchema,\n TopicPubSchema,\n PingMessageSchema,\n PongMessageSchema,\n // ORMap Sync Messages\n ORMapSyncInitSchema,\n ORMapSyncRespRootSchema,\n ORMapSyncRespBucketsSchema,\n ORMapMerkleReqBucketSchema,\n ORMapSyncRespLeafSchema,\n ORMapDiffRequestSchema,\n ORMapDiffResponseSchema,\n ORMapPushDiffSchema,\n // Phase 4: Partition Map\n PartitionMapRequestSchema,\n // Phase 5.2: PN Counter\n CounterRequestSchema,\n CounterSyncSchema,\n // Phase 5.03: Entry Processor\n EntryProcessRequestSchema,\n EntryProcessBatchRequestSchema,\n EntryProcessResponseSchema,\n EntryProcessBatchResponseSchema,\n // Phase 5.04: Event Journal\n JournalSubscribeRequestSchema,\n JournalUnsubscribeRequestSchema,\n JournalEventMessageSchema,\n JournalReadRequestSchema,\n JournalReadResponseSchema,\n // Phase 5.05: Conflict Resolver\n RegisterResolverRequestSchema,\n RegisterResolverResponseSchema,\n UnregisterResolverRequestSchema,\n UnregisterResolverResponseSchema,\n MergeRejectedMessageSchema,\n ListResolversRequestSchema,\n ListResolversResponseSchema,\n // Phase 11.1: Full-Text Search\n SearchMessageSchema,\n SearchRespMessageSchema,\n // Phase 11.1b: Live Search Subscriptions\n SearchSubMessageSchema,\n SearchUpdateMessageSchema,\n SearchUnsubMessageSchema,\n]);\n\n// --- Type Inference ---\n\nexport type Timestamp = z.infer<typeof TimestampSchema>;\nexport type LWWRecord<V = any> = z.infer<typeof LWWRecordSchema>; // Generic placeholder\nexport type ORMapRecord<V = any> = z.infer<typeof ORMapRecordSchema>; // Generic placeholder\n// export type PredicateNode = z.infer<typeof PredicateNodeSchema>; // Conflict with predicate.ts\nexport type Query = z.infer<typeof QuerySchema>;\nexport type ClientOp = z.infer<typeof ClientOpSchema>;\nexport type Message = z.infer<typeof MessageSchema>;\nexport type PingMessage = z.infer<typeof PingMessageSchema>;\nexport type PongMessage = z.infer<typeof PongMessageSchema>;\nexport type BatchMessage = z.infer<typeof BatchMessageSchema>;\n\n// Write Concern types (Phase 5.01)\nexport type OpAckMessage = z.infer<typeof OpAckMessageSchema>;\nexport type OpRejectedMessage = z.infer<typeof OpRejectedMessageSchema>;\nexport type OpResult = z.infer<typeof OpResultSchema>;\n\n// Entry Processor types (Phase 5.03)\nexport type EntryProcessRequest = z.infer<typeof EntryProcessRequestSchema>;\nexport type EntryProcessBatchRequest = z.infer<typeof EntryProcessBatchRequestSchema>;\nexport type EntryProcessResponse = z.infer<typeof EntryProcessResponseSchema>;\nexport type EntryProcessBatchResponse = z.infer<typeof EntryProcessBatchResponseSchema>;\nexport type EntryProcessKeyResult = z.infer<typeof EntryProcessKeyResultSchema>;\n\n// Event Journal types (Phase 5.04)\nexport type JournalEventType = z.infer<typeof JournalEventTypeSchema>;\nexport type JournalEventData = z.infer<typeof JournalEventDataSchema>;\nexport type JournalSubscribeRequest = z.infer<typeof JournalSubscribeRequestSchema>;\nexport type JournalUnsubscribeRequest = z.infer<typeof JournalUnsubscribeRequestSchema>;\nexport type JournalEventMessage = z.infer<typeof JournalEventMessageSchema>;\nexport type JournalReadRequest = z.infer<typeof JournalReadRequestSchema>;\nexport type JournalReadResponse = z.infer<typeof JournalReadResponseSchema>;\n\n// Conflict Resolver types (Phase 5.05)\nexport type ConflictResolver = z.infer<typeof ConflictResolverSchema>;\nexport type RegisterResolverRequest = z.infer<typeof RegisterResolverRequestSchema>;\nexport type RegisterResolverResponse = z.infer<typeof RegisterResolverResponseSchema>;\nexport type UnregisterResolverRequest = z.infer<typeof UnregisterResolverRequestSchema>;\nexport type UnregisterResolverResponse = z.infer<typeof UnregisterResolverResponseSchema>;\nexport type MergeRejectedMessage = z.infer<typeof MergeRejectedMessageSchema>;\nexport type ListResolversRequest = z.infer<typeof ListResolversRequestSchema>;\nexport type ListResolversResponse = z.infer<typeof ListResolversResponseSchema>;\n\n// Full-Text Search types (Phase 11.1)\nexport type SearchOptions = z.infer<typeof SearchOptionsSchema>;\nexport type SearchPayload = z.infer<typeof SearchPayloadSchema>;\nexport type SearchMessage = z.infer<typeof SearchMessageSchema>;\nexport type SearchRespPayload = z.infer<typeof SearchRespPayloadSchema>;\nexport type SearchRespMessage = z.infer<typeof SearchRespMessageSchema>;\n\n// Live Search Subscription types (Phase 11.1b)\nexport type SearchUpdateType = z.infer<typeof SearchUpdateTypeSchema>;\nexport type SearchSubPayload = z.infer<typeof SearchSubPayloadSchema>;\nexport type SearchSubMessage = z.infer<typeof SearchSubMessageSchema>;\nexport type SearchUpdatePayload = z.infer<typeof SearchUpdatePayloadSchema>;\nexport type SearchUpdateMessage = z.infer<typeof SearchUpdateMessageSchema>;\nexport type SearchUnsubPayload = z.infer<typeof SearchUnsubPayloadSchema>;\nexport type SearchUnsubMessage = z.infer<typeof SearchUnsubMessageSchema>;\n","/**\n * Write Concern - Configurable Acknowledgment Levels\n *\n * Write Concern defines when a write operation is considered successful.\n * Similar to MongoDB's writeConcern, Kafka's acks, and Cassandra's consistency levels.\n */\n\n/**\n * Write Concern levels - determines when an operation is acknowledged.\n *\n * Levels are ordered by durability guarantee (lowest to highest):\n * FIRE_AND_FORGET < MEMORY < APPLIED < REPLICATED < PERSISTED\n */\nexport enum WriteConcern {\n /**\n * FIRE_AND_FORGET (acks=0)\n * - ACK sent immediately after server receives the message\n * - Operation may be lost if server crashes before processing\n * - Maximum throughput, minimum latency\n * - Use case: metrics, logs, non-critical data\n */\n FIRE_AND_FORGET = 'FIRE_AND_FORGET',\n\n /**\n * MEMORY (acks=1, default) - current Early ACK behavior\n * - ACK sent after validation and queuing for processing\n * - Operation is in memory but not yet applied to CRDT\n * - Use case: most operations, real-time updates\n */\n MEMORY = 'MEMORY',\n\n /**\n * APPLIED\n * - ACK sent after operation is applied to CRDT in memory\n * - Data is readable on this node immediately after ACK\n * - Use case: operations requiring immediate consistency on the node\n */\n APPLIED = 'APPLIED',\n\n /**\n * REPLICATED\n * - ACK sent after operation is broadcast to cluster (CLUSTER_EVENT sent)\n * - Data survives primary node failure\n * - Use case: important data requiring cluster durability\n */\n REPLICATED = 'REPLICATED',\n\n /**\n * PERSISTED\n * - ACK sent after operation is written to storage on primary node\n * - Data survives node restart\n * - Use case: critical data (financial transactions, audit logs)\n */\n PERSISTED = 'PERSISTED',\n}\n\n/**\n * Default timeout for Write Concern acknowledgments (ms)\n */\nexport const DEFAULT_WRITE_CONCERN_TIMEOUT = 5000;\n\n/**\n * Write options for PUT/REMOVE operations\n */\nexport interface WriteOptions {\n /**\n * Write acknowledgment level.\n * @default WriteConcern.MEMORY\n */\n writeConcern?: WriteConcern;\n\n /**\n * Timeout for waiting for acknowledgment (ms).\n * Applies to APPLIED, REPLICATED, PERSISTED levels.\n * @default 5000\n */\n timeout?: number;\n}\n\n/**\n * Result of a write operation\n */\nexport interface WriteResult {\n /** Whether the operation achieved the requested Write Concern level */\n success: boolean;\n\n /** Operation ID */\n opId: string;\n\n /** The Write Concern level actually achieved */\n achievedLevel: WriteConcern;\n\n /** Time taken to achieve the level (ms) */\n latencyMs: number;\n\n /** Error message if success=false */\n error?: string;\n}\n\n/**\n * Internal structure for tracking pending write acknowledgments\n */\nexport interface PendingWrite {\n /** Operation ID */\n opId: string;\n\n /** Target Write Concern level */\n writeConcern: WriteConcern;\n\n /** Timestamp when operation was registered */\n timestamp: number;\n\n /** Timeout duration (ms) */\n timeout: number;\n\n /** Promise resolve callback */\n resolve: (result: WriteResult) => void;\n\n /** Promise reject callback */\n reject: (error: Error) => void;\n\n /** Timeout handle for cleanup */\n timeoutHandle?: ReturnType<typeof setTimeout>;\n\n /** Set of levels that have been achieved */\n achievedLevels: Set<WriteConcern>;\n}\n\n/**\n * Ordered list of Write Concern levels (lowest to highest)\n */\nexport const WRITE_CONCERN_ORDER: readonly WriteConcern[] = [\n WriteConcern.FIRE_AND_FORGET,\n WriteConcern.MEMORY,\n WriteConcern.APPLIED,\n WriteConcern.REPLICATED,\n WriteConcern.PERSISTED,\n] as const;\n\n/**\n * Check if a target Write Concern level is achieved based on achieved levels.\n *\n * @param achieved - Set of achieved Write Concern levels\n * @param target - Target Write Concern level to check\n * @returns true if target level (or higher) is achieved\n */\nexport function isWriteConcernAchieved(\n achieved: Set<WriteConcern>,\n target: WriteConcern\n): boolean {\n const targetIndex = WRITE_CONCERN_ORDER.indexOf(target);\n const achievedIndex = Math.max(\n ...Array.from(achieved).map((l) => WRITE_CONCERN_ORDER.indexOf(l))\n );\n return achievedIndex >= targetIndex;\n}\n\n/**\n * Get the highest achieved Write Concern level from a set of achieved levels.\n *\n * @param achieved - Set of achieved Write Concern levels\n * @returns The highest achieved level\n */\nexport function getHighestWriteConcernLevel(\n achieved: Set<WriteConcern>\n): WriteConcern {\n for (let i = WRITE_CONCERN_ORDER.length - 1; i >= 0; i--) {\n if (achieved.has(WRITE_CONCERN_ORDER[i])) {\n return WRITE_CONCERN_ORDER[i];\n }\n }\n return WriteConcern.FIRE_AND_FORGET;\n}\n","/**\n * Cluster types for Phase 4: Clustering Improvements\n *\n * These types are shared between client and server packages\n * for partition-aware routing and cluster communication.\n */\n\n// ============================================\n// Node and Cluster Status\n// ============================================\n\nexport type NodeStatus = 'ACTIVE' | 'JOINING' | 'LEAVING' | 'SUSPECTED' | 'FAILED';\n\nexport interface NodeInfo {\n nodeId: string;\n endpoints: {\n websocket: string; // ws://host:port or wss://host:port\n http?: string; // Optional REST endpoint\n };\n status: NodeStatus;\n}\n\n// ============================================\n// Partition Map\n// ============================================\n\nexport interface PartitionInfo {\n partitionId: number;\n ownerNodeId: string;\n backupNodeIds: string[];\n}\n\nexport interface PartitionMap {\n version: number; // Incremented on topology change\n partitionCount: number; // 271 by default\n nodes: NodeInfo[];\n partitions: PartitionInfo[];\n generatedAt: number; // Timestamp when map was generated\n}\n\n// ============================================\n// Partition Map Protocol Messages\n// ============================================\n\nexport interface PartitionMapMessage {\n type: 'PARTITION_MAP';\n payload: PartitionMap;\n}\n\nexport interface PartitionMapRequestMessage {\n type: 'PARTITION_MAP_REQUEST';\n payload?: {\n currentVersion?: number;\n };\n}\n\nexport interface PartitionChange {\n partitionId: number;\n previousOwner: string;\n newOwner: string;\n reason: 'REBALANCE' | 'FAILOVER' | 'JOIN' | 'LEAVE';\n}\n\nexport interface PartitionMapDeltaMessage {\n type: 'PARTITION_MAP_DELTA';\n payload: {\n version: number;\n previousVersion: number;\n changes: PartitionChange[];\n timestamp: number;\n };\n}\n\n// ============================================\n// Routing Errors\n// ============================================\n\nexport interface NotOwnerError {\n code: 'NOT_OWNER';\n message: string;\n hint: {\n partitionId: number;\n currentOwner: string;\n mapVersion: number;\n };\n}\n\nexport interface StaleMapError {\n code: 'STALE_MAP';\n message: string;\n hint: {\n clientVersion: number;\n serverVersion: number;\n };\n}\n\nexport type RoutingError = NotOwnerError | StaleMapError;\n\n// ============================================\n// Connection Pool Configuration\n// ============================================\n\nexport interface ConnectionPoolConfig {\n /** Maximum connections per node (default: 1) */\n maxConnectionsPerNode: number;\n /** Connection timeout in ms (default: 5000) */\n connectionTimeoutMs: number;\n /** Health check interval in ms (default: 10000) */\n healthCheckIntervalMs: number;\n /** Reconnect delay base in ms (default: 1000) */\n reconnectDelayMs: number;\n /** Maximum reconnect delay in ms (default: 30000) */\n maxReconnectDelayMs: number;\n /** Maximum reconnect attempts before marking unhealthy (default: 5) */\n maxReconnectAttempts: number;\n}\n\nexport const DEFAULT_CONNECTION_POOL_CONFIG: ConnectionPoolConfig = {\n maxConnectionsPerNode: 1,\n connectionTimeoutMs: 5000,\n healthCheckIntervalMs: 10000,\n reconnectDelayMs: 1000,\n maxReconnectDelayMs: 30000,\n maxReconnectAttempts: 5,\n};\n\n// ============================================\n// Partition Router Configuration\n// ============================================\n\nexport interface PartitionRouterConfig {\n /** Fallback mode when routing fails: 'forward' uses primary, 'error' throws */\n fallbackMode: 'forward' | 'error';\n /** How often to refresh stale partition map in ms (default: 30000) */\n mapRefreshIntervalMs: number;\n /** Max staleness before forcing refresh in ms (default: 60000) */\n maxMapStalenessMs: number;\n}\n\nexport const DEFAULT_PARTITION_ROUTER_CONFIG: PartitionRouterConfig = {\n fallbackMode: 'forward',\n mapRefreshIntervalMs: 30000,\n maxMapStalenessMs: 60000,\n};\n\n// ============================================\n// Cluster Client Configuration\n// ============================================\n\n/**\n * Circuit breaker configuration.\n */\nexport interface CircuitBreakerConfig {\n /** Number of failures before opening circuit (default: 5) */\n failureThreshold: number;\n /** Time in ms before attempting to close circuit (default: 30000) */\n resetTimeoutMs: number;\n}\n\nexport const DEFAULT_CIRCUIT_BREAKER_CONFIG: CircuitBreakerConfig = {\n failureThreshold: 5,\n resetTimeoutMs: 30000,\n};\n\nexport interface ClusterClientConfig {\n /** Enable cluster mode */\n enabled: boolean;\n /** Initial seed nodes to connect to */\n seedNodes: string[];\n /** Routing mode: 'direct' routes to owner, 'forward' uses server forwarding */\n routingMode: 'direct' | 'forward';\n /** Connection pool configuration */\n connectionPool?: Partial<ConnectionPoolConfig>;\n /** Partition router configuration */\n routing?: Partial<PartitionRouterConfig>;\n /** Circuit breaker configuration */\n circuitBreaker?: Partial<CircuitBreakerConfig>;\n}\n\n// ============================================\n// Node Health\n// ============================================\n\nexport type ConnectionState =\n | 'DISCONNECTED'\n | 'CONNECTING'\n | 'CONNECTED'\n | 'AUTHENTICATED'\n | 'RECONNECTING'\n | 'FAILED';\n\nexport interface NodeHealth {\n nodeId: string;\n state: ConnectionState;\n lastSeen: number;\n latencyMs: number;\n reconnectAttempts: number;\n}\n\n// ============================================\n// Cluster Events (for EventEmitter)\n// ============================================\n\nexport interface ClusterEvents {\n 'node:connected': { nodeId: string };\n 'node:disconnected': { nodeId: string; reason: string };\n 'node:healthy': { nodeId: string };\n 'node:unhealthy': { nodeId: string; reason: string };\n 'partitionMap:updated': { version: number; changesCount: number };\n 'partitionMap:stale': { currentVersion: number; lastRefresh: number };\n 'routing:miss': { key: string; expectedOwner: string; actualOwner: string };\n}\n\n// ============================================\n// Migration State Machine (Task 03)\n// ============================================\n\nexport enum PartitionState {\n STABLE = 'STABLE', // Normal operation\n MIGRATING = 'MIGRATING', // Data being transferred\n SYNC = 'SYNC', // Verifying consistency\n FAILED = 'FAILED', // Migration failed, needs retry\n}\n\nexport interface PartitionMigration {\n partitionId: number;\n state: PartitionState;\n sourceNode: string;\n targetNode: string;\n startTime: number;\n bytesTransferred: number;\n totalBytes: number;\n retryCount: number;\n}\n\nexport interface MigrationConfig {\n /** Partitions per batch (default: 10) */\n batchSize: number;\n /** Delay between batches in ms (default: 5000) */\n batchIntervalMs: number;\n /** Bytes per chunk (default: 64KB) */\n transferChunkSize: number;\n /** Retries per partition (default: 3) */\n maxRetries: number;\n /** Sync phase timeout in ms (default: 30000) */\n syncTimeoutMs: number;\n /** Concurrent transfers (default: 4) */\n parallelTransfers: number;\n}\n\nexport const DEFAULT_MIGRATION_CONFIG: MigrationConfig = {\n batchSize: 10,\n batchIntervalMs: 5000,\n transferChunkSize: 65536, // 64KB\n maxRetries: 3,\n syncTimeoutMs: 30000,\n parallelTransfers: 4,\n};\n\nexport interface MigrationStatus {\n inProgress: boolean;\n active: PartitionMigration[];\n queued: number;\n completed: number;\n failed: number;\n estimatedTimeRemainingMs: number;\n}\n\nexport interface MigrationMetrics {\n migrationsStarted: number;\n migrationsCompleted: number;\n migrationsFailed: number;\n chunksTransferred: number;\n bytesTransferred: number;\n activeMigrations: number;\n queuedMigrations: number;\n}\n\n// ============================================\n// Migration Protocol Messages (Task 03)\n// ============================================\n\nexport interface MigrationStartMessage {\n type: 'MIGRATION_START';\n payload: {\n partitionId: number;\n sourceNode: string;\n estimatedSize: number;\n };\n}\n\nexport interface MigrationChunkMessage {\n type: 'MIGRATION_CHUNK';\n payload: {\n partitionId: number;\n chunkIndex: number;\n totalChunks: number;\n data: Uint8Array;\n checksum: string;\n };\n}\n\nexport interface MigrationChunkAckMessage {\n type: 'MIGRATION_CHUNK_ACK';\n payload: {\n partitionId: number;\n chunkIndex: number;\n success: boolean;\n };\n}\n\nexport interface MigrationCompleteMessage {\n type: 'MIGRATION_COMPLETE';\n payload: {\n partitionId: number;\n totalRecords: number;\n checksum: string;\n };\n}\n\nexport interface MigrationVerifyMessage {\n type: 'MIGRATION_VERIFY';\n payload: {\n partitionId: number;\n success: boolean;\n checksumMatch: boolean;\n };\n}\n\nexport type MigrationMessage =\n | MigrationStartMessage\n | MigrationChunkMessage\n | MigrationChunkAckMessage\n | MigrationCompleteMessage\n | MigrationVerifyMessage;\n\n// ============================================\n// Consistency Levels (Task 04)\n// ============================================\n\nexport enum ConsistencyLevel {\n /** Wait for all replicas (owner + all backups) */\n STRONG = 'STRONG',\n /** Wait for majority (owner + N/2 backups) */\n QUORUM = 'QUORUM',\n /** Acknowledge after owner write only, background replication */\n EVENTUAL = 'EVENTUAL',\n}\n\nexport interface WriteOptions {\n consistency?: ConsistencyLevel;\n /** Replication timeout in ms */\n timeout?: number;\n}\n\nexport interface ReadOptions {\n consistency?: ConsistencyLevel;\n /** Read from backup if owner unavailable */\n allowStale?: boolean;\n /** Max acceptable lag in ms */\n maxStaleness?: number;\n}\n\n// ============================================\n// Replication Configuration (Task 04)\n// ============================================\n\nexport interface ReplicationConfig {\n defaultConsistency: ConsistencyLevel;\n /** Max queued operations (default: 10000) */\n queueSizeLimit: number;\n /** Operations per batch (default: 100) */\n batchSize: number;\n /** Batch flush interval in ms (default: 50) */\n batchIntervalMs: number;\n /** Ack timeout in ms (default: 5000) */\n ackTimeoutMs: number;\n /** Retries before marking node unhealthy (default: 3) */\n maxRetries: number;\n}\n\nexport const DEFAULT_REPLICATION_CONFIG: ReplicationConfig = {\n defaultConsistency: ConsistencyLevel.EVENTUAL,\n queueSizeLimit: 10000,\n batchSize: 100,\n batchIntervalMs: 50,\n ackTimeoutMs: 5000,\n maxRetries: 3,\n};\n\nexport interface ReplicationTask {\n opId: string;\n operation: unknown; // Will be typed more specifically in server\n consistency: ConsistencyLevel;\n timestamp: number;\n retryCount: number;\n}\n\nexport interface ReplicationLag {\n /** Current lag in ms */\n current: number;\n /** Average lag */\n avg: number;\n /** Maximum observed lag */\n max: number;\n /** 99th percentile lag */\n percentile99: number;\n}\n\nexport interface ReplicationHealth {\n healthy: boolean;\n unhealthyNodes: string[];\n laggyNodes: string[];\n avgLagMs: number;\n}\n\nexport interface ReplicationResult {\n success: boolean;\n ackedBy: string[];\n}\n\n// ============================================\n// Replication Protocol Messages (Task 04)\n// ============================================\n\nexport interface ReplicationMessage {\n type: 'REPLICATION';\n payload: {\n opId: string;\n operation: unknown;\n consistency: ConsistencyLevel;\n };\n}\n\nexport interface ReplicationBatchMessage {\n type: 'REPLICATION_BATCH';\n payload: {\n operations: unknown[];\n opIds: string[];\n };\n}\n\nexport interface ReplicationAckMessage {\n type: 'REPLICATION_ACK';\n payload: {\n opId: string;\n success: boolean;\n timestamp: number;\n };\n}\n\nexport interface ReplicationBatchAckMessage {\n type: 'REPLICATION_BATCH_ACK';\n payload: {\n opIds: string[];\n success: boolean;\n timestamp: number;\n };\n}\n\nexport type ReplicationProtocolMessage =\n | ReplicationMessage\n | ReplicationBatchMessage\n | ReplicationAckMessage\n | ReplicationBatchAckMessage;\n\n// ============================================\n// Constants\n// ============================================\n\nexport const PARTITION_COUNT = 271;\nexport const DEFAULT_BACKUP_COUNT = 1;\n","/**\n * Type-safe wrapper over sorted-btree for use in NavigableIndex\n *\n * Provides O(log N) operations for:\n * - set/get/delete\n * - range queries\n * - greaterThan/lessThan queries\n */\n\nimport BTree from 'sorted-btree';\nimport { Comparator, RangeOptions, defaultComparator } from './types';\n\n/**\n * A sorted map implementation backed by a B+ tree.\n * Provides efficient range queries and ordered iteration.\n *\n * @template K - Key type (must be comparable)\n * @template V - Value type\n */\nexport class SortedMap<K, V> {\n private readonly tree: BTree<K, V>;\n private readonly comparator: Comparator<K>;\n\n constructor(comparator?: Comparator<K>) {\n this.comparator = comparator ?? (defaultComparator as Comparator<K>);\n this.tree = new BTree<K, V>(undefined, this.comparator);\n }\n\n /**\n * Set a key-value pair. Updates existing key if present.\n * Time complexity: O(log N)\n */\n set(key: K, value: V): this {\n this.tree.set(key, value);\n return this;\n }\n\n /**\n * Get the value for a key.\n * Time complexity: O(log N)\n */\n get(key: K): V | undefined {\n return this.tree.get(key);\n }\n\n /**\n * Delete a key from the map.\n * Time complexity: O(log N)\n * @returns true if the key existed and was deleted\n */\n delete(key: K): boolean {\n return this.tree.delete(key);\n }\n\n /**\n * Check if a key exists in the map.\n * Time complexity: O(log N)\n */\n has(key: K): boolean {\n return this.tree.has(key);\n }\n\n /**\n * Get the number of entries in the map.\n */\n get size(): number {\n return this.tree.size;\n }\n\n /**\n * Check if the map is empty.\n */\n get isEmpty(): boolean {\n return this.tree.size === 0;\n }\n\n /**\n * Get the minimum key in the map.\n * Time complexity: O(log N)\n */\n minKey(): K | undefined {\n return this.tree.minKey();\n }\n\n /**\n * Get the maximum key in the map.\n * Time complexity: O(log N)\n */\n maxKey(): K | undefined {\n return this.tree.maxKey();\n }\n\n /**\n * Iterate over entries in a range [from, to).\n * Time complexity: O(log N + K) where K is the number of results\n *\n * @param from - Lower bound\n * @param to - Upper bound\n * @param options - Range options for inclusive/exclusive bounds\n */\n *range(from: K, to: K, options: RangeOptions = {}): IterableIterator<[K, V]> {\n const { fromInclusive = true, toInclusive = false } = options;\n\n // Validate range\n if (this.comparator(from, to) > 0) {\n return; // Empty range\n }\n\n // Use BTree's getRange which returns [key, value] pairs\n // getRange(lo, hi, includeHi) - lo is always inclusive\n const entries = this.tree.getRange(from, to, toInclusive);\n\n for (const [key, value] of entries) {\n // Skip from if not inclusive\n if (!fromInclusive && this.comparator(key, from) === 0) {\n continue;\n }\n yield [key, value];\n }\n }\n\n /**\n * Iterate over entries where key > value (or >= if inclusive).\n * Time complexity: O(log N + K) where K is the number of results\n *\n * @param key - Lower bound\n * @param inclusive - Include the bound in results (default: false)\n */\n *greaterThan(key: K, inclusive: boolean = false): IterableIterator<[K, V]> {\n // Find entries starting from key\n const entries = this.tree.entries(key);\n\n let first = true;\n for (const [k, v] of entries) {\n if (first) {\n first = false;\n // Skip the exact match if not inclusive\n if (!inclusive && this.comparator(k, key) === 0) {\n continue;\n }\n }\n yield [k, v];\n }\n }\n\n /**\n * Iterate over entries where key < value (or <= if inclusive).\n * Time complexity: O(log N + K) where K is the number of results\n *\n * Note: This method iterates from the beginning of the tree.\n * The O(log N) component is for finding the upper bound,\n * and O(K) is for yielding K results.\n *\n * @param key - Upper bound\n * @param inclusive - Include the bound in results (default: false)\n */\n *lessThan(key: K, inclusive: boolean = false): IterableIterator<[K, V]> {\n // Find the upper bound key\n const upperKey = inclusive ? this.floorKey(key) : this.lowerKey(key);\n\n if (upperKey === undefined) {\n return; // No keys less than the given key\n }\n\n // Use getRange from minKey to upperKey (inclusive)\n const minKey = this.tree.minKey();\n if (minKey === undefined) {\n return;\n }\n\n // getRange(lo, hi, includeHi) - returns entries in [lo, hi] or [lo, hi)\n const entries = this.tree.getRange(minKey, upperKey, true);\n for (const entry of entries) {\n yield entry;\n }\n }\n\n /**\n * Iterate over all entries in sorted order.\n * Time complexity: O(N)\n */\n *entries(): IterableIterator<[K, V]> {\n for (const entry of this.tree.entries()) {\n yield entry;\n }\n }\n\n /**\n * Iterate over all keys in sorted order.\n * Time complexity: O(N)\n */\n *keys(): IterableIterator<K> {\n for (const key of this.tree.keys()) {\n yield key;\n }\n }\n\n /**\n * Iterate over all values in sorted order.\n * Time complexity: O(N)\n */\n *values(): IterableIterator<V> {\n for (const value of this.tree.values()) {\n yield value;\n }\n }\n\n /**\n * Iterate over entries in reverse sorted order.\n * Time complexity: O(N)\n */\n *entriesReversed(): IterableIterator<[K, V]> {\n for (const entry of this.tree.entriesReversed()) {\n yield entry;\n }\n }\n\n /**\n * Remove all entries from the map.\n */\n clear(): void {\n this.tree.clear();\n }\n\n /**\n * Execute a callback for each entry in sorted order.\n */\n forEach(callback: (value: V, key: K, map: this) => void): void {\n this.tree.forEach((value, key) => {\n callback(value, key, this);\n });\n }\n\n /**\n * Create a new SortedMap from entries.\n */\n static from<K, V>(\n entries: Iterable<[K, V]>,\n comparator?: Comparator<K>\n ): SortedMap<K, V> {\n const map = new SortedMap<K, V>(comparator);\n for (const [key, value] of entries) {\n map.set(key, value);\n }\n return map;\n }\n\n /**\n * Get or set a value using a factory function.\n * If the key doesn't exist, the factory is called to create the value.\n */\n getOrSet(key: K, factory: () => V): V {\n const existing = this.tree.get(key);\n if (existing !== undefined) {\n return existing;\n }\n const value = factory();\n this.tree.set(key, value);\n return value;\n }\n\n /**\n * Update a value if the key exists.\n * @returns true if the key existed and was updated\n */\n update(key: K, updater: (value: V) => V): boolean {\n const existing = this.tree.get(key);\n if (existing === undefined) {\n return false;\n }\n this.tree.set(key, updater(existing));\n return true;\n }\n\n /**\n * Get the entry at a specific index (0-based).\n * Time complexity: O(N) - requires linear scan from the beginning.\n * Note: B+ trees do not support O(log N) index-based access.\n */\n at(index: number): [K, V] | undefined {\n if (index < 0 || index >= this.tree.size) {\n return undefined;\n }\n\n let i = 0;\n for (const entry of this.tree.entries()) {\n if (i === index) {\n return entry;\n }\n i++;\n }\n return undefined;\n }\n\n /**\n * Find the greatest key less than the given key.\n * Time complexity: O(log N)\n */\n lowerKey(key: K): K | undefined {\n return this.tree.nextLowerKey(key);\n }\n\n /**\n * Find the greatest key less than or equal to the given key.\n * Time complexity: O(log N)\n */\n floorKey(key: K): K | undefined {\n // Check if exact key exists first\n if (this.tree.has(key)) {\n return key;\n }\n // Otherwise find the next lower key\n return this.tree.nextLowerKey(key);\n }\n\n /**\n * Find the least key greater than the given key.\n * Time complexity: O(log N)\n */\n higherKey(key: K): K | undefined {\n for (const [k] of this.tree.entries(key)) {\n if (this.comparator(k, key) > 0) {\n return k;\n }\n }\n return undefined;\n }\n\n /**\n * Find the least key greater than or equal to the given key.\n * Time complexity: O(log N)\n */\n ceilingKey(key: K): K | undefined {\n for (const [k] of this.tree.entries(key)) {\n return k;\n }\n return undefined;\n }\n\n /**\n * Make the map iterable.\n */\n [Symbol.iterator](): IterableIterator<[K, V]> {\n return this.entries();\n }\n}\n","/**\n * Common types for sorted data structures\n */\n\n/**\n * Comparator function for ordering keys\n */\nexport type Comparator<K> = (a: K, b: K) => number;\n\n/**\n * Options for range queries\n */\nexport interface RangeOptions {\n /** Include the lower bound in results (default: true) */\n fromInclusive?: boolean;\n /** Include the upper bound in results (default: false) */\n toInclusive?: boolean;\n}\n\n/**\n * Default comparator using natural ordering\n */\nexport function defaultComparator<K>(a: K, b: K): number {\n if (a < b) return -1;\n if (a > b) return 1;\n return 0;\n}\n\n/**\n * String comparator for locale-aware ordering\n */\nexport function stringComparator(a: string, b: string): number {\n return a.localeCompare(b);\n}\n\n/**\n * Numeric comparator for number keys\n */\nexport function numericComparator(a: number, b: number): number {\n return a - b;\n}\n\n/**\n * Reverse comparator wrapper\n */\nexport function reverseComparator<K>(comparator: Comparator<K>): Comparator<K> {\n return (a: K, b: K) => -comparator(a, b);\n}\n","/**\n * Attribute System for Query Engine\n *\n * Attributes extract value(s) from records for indexing and querying.\n * Inspired by CQEngine Attribute<O, A>.\n *\n * @module query/Attribute\n */\n\n/**\n * Attribute extracts value(s) from a record.\n * V = Record value type, A = Attribute value type\n */\nexport interface Attribute<V, A> {\n /** Unique attribute name */\n readonly name: string;\n\n /** Attribute value type */\n readonly type: 'simple' | 'multi';\n\n /**\n * Extract value from record.\n * Returns undefined if attribute doesn't exist.\n */\n getValue(record: V): A | undefined;\n\n /**\n * For multi-value attributes, returns all values.\n * For simple attributes, returns single-element array.\n */\n getValues(record: V): A[];\n}\n\n/**\n * Attribute that returns exactly one value per record.\n */\nexport class SimpleAttribute<V, A> implements Attribute<V, A> {\n readonly type = 'simple' as const;\n\n constructor(\n readonly name: string,\n private readonly extractor: (record: V) => A | undefined\n ) {}\n\n getValue(record: V): A | undefined {\n return this.extractor(record);\n }\n\n getValues(record: V): A[] {\n const value = this.getValue(record);\n return value !== undefined ? [value] : [];\n }\n}\n\n/**\n * Factory function for SimpleAttribute.\n */\nexport function simpleAttribute<V, A>(\n name: string,\n extractor: (record: V) => A | undefined\n): SimpleAttribute<V, A> {\n return new SimpleAttribute(name, extractor);\n}\n\n/**\n * Attribute that returns zero or more values per record.\n * Example: tags, categories, roles.\n */\nexport class MultiValueAttribute<V, A> implements Attribute<V, A> {\n readonly type = 'multi' as const;\n\n constructor(\n readonly name: string,\n private readonly extractor: (record: V) => A[]\n ) {}\n\n getValue(record: V): A | undefined {\n const values = this.extractor(record);\n return values.length > 0 ? values[0] : undefined;\n }\n\n getValues(record: V): A[] {\n return this.extractor(record);\n }\n}\n\n/**\n * Factory function for MultiValueAttribute.\n */\nexport function multiAttribute<V, A>(\n name: string,\n extractor: (record: V) => A[]\n): MultiValueAttribute<V, A> {\n return new MultiValueAttribute(name, extractor);\n}\n","/**\n * SetResultSet Implementation\n *\n * ResultSet backed by a Set, used for HashIndex results.\n *\n * @module query/resultset/SetResultSet\n */\n\nimport type { ResultSet } from './ResultSet';\n\n/**\n * ResultSet backed by a Set.\n * Provides O(1) contains() check and direct iteration.\n */\nexport class SetResultSet<K> implements ResultSet<K> {\n constructor(\n private readonly keys: Set<K>,\n private readonly retrievalCost: number\n ) {}\n\n [Symbol.iterator](): Iterator<K> {\n return this.keys[Symbol.iterator]();\n }\n\n getRetrievalCost(): number {\n return this.retrievalCost;\n }\n\n getMergeCost(): number {\n return this.keys.size;\n }\n\n contains(key: K): boolean {\n return this.keys.has(key);\n }\n\n size(): number {\n return this.keys.size;\n }\n\n toArray(): K[] {\n return Array.from(this.keys);\n }\n\n isEmpty(): boolean {\n return this.keys.size === 0;\n }\n}\n","/**\n * HashIndex Implementation\n *\n * Hash-based index for O(1) equality lookups.\n * Supports: equal, in, has queries.\n *\n * Structure: Map<AttributeValue, Set<RecordKey>>\n *\n * CQEngine Reference: HashIndex.java (retrieval cost: 30)\n *\n * @module query/indexes/HashIndex\n */\n\nimport type { Attribute } from '../Attribute';\nimport type { Index, IndexQuery, IndexStats } from './types';\nimport type { ResultSet } from '../resultset/ResultSet';\nimport { SetResultSet } from '../resultset/SetResultSet';\n\n/**\n * Hash-based index for O(1) equality lookups.\n *\n * K = record key type, V = record value type, A = attribute value type\n */\nexport class HashIndex<K, V, A> implements Index<K, V, A> {\n readonly type = 'hash' as const;\n\n /** Map from attribute value to set of record keys */\n private data: Map<A, Set<K>> = new Map();\n\n /** Set of all keys with non-null attribute value */\n private allKeys: Set<K> = new Set();\n\n private static readonly RETRIEVAL_COST = 30;\n private static readonly SUPPORTED_QUERIES = ['equal', 'in', 'has'];\n\n constructor(readonly attribute: Attribute<V, A>) {}\n\n getRetrievalCost(): number {\n return HashIndex.RETRIEVAL_COST;\n }\n\n supportsQuery(queryType: string): boolean {\n return HashIndex.SUPPORTED_QUERIES.includes(queryType);\n }\n\n retrieve(query: IndexQuery<A>): ResultSet<K> {\n switch (query.type) {\n case 'equal':\n return this.retrieveEqual(query.value as A);\n case 'in':\n return this.retrieveIn(query.values as A[]);\n case 'has':\n return this.retrieveHas();\n default:\n throw new Error(`HashIndex does not support query type: ${query.type}`);\n }\n }\n\n private retrieveEqual(value: A): ResultSet<K> {\n const keys = this.data.get(value);\n return new SetResultSet(keys ? new Set(keys) : new Set(), HashIndex.RETRIEVAL_COST);\n }\n\n private retrieveIn(values: A[]): ResultSet<K> {\n const result = new Set<K>();\n for (const value of values) {\n const keys = this.data.get(value);\n if (keys) {\n for (const key of keys) {\n result.add(key);\n }\n }\n }\n return new SetResultSet(result, HashIndex.RETRIEVAL_COST);\n }\n\n private retrieveHas(): ResultSet<K> {\n return new SetResultSet(new Set(this.allKeys), HashIndex.RETRIEVAL_COST);\n }\n\n add(key: K, record: V): void {\n const values = this.attribute.getValues(record);\n if (values.length === 0) return;\n\n for (const value of values) {\n let keys = this.data.get(value);\n if (!keys) {\n keys = new Set();\n this.data.set(value, keys);\n }\n keys.add(key);\n }\n\n this.allKeys.add(key);\n }\n\n remove(key: K, record: V): void {\n const values = this.attribute.getValues(record);\n\n for (const value of values) {\n const keys = this.data.get(value);\n if (keys) {\n keys.delete(key);\n if (keys.size === 0) {\n this.data.delete(value);\n }\n }\n }\n\n this.allKeys.delete(key);\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n const oldValues = this.attribute.getValues(oldRecord);\n const newValues = this.attribute.getValues(newRecord);\n\n // Optimize: check if values actually changed\n if (this.arraysEqual(oldValues, newValues)) {\n return;\n }\n\n this.remove(key, oldRecord);\n this.add(key, newRecord);\n }\n\n clear(): void {\n this.data.clear();\n this.allKeys.clear();\n }\n\n getStats(): IndexStats {\n let totalEntries = 0;\n for (const keys of this.data.values()) {\n totalEntries += keys.size;\n }\n\n return {\n distinctValues: this.data.size,\n totalEntries,\n avgEntriesPerValue: this.data.size > 0 ? totalEntries / this.data.size : 0,\n };\n }\n\n private arraysEqual(a: A[], b: A[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n }\n}\n","/**\n * LazyResultSet Implementation\n *\n * Lazily evaluated result set for range queries.\n * Used when materializing all results upfront would be expensive.\n *\n * @module query/resultset/LazyResultSet\n */\n\nimport type { ResultSet } from './ResultSet';\n\n/**\n * Factory function type that creates a generator for lazy iteration.\n */\nexport type IteratorFactory<K> = () => Generator<K>;\n\n/**\n * Lazily evaluated result set.\n * Used for range queries where materializing all results upfront is expensive.\n *\n * K = record key type\n */\nexport class LazyResultSet<K> implements ResultSet<K> {\n /** Cached materialized results */\n private cached: K[] | null = null;\n\n /**\n * Create a LazyResultSet.\n *\n * @param iteratorFactory - Factory that creates a fresh generator each time\n * @param retrievalCost - Cost of retrieving results from the index\n * @param estimatedSize - Estimated result count for merge cost calculation\n */\n constructor(\n private readonly iteratorFactory: IteratorFactory<K>,\n private readonly retrievalCost: number,\n private readonly estimatedSize: number\n ) {}\n\n *[Symbol.iterator](): Generator<K> {\n if (this.cached) {\n yield* this.cached;\n return;\n }\n\n yield* this.iteratorFactory();\n }\n\n getRetrievalCost(): number {\n return this.retrievalCost;\n }\n\n getMergeCost(): number {\n // Use actual size if cached, otherwise use estimated size\n return this.cached?.length ?? this.estimatedSize;\n }\n\n contains(key: K): boolean {\n // Must materialize to check containment\n return this.toArray().includes(key);\n }\n\n size(): number {\n return this.toArray().length;\n }\n\n toArray(): K[] {\n if (!this.cached) {\n this.cached = [...this.iteratorFactory()];\n }\n return this.cached;\n }\n\n isEmpty(): boolean {\n // If already cached, use the cached value\n if (this.cached) {\n return this.cached.length === 0;\n }\n\n // Try to avoid full materialization by checking just the first element\n const iter = this.iteratorFactory();\n const first = iter.next();\n return first.done === true;\n }\n\n /**\n * Check if the result set has been materialized.\n * Useful for testing lazy evaluation behavior.\n */\n isMaterialized(): boolean {\n return this.cached !== null;\n }\n\n /**\n * Force materialization of the result set.\n * Returns the cached array.\n */\n materialize(): K[] {\n return this.toArray();\n }\n\n /**\n * Get the estimated size before materialization.\n */\n getEstimatedSize(): number {\n return this.estimatedSize;\n }\n}\n","/**\n * NavigableIndex Implementation\n *\n * Sorted index for O(log N) range queries.\n * Supports: equal, in, has, gt, gte, lt, lte, between queries.\n *\n * Structure: SortedMap<AttributeValue, Set<RecordKey>>\n *\n * CQEngine Reference: NavigableIndex.java (retrieval cost: 40)\n *\n * @module query/indexes/NavigableIndex\n */\n\nimport type { Attribute } from '../Attribute';\nimport type { Index, IndexQuery, IndexStats } from './types';\nimport type { ResultSet } from '../resultset/ResultSet';\nimport { SetResultSet } from '../resultset/SetResultSet';\nimport { LazyResultSet } from '../resultset/LazyResultSet';\nimport { SortedMap } from '../ds/SortedMap';\nimport type { Comparator } from '../ds/types';\n\n/**\n * Sorted index for O(log N) range queries.\n *\n * K = record key type, V = record value type, A = attribute value type (must be orderable)\n */\nexport class NavigableIndex<K, V, A extends string | number>\n implements Index<K, V, A>\n{\n readonly type = 'navigable' as const;\n\n /** Sorted map from attribute value to set of record keys */\n private data: SortedMap<A, Set<K>>;\n\n /** Set of all keys with non-null attribute value */\n private allKeys: Set<K> = new Set();\n\n /** Retrieval cost as per CQEngine cost model */\n private static readonly RETRIEVAL_COST = 40;\n\n /** Supported query types */\n private static readonly SUPPORTED_QUERIES = [\n 'equal',\n 'in',\n 'has',\n 'gt',\n 'gte',\n 'lt',\n 'lte',\n 'between',\n ];\n\n /**\n * Create a NavigableIndex.\n *\n * @param attribute - Attribute to index\n * @param comparator - Optional custom comparator for ordering\n */\n constructor(\n readonly attribute: Attribute<V, A>,\n comparator?: Comparator<A>\n ) {\n this.data = new SortedMap<A, Set<K>>(comparator);\n }\n\n getRetrievalCost(): number {\n return NavigableIndex.RETRIEVAL_COST;\n }\n\n supportsQuery(queryType: string): boolean {\n return NavigableIndex.SUPPORTED_QUERIES.includes(queryType);\n }\n\n retrieve(query: IndexQuery<A>): ResultSet<K> {\n switch (query.type) {\n case 'equal':\n return this.retrieveEqual(query.value as A);\n case 'in':\n return this.retrieveIn(query.values as A[]);\n case 'has':\n return this.retrieveHas();\n case 'gt':\n return this.retrieveGreaterThan(query.value as A, false);\n case 'gte':\n return this.retrieveGreaterThan(query.value as A, true);\n case 'lt':\n return this.retrieveLessThan(query.value as A, false);\n case 'lte':\n return this.retrieveLessThan(query.value as A, true);\n case 'between':\n return this.retrieveBetween(\n query.from as A,\n query.to as A,\n query.fromInclusive ?? true,\n query.toInclusive ?? false\n );\n default:\n throw new Error(\n `NavigableIndex does not support query type: ${query.type}`\n );\n }\n }\n\n // ============== Equality Queries ==============\n\n private retrieveEqual(value: A): ResultSet<K> {\n const keys = this.data.get(value);\n return new SetResultSet(\n keys ? new Set(keys) : new Set(),\n NavigableIndex.RETRIEVAL_COST\n );\n }\n\n private retrieveIn(values: A[]): ResultSet<K> {\n const result = new Set<K>();\n for (const value of values) {\n const keys = this.data.get(value);\n if (keys) {\n for (const key of keys) {\n result.add(key);\n }\n }\n }\n return new SetResultSet(result, NavigableIndex.RETRIEVAL_COST);\n }\n\n private retrieveHas(): ResultSet<K> {\n return new SetResultSet(\n new Set(this.allKeys),\n NavigableIndex.RETRIEVAL_COST\n );\n }\n\n // ============== Range Queries ==============\n\n private retrieveGreaterThan(value: A, inclusive: boolean): ResultSet<K> {\n return new LazyResultSet(\n () => this.iterateGreaterThan(value, inclusive),\n NavigableIndex.RETRIEVAL_COST,\n this.estimateGreaterThanSize()\n );\n }\n\n private retrieveLessThan(value: A, inclusive: boolean): ResultSet<K> {\n return new LazyResultSet(\n () => this.iterateLessThan(value, inclusive),\n NavigableIndex.RETRIEVAL_COST,\n this.estimateLessThanSize()\n );\n }\n\n private retrieveBetween(\n from: A,\n to: A,\n fromInclusive: boolean,\n toInclusive: boolean\n ): ResultSet<K> {\n return new LazyResultSet(\n () => this.iterateBetween(from, to, fromInclusive, toInclusive),\n NavigableIndex.RETRIEVAL_COST,\n this.estimateBetweenSize()\n );\n }\n\n // ============== Lazy Iterators ==============\n\n private *iterateGreaterThan(value: A, inclusive: boolean): Generator<K> {\n for (const [, keys] of this.data.greaterThan(value, inclusive)) {\n for (const key of keys) {\n yield key;\n }\n }\n }\n\n private *iterateLessThan(value: A, inclusive: boolean): Generator<K> {\n for (const [, keys] of this.data.lessThan(value, inclusive)) {\n for (const key of keys) {\n yield key;\n }\n }\n }\n\n private *iterateBetween(\n from: A,\n to: A,\n fromInclusive: boolean,\n toInclusive: boolean\n ): Generator<K> {\n for (const [, keys] of this.data.range(from, to, {\n fromInclusive,\n toInclusive,\n })) {\n for (const key of keys) {\n yield key;\n }\n }\n }\n\n // ============== Size Estimation ==============\n\n /**\n * Estimate size for gt/gte queries.\n * Uses rough estimate: assume uniform distribution, return half.\n */\n private estimateGreaterThanSize(): number {\n return Math.max(1, Math.floor(this.allKeys.size / 2));\n }\n\n /**\n * Estimate size for lt/lte queries.\n * Uses rough estimate: assume uniform distribution, return half.\n */\n private estimateLessThanSize(): number {\n return Math.max(1, Math.floor(this.allKeys.size / 2));\n }\n\n /**\n * Estimate size for between queries.\n * Uses rough estimate: assume uniform distribution, return quarter.\n */\n private estimateBetweenSize(): number {\n return Math.max(1, Math.floor(this.allKeys.size / 4));\n }\n\n // ============== Index Mutations ==============\n\n add(key: K, record: V): void {\n const values = this.attribute.getValues(record);\n if (values.length === 0) return;\n\n for (const value of values) {\n let keys = this.data.get(value);\n if (!keys) {\n keys = new Set();\n this.data.set(value, keys);\n }\n keys.add(key);\n }\n\n this.allKeys.add(key);\n }\n\n remove(key: K, record: V): void {\n const values = this.attribute.getValues(record);\n\n for (const value of values) {\n const keys = this.data.get(value);\n if (keys) {\n keys.delete(key);\n if (keys.size === 0) {\n this.data.delete(value);\n }\n }\n }\n\n this.allKeys.delete(key);\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n const oldValues = this.attribute.getValues(oldRecord);\n const newValues = this.attribute.getValues(newRecord);\n\n // Optimize: check if values actually changed\n if (this.arraysEqual(oldValues, newValues)) {\n return;\n }\n\n this.remove(key, oldRecord);\n this.add(key, newRecord);\n }\n\n clear(): void {\n this.data.clear();\n this.allKeys.clear();\n }\n\n getStats(): IndexStats {\n let totalEntries = 0;\n for (const [, keys] of this.data.entries()) {\n totalEntries += keys.size;\n }\n\n return {\n distinctValues: this.data.size,\n totalEntries,\n avgEntriesPerValue:\n this.data.size > 0 ? totalEntries / this.data.size : 0,\n };\n }\n\n // ============== Helpers ==============\n\n private arraysEqual(a: A[], b: A[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n }\n\n /**\n * Get the minimum indexed value.\n * Useful for debugging and range estimation.\n */\n getMinValue(): A | undefined {\n return this.data.minKey();\n }\n\n /**\n * Get the maximum indexed value.\n * Useful for debugging and range estimation.\n */\n getMaxValue(): A | undefined {\n return this.data.maxKey();\n }\n}\n","/**\n * FallbackIndex Implementation\n *\n * Fallback index that performs full scan for queries without suitable index.\n * Has maximum retrieval cost to ensure it's only used as a last resort.\n *\n * @module query/indexes/FallbackIndex\n */\n\nimport type { Index, IndexQuery, IndexStats } from './types';\nimport type { ResultSet } from '../resultset/ResultSet';\nimport { SetResultSet } from '../resultset/SetResultSet';\nimport { simpleAttribute } from '../Attribute';\n\n/**\n * Fallback index that performs full scan.\n * Used when no suitable index exists for a query.\n *\n * K = record key type, V = record value type\n */\nexport class FallbackIndex<K, V> implements Index<K, V, unknown> {\n readonly type = 'hash' as const;\n\n /** Wildcard attribute for fallback */\n readonly attribute = simpleAttribute<V, unknown>('*', () => undefined);\n\n /** Maximum retrieval cost ensures this is only used as fallback */\n private static readonly RETRIEVAL_COST = Number.MAX_SAFE_INTEGER;\n\n /**\n * Create a FallbackIndex.\n *\n * @param getAllKeys - Function to get all keys in the collection\n * @param getRecord - Function to get a record by key\n * @param matchesPredicate - Function to check if a record matches a query\n */\n constructor(\n private readonly getAllKeys: () => Iterable<K>,\n private readonly getRecord: (key: K) => V | undefined,\n private readonly matchesPredicate: (record: V, query: IndexQuery<unknown>) => boolean\n ) {}\n\n getRetrievalCost(): number {\n return FallbackIndex.RETRIEVAL_COST;\n }\n\n /**\n * Supports any query type via full scan.\n */\n supportsQuery(): boolean {\n return true;\n }\n\n /**\n * Retrieve by performing full scan and applying predicate.\n */\n retrieve(query: IndexQuery<unknown>): ResultSet<K> {\n const result = new Set<K>();\n\n for (const key of this.getAllKeys()) {\n const record = this.getRecord(key);\n if (record && this.matchesPredicate(record, query)) {\n result.add(key);\n }\n }\n\n return new SetResultSet(result, FallbackIndex.RETRIEVAL_COST);\n }\n\n // FallbackIndex doesn't maintain state - these are no-ops\n add(): void {}\n remove(): void {}\n update(): void {}\n clear(): void {}\n\n getStats(): IndexStats {\n return {\n distinctValues: 0,\n totalEntries: 0,\n avgEntriesPerValue: 0,\n };\n }\n}\n\n/**\n * Factory to create predicate matcher from query.\n * Used by FallbackIndex to evaluate queries against records.\n *\n * @param getAttribute - Function to get attribute value from record\n */\nexport function createPredicateMatcher<V>(\n getAttribute: (record: V, attrName: string) => unknown\n): (record: V, query: IndexQuery<unknown>) => boolean {\n return (record: V, query: IndexQuery<unknown>): boolean => {\n // For wildcard queries, match everything\n if ((query as { attribute?: string }).attribute === '*') {\n return true;\n }\n\n const attrName = (query as { attribute?: string }).attribute;\n if (!attrName) {\n return true;\n }\n\n const value = getAttribute(record, attrName);\n\n switch (query.type) {\n case 'equal':\n return value === query.value;\n\n case 'in':\n return query.values?.includes(value) ?? false;\n\n case 'has':\n return value !== undefined && value !== null;\n\n case 'gt':\n return typeof value === 'number' && typeof query.value === 'number'\n ? value > query.value\n : typeof value === 'string' && typeof query.value === 'string'\n ? value > query.value\n : false;\n\n case 'gte':\n return typeof value === 'number' && typeof query.value === 'number'\n ? value >= query.value\n : typeof value === 'string' && typeof query.value === 'string'\n ? value >= query.value\n : false;\n\n case 'lt':\n return typeof value === 'number' && typeof query.value === 'number'\n ? value < query.value\n : typeof value === 'string' && typeof query.value === 'string'\n ? value < query.value\n : false;\n\n case 'lte':\n return typeof value === 'number' && typeof query.value === 'number'\n ? value <= query.value\n : typeof value === 'string' && typeof query.value === 'string'\n ? value <= query.value\n : false;\n\n case 'between': {\n if (typeof value !== 'number' && typeof value !== 'string') {\n return false;\n }\n const fromInclusive = query.fromInclusive ?? true;\n const toInclusive = query.toInclusive ?? false;\n const from = query.from;\n const to = query.to;\n\n if (from === undefined || from === null || to === undefined || to === null) {\n return false;\n }\n\n const aboveFrom = fromInclusive ? value >= from : value > from;\n const belowTo = toInclusive ? value <= to : value < to;\n return aboveFrom && belowTo;\n }\n\n default:\n return false;\n }\n };\n}\n","/**\n * Query Types and Plan Types for Query Engine\n *\n * Defines query node types for the cost-based optimizer\n * and execution plan types.\n *\n * @module query/QueryTypes\n */\n\nimport type { Index, IndexQuery } from './indexes/types';\n\n// ============== Query Node Types ==============\n\n/**\n * Base query node interface.\n * Compatible with existing PredicateNode from predicate.ts\n */\nexport interface QueryNode {\n type: string;\n}\n\n/**\n * Simple query node for attribute-based conditions.\n */\nexport interface SimpleQueryNode extends QueryNode {\n type: 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'between' | 'like' | 'regex' | 'in' | 'has' | 'contains' | 'containsAll' | 'containsAny';\n attribute: string;\n value?: unknown;\n values?: unknown[];\n /** For 'between' queries: lower bound */\n from?: unknown;\n /** For 'between' queries: upper bound */\n to?: unknown;\n /** For 'between' queries: include lower bound (default: true) */\n fromInclusive?: boolean;\n /** For 'between' queries: include upper bound (default: false) */\n toInclusive?: boolean;\n}\n\n// ============== Full-Text Search Query Types (Phase 12) ==============\n\n/**\n * Options for full-text search match queries.\n */\nexport interface MatchQueryOptions {\n /** Minimum BM25 score threshold */\n minScore?: number;\n /** Boost factor for this field */\n boost?: number;\n /** Operator for multi-term queries: 'and' requires all terms, 'or' requires any */\n operator?: 'and' | 'or';\n /** Fuzziness level for typo tolerance (0 = exact, 1 = 1 edit, 2 = 2 edits) */\n fuzziness?: number;\n}\n\n/**\n * Match query node for BM25 full-text search.\n */\nexport interface MatchQueryNode extends QueryNode {\n type: 'match';\n attribute: string;\n query: string;\n options?: MatchQueryOptions;\n}\n\n/**\n * Match phrase query node for exact phrase matching.\n */\nexport interface MatchPhraseQueryNode extends QueryNode {\n type: 'matchPhrase';\n attribute: string;\n query: string;\n /** Word distance tolerance (0 = exact phrase) */\n slop?: number;\n}\n\n/**\n * Match prefix query node for prefix matching.\n */\nexport interface MatchPrefixQueryNode extends QueryNode {\n type: 'matchPrefix';\n attribute: string;\n prefix: string;\n /** Maximum number of term expansions */\n maxExpansions?: number;\n}\n\n/**\n * Union type for FTS query nodes.\n */\nexport type FTSQueryNode = MatchQueryNode | MatchPhraseQueryNode | MatchPrefixQueryNode;\n\n/**\n * Logical query node for combining conditions.\n */\nexport interface LogicalQueryNode {\n type: 'and' | 'or' | 'not';\n children?: Query[];\n child?: Query;\n}\n\n/**\n * Union type for all query types.\n */\nexport type Query = SimpleQueryNode | LogicalQueryNode | FTSQueryNode;\n\n// ============== Query Options ==============\n\n/**\n * Query execution options for sort/limit/offset.\n */\nexport interface QueryOptions {\n /** Sort by field(s): field name -> direction */\n sort?: Record<string, 'asc' | 'desc'>;\n /** Maximum number of results to return */\n limit?: number;\n /** Number of results to skip */\n offset?: number;\n}\n\n// ============== Execution Plan Types ==============\n\n/**\n * Execution plan step.\n * Represents a single operation in the query execution plan.\n */\nexport type PlanStep =\n | IndexScanStep\n | FullScanStep\n | IntersectionStep\n | UnionStep\n | FilterStep\n | NotStep\n | FTSScanStep\n | FusionStep;\n\n/**\n * Index scan step - retrieves from an index.\n */\nexport interface IndexScanStep {\n type: 'index-scan';\n index: Index<unknown, unknown, unknown>;\n query: IndexQuery<unknown>;\n}\n\n/**\n * Full scan step - scans all records.\n */\nexport interface FullScanStep {\n type: 'full-scan';\n predicate: Query;\n}\n\n/**\n * Intersection step - AND of multiple result sets.\n */\nexport interface IntersectionStep {\n type: 'intersection';\n steps: PlanStep[];\n}\n\n/**\n * Union step - OR of multiple result sets.\n */\nexport interface UnionStep {\n type: 'union';\n steps: PlanStep[];\n}\n\n/**\n * Filter step - applies predicate to source results.\n */\nexport interface FilterStep {\n type: 'filter';\n source: PlanStep;\n predicate: Query;\n}\n\n/**\n * NOT step - negation (all keys minus matching keys).\n */\nexport interface NotStep {\n type: 'not';\n source: PlanStep;\n allKeys: () => Set<unknown>;\n}\n\n// ============== Full-Text Search Plan Types (Phase 12) ==============\n\n/**\n * Fusion strategy for combining results from different search methods.\n */\nexport type FusionStrategy = 'intersection' | 'rrf' | 'score-filter';\n\n/**\n * FTS scan step - full-text search using FullTextIndex.\n * Returns scored results (documents with BM25 scores).\n */\nexport interface FTSScanStep {\n type: 'fts-scan';\n /** Field to search */\n field: string;\n /** Search query or phrase */\n query: string;\n /** Type of FTS query */\n ftsType: 'match' | 'matchPhrase' | 'matchPrefix';\n /** Query options (minScore, boost, etc.) */\n options?: MatchQueryOptions;\n /** This step returns scored results */\n returnsScored: true;\n /** Estimated cost */\n estimatedCost: number;\n}\n\n/**\n * Fusion step - combines results from multiple steps using RRF or other strategy.\n */\nexport interface FusionStep {\n type: 'fusion';\n /** Steps to combine */\n steps: PlanStep[];\n /** Fusion strategy */\n strategy: FusionStrategy;\n /** Whether result is scored (true if any child is scored) */\n returnsScored: boolean;\n}\n\n// ============== Query Plan ==============\n\n/**\n * Complete query execution plan.\n */\nexport interface QueryPlan {\n /** Root execution step */\n root: PlanStep;\n /** Estimated execution cost */\n estimatedCost: number;\n /** Whether any index is used */\n usesIndexes: boolean;\n /** Whether sort can use index order */\n indexedSort?: boolean;\n /** Sort configuration */\n sort?: {\n field: string;\n direction: 'asc' | 'desc';\n };\n /** Limit configuration */\n limit?: number;\n /** Offset configuration */\n offset?: number;\n}\n\n// ============== Type Guards ==============\n\n/**\n * Check if a query is a simple query node.\n */\nexport function isSimpleQuery(query: Query): query is SimpleQueryNode {\n return [\n 'eq',\n 'neq',\n 'gt',\n 'gte',\n 'lt',\n 'lte',\n 'between',\n 'like',\n 'regex',\n 'in',\n 'has',\n 'contains',\n 'containsAll',\n 'containsAny',\n ].includes(query.type);\n}\n\n/**\n * Check if a query is a logical query node.\n */\nexport function isLogicalQuery(query: Query): query is LogicalQueryNode {\n return query.type === 'and' || query.type === 'or' || query.type === 'not';\n}\n\n/**\n * Check if a query is a full-text search query node.\n */\nexport function isFTSQuery(query: Query): query is FTSQueryNode {\n return query.type === 'match' || query.type === 'matchPhrase' || query.type === 'matchPrefix';\n}\n\n/**\n * Check if a query is a match query node.\n */\nexport function isMatchQuery(query: Query): query is MatchQueryNode {\n return query.type === 'match';\n}\n\n/**\n * Check if a query is a match phrase query node.\n */\nexport function isMatchPhraseQuery(query: Query): query is MatchPhraseQueryNode {\n return query.type === 'matchPhrase';\n}\n\n/**\n * Check if a query is a match prefix query node.\n */\nexport function isMatchPrefixQuery(query: Query): query is MatchPrefixQueryNode {\n return query.type === 'matchPrefix';\n}\n","/**\n * StandingQueryIndex Implementation\n *\n * Pre-computed index for a specific query.\n * Maintains result set incrementally as data changes.\n *\n * Lowest retrieval cost (10) - O(1) query execution.\n * Critical for Live Queries in TopGun where the same query\n * is executed repeatedly on every data change.\n *\n * CQEngine Reference: StandingQueryIndex.java (retrieval cost: 10)\n *\n * @module query/indexes/StandingQueryIndex\n */\n\nimport type { Attribute } from '../Attribute';\nimport { simpleAttribute } from '../Attribute';\nimport type { Index, IndexQuery, IndexStats } from './types';\nimport type { ResultSet } from '../resultset/ResultSet';\nimport { SetResultSet } from '../resultset/SetResultSet';\nimport type { Query, SimpleQueryNode, LogicalQueryNode } from '../QueryTypes';\nimport { isSimpleQuery, isLogicalQuery } from '../QueryTypes';\n\n/**\n * Change type for standing query updates.\n */\nexport type StandingQueryChange = 'added' | 'removed' | 'updated' | 'unchanged';\n\n/**\n * Options for creating a StandingQueryIndex.\n */\nexport interface StandingQueryIndexOptions<K, V> {\n /** Query this index answers */\n query: Query;\n /** Function to get record by key (optional, for validation) */\n getRecord?: (key: K) => V | undefined;\n}\n\n/**\n * Pre-computed index for a specific query.\n * Maintains result set incrementally as data changes.\n *\n * K = record key type, V = record value type\n */\nexport class StandingQueryIndex<K, V> implements Index<K, V, unknown> {\n readonly type = 'standing' as const;\n\n /**\n * Wildcard attribute - StandingQueryIndex doesn't index by attribute,\n * it indexes by query match.\n */\n readonly attribute: Attribute<V, unknown> = simpleAttribute<V, unknown>(\n '*',\n () => undefined\n );\n\n /** Pre-computed result set */\n private results: Set<K> = new Set();\n\n /** Query this index answers */\n private readonly query: Query;\n\n /** Record accessor (optional) */\n private readonly getRecord?: (key: K) => V | undefined;\n\n /** Retrieval cost - lowest of all index types */\n private static readonly RETRIEVAL_COST = 10;\n\n constructor(options: StandingQueryIndexOptions<K, V>) {\n this.query = options.query;\n this.getRecord = options.getRecord;\n }\n\n /**\n * Get the query this index answers.\n */\n getQuery(): Query {\n return this.query;\n }\n\n /**\n * Check if this index answers the given query.\n */\n answersQuery(query: Query): boolean {\n return this.queriesEqual(this.query, query);\n }\n\n getRetrievalCost(): number {\n return StandingQueryIndex.RETRIEVAL_COST;\n }\n\n supportsQuery(_queryType: string): boolean {\n // StandingQueryIndex supports any query type since it pre-computes results\n // The actual query matching is done via answersQuery()\n return true;\n }\n\n retrieve(_query: IndexQuery<unknown>): ResultSet<K> {\n // Return pre-computed results (copy to avoid mutation)\n return new SetResultSet(new Set(this.results), StandingQueryIndex.RETRIEVAL_COST);\n }\n\n /**\n * Get current result set (for live query updates).\n * Returns a copy to avoid external mutation.\n */\n getResults(): Set<K> {\n return new Set(this.results);\n }\n\n /**\n * Get result count.\n */\n getResultCount(): number {\n return this.results.size;\n }\n\n /**\n * Check if key is in results.\n */\n contains(key: K): boolean {\n return this.results.has(key);\n }\n\n add(key: K, record: V): void {\n // Evaluate predicate and add if matches\n if (this.evaluateRecord(record)) {\n this.results.add(key);\n }\n }\n\n remove(key: K, _record: V): void {\n // Always try to remove (may or may not be in results)\n this.results.delete(key);\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n const wasMatch = this.evaluateRecord(oldRecord);\n const isMatch = this.evaluateRecord(newRecord);\n\n if (wasMatch && !isMatch) {\n // Was in results, no longer matches\n this.results.delete(key);\n } else if (!wasMatch && isMatch) {\n // Was not in results, now matches\n this.results.add(key);\n }\n // If both match or neither match, no change to results set\n // (though the record itself may have changed)\n }\n\n /**\n * Determine what changed for a record update.\n * Returns the type of change relative to the query results.\n *\n * @param key - Record key\n * @param oldRecord - Previous record value (undefined for new records)\n * @param newRecord - New record value (undefined for deleted records)\n * @returns Change type: 'added', 'removed', 'updated', or 'unchanged'\n */\n determineChange(\n _key: K,\n oldRecord: V | undefined,\n newRecord: V | undefined\n ): StandingQueryChange {\n const wasMatch = oldRecord ? this.evaluateRecord(oldRecord) : false;\n const isMatch = newRecord ? this.evaluateRecord(newRecord) : false;\n\n if (!wasMatch && isMatch) {\n return 'added';\n } else if (wasMatch && !isMatch) {\n return 'removed';\n } else if (wasMatch && isMatch) {\n return 'updated';\n }\n return 'unchanged';\n }\n\n clear(): void {\n this.results.clear();\n }\n\n getStats(): IndexStats {\n return {\n distinctValues: 1, // Single query\n totalEntries: this.results.size,\n avgEntriesPerValue: this.results.size,\n };\n }\n\n /**\n * Build index from existing data.\n *\n * @param entries - Iterable of [key, record] pairs\n */\n buildFromData(entries: Iterable<[K, V]>): void {\n this.results.clear();\n for (const [key, record] of entries) {\n if (this.evaluateRecord(record)) {\n this.results.add(key);\n }\n }\n }\n\n /**\n * Evaluate a record against the query predicate.\n *\n * @param record - Record to evaluate\n * @returns true if record matches the query\n */\n private evaluateRecord(record: V): boolean {\n try {\n return this.evaluateQuery(this.query, record);\n } catch {\n return false;\n }\n }\n\n /**\n * Evaluate a query node against a record.\n * Implements predicate evaluation logic.\n */\n private evaluateQuery(query: Query, record: V): boolean {\n if (isSimpleQuery(query)) {\n return this.evaluateSimpleQuery(query, record);\n } else if (isLogicalQuery(query)) {\n return this.evaluateLogicalQuery(query, record);\n }\n return false;\n }\n\n /**\n * Evaluate a simple query (attribute-based condition).\n */\n private evaluateSimpleQuery(query: SimpleQueryNode, record: V): boolean {\n const value = this.getAttributeValue(record, query.attribute);\n\n switch (query.type) {\n case 'eq':\n return value === query.value;\n\n case 'neq':\n return value !== query.value;\n\n case 'gt':\n return (\n value !== undefined &&\n value !== null &&\n (value as number) > (query.value as number)\n );\n\n case 'gte':\n return (\n value !== undefined &&\n value !== null &&\n (value as number) >= (query.value as number)\n );\n\n case 'lt':\n return (\n value !== undefined &&\n value !== null &&\n (value as number) < (query.value as number)\n );\n\n case 'lte':\n return (\n value !== undefined &&\n value !== null &&\n (value as number) <= (query.value as number)\n );\n\n case 'in':\n return query.values !== undefined && query.values.includes(value);\n\n case 'has':\n return value !== undefined && value !== null;\n\n case 'like':\n if (typeof value !== 'string' || typeof query.value !== 'string') {\n return false;\n }\n return this.matchLike(value, query.value);\n\n case 'regex':\n if (typeof value !== 'string' || typeof query.value !== 'string') {\n return false;\n }\n try {\n return new RegExp(query.value).test(value);\n } catch {\n return false;\n }\n\n case 'between':\n if (value === undefined || value === null) {\n return false;\n }\n const val = value as number | string;\n const from = query.from as number | string;\n const to = query.to as number | string;\n const fromOk = query.fromInclusive !== false ? val >= from : val > from;\n const toOk = query.toInclusive !== false ? val <= to : val < to;\n return fromOk && toOk;\n\n case 'contains':\n if (typeof value !== 'string' || typeof query.value !== 'string') {\n return false;\n }\n return value.toLowerCase().includes((query.value as string).toLowerCase());\n\n case 'containsAll':\n if (typeof value !== 'string' || !query.values) {\n return false;\n }\n return query.values.every(\n (v) => typeof v === 'string' && value.toLowerCase().includes(v.toLowerCase())\n );\n\n case 'containsAny':\n if (typeof value !== 'string' || !query.values) {\n return false;\n }\n return query.values.some(\n (v) => typeof v === 'string' && value.toLowerCase().includes(v.toLowerCase())\n );\n\n default:\n return false;\n }\n }\n\n /**\n * Evaluate a logical query (AND/OR/NOT).\n */\n private evaluateLogicalQuery(query: LogicalQueryNode, record: V): boolean {\n switch (query.type) {\n case 'and':\n if (!query.children || query.children.length === 0) {\n return true;\n }\n return query.children.every((child) => this.evaluateQuery(child, record));\n\n case 'or':\n if (!query.children || query.children.length === 0) {\n return false;\n }\n return query.children.some((child) => this.evaluateQuery(child, record));\n\n case 'not':\n if (!query.child) {\n return true;\n }\n return !this.evaluateQuery(query.child, record);\n\n default:\n return false;\n }\n }\n\n /**\n * Get attribute value from record using dot notation.\n */\n private getAttributeValue(record: V, path: string): unknown {\n if (record === null || record === undefined) {\n return undefined;\n }\n\n const parts = path.split('.');\n let current: unknown = record;\n\n for (const part of parts) {\n if (current === null || current === undefined) {\n return undefined;\n }\n if (typeof current !== 'object') {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n }\n\n /**\n * Match a value against a LIKE pattern.\n * Supports % as wildcard for any characters.\n */\n private matchLike(value: string, pattern: string): boolean {\n // Convert LIKE pattern to regex\n const escaped = pattern.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n const regex = escaped.replace(/%/g, '.*').replace(/_/g, '.');\n return new RegExp(`^${regex}$`, 'i').test(value);\n }\n\n /**\n * Deep equality check for queries.\n */\n private queriesEqual(a: Query, b: Query): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n }\n}\n","/**\n * Tokenizer Interface and Implementations\n *\n * Provides text tokenization for InvertedIndex full-text search.\n * Tokenizers split text into searchable tokens.\n *\n * @module query/tokenization/Tokenizer\n */\n\n/**\n * Interface for text tokenizers.\n * Tokenizers split text into an array of tokens (words, n-grams, etc.)\n */\nexport interface Tokenizer {\n /**\n * Split text into tokens.\n *\n * @param text - Text to tokenize\n * @returns Array of tokens\n */\n tokenize(text: string): string[];\n}\n\n/**\n * Tokenizer that splits on whitespace.\n * Simplest tokenizer - splits on any whitespace characters.\n *\n * Example: \"hello world\" → [\"hello\", \"world\"]\n */\nexport class WhitespaceTokenizer implements Tokenizer {\n tokenize(text: string): string[] {\n if (!text || typeof text !== 'string') {\n return [];\n }\n return text.split(/\\s+/).filter((t) => t.length > 0);\n }\n}\n\n/**\n * Tokenizer that splits on word boundaries.\n * Splits on non-word characters (anything not [a-zA-Z0-9_]).\n *\n * Example: \"hello-world! test123\" → [\"hello\", \"world\", \"test123\"]\n */\nexport class WordBoundaryTokenizer implements Tokenizer {\n tokenize(text: string): string[] {\n if (!text || typeof text !== 'string') {\n return [];\n }\n return text.split(/\\W+/).filter((t) => t.length > 0);\n }\n}\n\n/**\n * N-gram tokenizer for substring matching.\n * Creates overlapping character sequences of length n.\n *\n * Example (n=3): \"hello\" → [\"hel\", \"ell\", \"llo\"]\n *\n * Use cases:\n * - Fuzzy search (typo tolerance)\n * - Substring matching (contains anywhere)\n * - Partial word matching\n */\nexport class NGramTokenizer implements Tokenizer {\n /**\n * Create an N-gram tokenizer.\n *\n * @param n - Length of each n-gram (default: 3)\n */\n constructor(private readonly n: number = 3) {\n if (n < 1) {\n throw new Error('N-gram size must be at least 1');\n }\n }\n\n tokenize(text: string): string[] {\n if (!text || typeof text !== 'string') {\n return [];\n }\n\n // Remove whitespace for n-gram generation\n const normalized = text.replace(/\\s+/g, ' ').trim();\n\n if (normalized.length < this.n) {\n // Text is shorter than n-gram size - return text itself if non-empty\n return normalized.length > 0 ? [normalized] : [];\n }\n\n const tokens: string[] = [];\n for (let i = 0; i <= normalized.length - this.n; i++) {\n tokens.push(normalized.substring(i, i + this.n));\n }\n\n return tokens;\n }\n\n /**\n * Get the n-gram size.\n */\n get size(): number {\n return this.n;\n }\n}\n","/**\n * Token Filter Interface and Implementations\n *\n * Token filters transform or filter tokens produced by tokenizers.\n * Common uses: lowercase normalization, stop word removal, length filtering.\n *\n * @module query/tokenization/TokenFilter\n */\n\n/**\n * Interface for token filters.\n * Filters transform an array of tokens into another array of tokens.\n */\nexport interface TokenFilter {\n /**\n * Apply filter to tokens.\n *\n * @param tokens - Input tokens\n * @returns Filtered tokens\n */\n apply(tokens: string[]): string[];\n}\n\n/**\n * Filter that converts all tokens to lowercase.\n * Essential for case-insensitive search.\n *\n * Example: [\"Hello\", \"WORLD\"] → [\"hello\", \"world\"]\n */\nexport class LowercaseFilter implements TokenFilter {\n apply(tokens: string[]): string[] {\n return tokens.map((t) => t.toLowerCase());\n }\n}\n\n/**\n * Default English stop words.\n * Common words that don't add search value.\n */\nexport const DEFAULT_STOP_WORDS = [\n 'a',\n 'an',\n 'and',\n 'are',\n 'as',\n 'at',\n 'be',\n 'but',\n 'by',\n 'for',\n 'if',\n 'in',\n 'into',\n 'is',\n 'it',\n 'no',\n 'not',\n 'of',\n 'on',\n 'or',\n 'such',\n 'that',\n 'the',\n 'their',\n 'then',\n 'there',\n 'these',\n 'they',\n 'this',\n 'to',\n 'was',\n 'will',\n 'with',\n];\n\n/**\n * Filter that removes stop words.\n * Stop words are common words that don't contribute to search relevance.\n *\n * Example: [\"the\", \"quick\", \"brown\", \"fox\"] → [\"quick\", \"brown\", \"fox\"]\n */\nexport class StopWordFilter implements TokenFilter {\n private readonly stopWords: Set<string>;\n\n /**\n * Create a stop word filter.\n *\n * @param stopWords - Array of stop words to remove (default: English stop words)\n */\n constructor(stopWords: string[] = DEFAULT_STOP_WORDS) {\n // Store in lowercase for case-insensitive matching\n this.stopWords = new Set(stopWords.map((w) => w.toLowerCase()));\n }\n\n apply(tokens: string[]): string[] {\n return tokens.filter((t) => !this.stopWords.has(t.toLowerCase()));\n }\n\n /**\n * Get the set of stop words.\n */\n getStopWords(): Set<string> {\n return new Set(this.stopWords);\n }\n}\n\n/**\n * Filter that removes tokens shorter than a minimum length.\n * Useful for filtering out single characters or very short tokens.\n *\n * Example (minLength=3): [\"a\", \"is\", \"the\", \"quick\"] → [\"the\", \"quick\"]\n */\nexport class MinLengthFilter implements TokenFilter {\n /**\n * Create a minimum length filter.\n *\n * @param minLength - Minimum token length (default: 2)\n */\n constructor(private readonly minLength: number = 2) {\n if (minLength < 1) {\n throw new Error('Minimum length must be at least 1');\n }\n }\n\n apply(tokens: string[]): string[] {\n return tokens.filter((t) => t.length >= this.minLength);\n }\n\n /**\n * Get the minimum length setting.\n */\n getMinLength(): number {\n return this.minLength;\n }\n}\n\n/**\n * Filter that removes tokens longer than a maximum length.\n * Useful for preventing very long tokens from being indexed.\n *\n * Example (maxLength=10): [\"short\", \"verylongword\"] → [\"short\"]\n */\nexport class MaxLengthFilter implements TokenFilter {\n /**\n * Create a maximum length filter.\n *\n * @param maxLength - Maximum token length (default: 50)\n */\n constructor(private readonly maxLength: number = 50) {\n if (maxLength < 1) {\n throw new Error('Maximum length must be at least 1');\n }\n }\n\n apply(tokens: string[]): string[] {\n return tokens.filter((t) => t.length <= this.maxLength);\n }\n\n /**\n * Get the maximum length setting.\n */\n getMaxLength(): number {\n return this.maxLength;\n }\n}\n\n/**\n * Filter that trims whitespace from tokens.\n * Ensures clean tokens without leading/trailing spaces.\n */\nexport class TrimFilter implements TokenFilter {\n apply(tokens: string[]): string[] {\n return tokens.map((t) => t.trim()).filter((t) => t.length > 0);\n }\n}\n\n/**\n * Filter that removes duplicate tokens.\n * Useful for reducing index size when tokens repeat.\n *\n * Example: [\"hello\", \"world\", \"hello\"] → [\"hello\", \"world\"]\n */\nexport class UniqueFilter implements TokenFilter {\n apply(tokens: string[]): string[] {\n return [...new Set(tokens)];\n }\n}\n","/**\n * Tokenization Pipeline\n *\n * Chains a tokenizer with multiple filters for text processing.\n * Provides factory methods for common configurations.\n *\n * @module query/tokenization/TokenizationPipeline\n */\n\nimport type { Tokenizer } from './Tokenizer';\nimport { WordBoundaryTokenizer } from './Tokenizer';\nimport type { TokenFilter } from './TokenFilter';\nimport { LowercaseFilter, MinLengthFilter, StopWordFilter } from './TokenFilter';\n\n/**\n * Pipeline configuration options.\n */\nexport interface TokenizationPipelineOptions {\n /** Tokenizer to use */\n tokenizer: Tokenizer;\n /** Filters to apply (in order) */\n filters?: TokenFilter[];\n}\n\n/**\n * Tokenization pipeline that chains a tokenizer with filters.\n *\n * Processing order:\n * 1. Tokenizer splits text into tokens\n * 2. Each filter transforms the token array in sequence\n *\n * Example:\n * ```typescript\n * const pipeline = TokenizationPipeline.simple();\n * pipeline.process(\"Hello World!\"); // [\"hello\", \"world\"]\n * ```\n */\nexport class TokenizationPipeline {\n private readonly tokenizer: Tokenizer;\n private readonly filters: TokenFilter[];\n\n /**\n * Create a tokenization pipeline.\n *\n * @param options - Pipeline configuration\n */\n constructor(options: TokenizationPipelineOptions) {\n this.tokenizer = options.tokenizer;\n this.filters = options.filters ?? [];\n }\n\n /**\n * Process text through the pipeline.\n *\n * @param text - Text to process\n * @returns Array of processed tokens\n */\n process(text: string): string[] {\n if (!text || typeof text !== 'string') {\n return [];\n }\n\n // Step 1: Tokenize\n let tokens = this.tokenizer.tokenize(text);\n\n // Step 2: Apply filters in order\n for (const filter of this.filters) {\n tokens = filter.apply(tokens);\n }\n\n return tokens;\n }\n\n /**\n * Get the tokenizer.\n */\n getTokenizer(): Tokenizer {\n return this.tokenizer;\n }\n\n /**\n * Get the filters.\n */\n getFilters(): TokenFilter[] {\n return [...this.filters];\n }\n\n // ==================== Factory Methods ====================\n\n /**\n * Create a simple pipeline with common defaults.\n * Uses word boundary tokenizer with lowercase and minimum length filters.\n *\n * Configuration:\n * - Tokenizer: WordBoundaryTokenizer\n * - Filters: LowercaseFilter, MinLengthFilter(2)\n *\n * @returns Simple tokenization pipeline\n */\n static simple(): TokenizationPipeline {\n return new TokenizationPipeline({\n tokenizer: new WordBoundaryTokenizer(),\n filters: [new LowercaseFilter(), new MinLengthFilter(2)],\n });\n }\n\n /**\n * Create a pipeline optimized for search.\n * Includes stop word removal for better search relevance.\n *\n * Configuration:\n * - Tokenizer: WordBoundaryTokenizer\n * - Filters: LowercaseFilter, MinLengthFilter(2), StopWordFilter\n *\n * @returns Search-optimized tokenization pipeline\n */\n static search(): TokenizationPipeline {\n return new TokenizationPipeline({\n tokenizer: new WordBoundaryTokenizer(),\n filters: [new LowercaseFilter(), new MinLengthFilter(2), new StopWordFilter()],\n });\n }\n\n /**\n * Create a minimal pipeline with just tokenization and lowercase.\n * No filtering - preserves all tokens.\n *\n * Configuration:\n * - Tokenizer: WordBoundaryTokenizer\n * - Filters: LowercaseFilter\n *\n * @returns Minimal tokenization pipeline\n */\n static minimal(): TokenizationPipeline {\n return new TokenizationPipeline({\n tokenizer: new WordBoundaryTokenizer(),\n filters: [new LowercaseFilter()],\n });\n }\n\n /**\n * Create a custom pipeline from a tokenizer and filters.\n *\n * @param tokenizer - Tokenizer to use\n * @param filters - Filters to apply\n * @returns Custom tokenization pipeline\n */\n static custom(tokenizer: Tokenizer, filters: TokenFilter[] = []): TokenizationPipeline {\n return new TokenizationPipeline({ tokenizer, filters });\n }\n}\n","/**\n * InvertedIndex Implementation\n *\n * Full-text search index using inverted index structure.\n * Supports: contains, containsAll, containsAny, has queries.\n *\n * Structure:\n * tokenIndex: Map<Token, Set<RecordKey>>\n * reverseIndex: Map<RecordKey, Set<Token>>\n *\n * Retrieval cost: 50 (between NavigableIndex:40 and FallbackIndex)\n *\n * @module query/indexes/InvertedIndex\n */\n\nimport type { Attribute } from '../Attribute';\nimport type { Index, IndexQuery, IndexStats } from './types';\nimport type { ResultSet } from '../resultset/ResultSet';\nimport { SetResultSet } from '../resultset/SetResultSet';\nimport { TokenizationPipeline } from '../tokenization';\n\n/**\n * Extended statistics for InvertedIndex.\n */\nexport interface InvertedIndexStats extends IndexStats {\n /** Total unique tokens in the index */\n totalTokens: number;\n /** Average number of tokens per indexed document */\n avgTokensPerDocument: number;\n /** Maximum documents for any single token */\n maxDocumentsPerToken: number;\n}\n\n/**\n * Inverted index for full-text search.\n * Maps tokens to sets of document keys for O(K) query performance.\n *\n * K = record key type, V = record value type, A = attribute value type (should be string)\n */\nexport class InvertedIndex<K, V, A extends string = string> implements Index<K, V, A> {\n readonly type = 'inverted' as const;\n\n /** Token → Set of keys */\n private tokenIndex: Map<string, Set<K>> = new Map();\n\n /** Key → Set of tokens (for efficient removal/update) */\n private reverseIndex: Map<K, Set<string>> = new Map();\n\n /** All keys with indexed content */\n private allKeys: Set<K> = new Set();\n\n private static readonly RETRIEVAL_COST = 50;\n private static readonly SUPPORTED_QUERIES = ['contains', 'containsAll', 'containsAny', 'has'];\n\n /**\n * Create an InvertedIndex.\n *\n * @param attribute - Attribute to index (should return string values)\n * @param pipeline - Tokenization pipeline (default: simple pipeline)\n */\n constructor(\n readonly attribute: Attribute<V, A>,\n private readonly pipeline: TokenizationPipeline = TokenizationPipeline.simple()\n ) {}\n\n getRetrievalCost(): number {\n return InvertedIndex.RETRIEVAL_COST;\n }\n\n supportsQuery(queryType: string): boolean {\n return InvertedIndex.SUPPORTED_QUERIES.includes(queryType);\n }\n\n retrieve(query: IndexQuery<A>): ResultSet<K> {\n switch (query.type) {\n case 'contains':\n return this.retrieveContains(query.value as A);\n case 'containsAll':\n return this.retrieveContainsAll(query.values as A[]);\n case 'containsAny':\n return this.retrieveContainsAny(query.values as A[]);\n case 'has':\n return this.retrieveHas();\n default:\n throw new Error(`InvertedIndex does not support query type: ${query.type}`);\n }\n }\n\n /**\n * Retrieve documents containing all tokens from the search text.\n * Uses AND semantics - document must contain ALL tokens.\n */\n private retrieveContains(searchText: A): ResultSet<K> {\n if (!searchText) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n const searchTokens = this.pipeline.process(String(searchText));\n if (searchTokens.length === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n // Sort tokens by frequency (ascending) for efficient intersection\n const sortedTokens = [...searchTokens].sort((a, b) => {\n const sizeA = this.tokenIndex.get(a)?.size ?? 0;\n const sizeB = this.tokenIndex.get(b)?.size ?? 0;\n return sizeA - sizeB;\n });\n\n // Start with smallest set\n const firstTokenKeys = this.tokenIndex.get(sortedTokens[0]);\n if (!firstTokenKeys || firstTokenKeys.size === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n const result = new Set(firstTokenKeys);\n\n // Intersect with remaining tokens\n for (let i = 1; i < sortedTokens.length; i++) {\n const tokenKeys = this.tokenIndex.get(sortedTokens[i]);\n if (!tokenKeys || tokenKeys.size === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n for (const key of result) {\n if (!tokenKeys.has(key)) {\n result.delete(key);\n }\n }\n\n if (result.size === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n }\n\n return new SetResultSet(result, InvertedIndex.RETRIEVAL_COST);\n }\n\n /**\n * Retrieve documents containing ALL specified values.\n * Each value is tokenized, and ALL resulting tokens must match.\n */\n private retrieveContainsAll(values: A[]): ResultSet<K> {\n if (!values || values.length === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n // Collect all tokens from all values\n const allTokens = new Set<string>();\n for (const value of values) {\n const tokens = this.pipeline.process(String(value));\n tokens.forEach((t) => allTokens.add(t));\n }\n\n if (allTokens.size === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n // Sort tokens by frequency for efficient intersection\n const sortedTokens = [...allTokens].sort((a, b) => {\n const sizeA = this.tokenIndex.get(a)?.size ?? 0;\n const sizeB = this.tokenIndex.get(b)?.size ?? 0;\n return sizeA - sizeB;\n });\n\n // Start with smallest set\n const firstTokenKeys = this.tokenIndex.get(sortedTokens[0]);\n if (!firstTokenKeys || firstTokenKeys.size === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n const result = new Set(firstTokenKeys);\n\n // Intersect with remaining tokens\n for (let i = 1; i < sortedTokens.length; i++) {\n const tokenKeys = this.tokenIndex.get(sortedTokens[i]);\n if (!tokenKeys || tokenKeys.size === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n for (const key of result) {\n if (!tokenKeys.has(key)) {\n result.delete(key);\n }\n }\n\n if (result.size === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n }\n\n return new SetResultSet(result, InvertedIndex.RETRIEVAL_COST);\n }\n\n /**\n * Retrieve documents containing ANY of the specified values.\n * Uses OR semantics - document can contain any token from any value.\n */\n private retrieveContainsAny(values: A[]): ResultSet<K> {\n if (!values || values.length === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n const result = new Set<K>();\n\n for (const value of values) {\n const tokens = this.pipeline.process(String(value));\n for (const token of tokens) {\n const keys = this.tokenIndex.get(token);\n if (keys) {\n for (const key of keys) {\n result.add(key);\n }\n }\n }\n }\n\n return new SetResultSet(result, InvertedIndex.RETRIEVAL_COST);\n }\n\n /**\n * Retrieve all documents with indexed content.\n */\n private retrieveHas(): ResultSet<K> {\n return new SetResultSet(new Set(this.allKeys), InvertedIndex.RETRIEVAL_COST);\n }\n\n // ==================== Index Operations ====================\n\n add(key: K, record: V): void {\n const values = this.attribute.getValues(record);\n if (values.length === 0) return;\n\n const allTokens = new Set<string>();\n\n // Tokenize all attribute values\n for (const value of values) {\n if (value === undefined || value === null) continue;\n const tokens = this.pipeline.process(String(value));\n tokens.forEach((t) => allTokens.add(t));\n }\n\n if (allTokens.size === 0) return;\n\n // Add to token index\n for (const token of allTokens) {\n let keys = this.tokenIndex.get(token);\n if (!keys) {\n keys = new Set();\n this.tokenIndex.set(token, keys);\n }\n keys.add(key);\n }\n\n // Add to reverse index\n this.reverseIndex.set(key, allTokens);\n this.allKeys.add(key);\n }\n\n remove(key: K, _record: V): void {\n const tokens = this.reverseIndex.get(key);\n if (!tokens) return;\n\n // Remove from token index\n for (const token of tokens) {\n const keys = this.tokenIndex.get(token);\n if (keys) {\n keys.delete(key);\n if (keys.size === 0) {\n this.tokenIndex.delete(token);\n }\n }\n }\n\n // Remove from reverse index\n this.reverseIndex.delete(key);\n this.allKeys.delete(key);\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n // Get old and new values\n const oldValues = this.attribute.getValues(oldRecord);\n const newValues = this.attribute.getValues(newRecord);\n\n // Quick check: if values are same, skip\n if (this.valuesEqual(oldValues, newValues)) {\n return;\n }\n\n // Full re-index\n this.remove(key, oldRecord);\n this.add(key, newRecord);\n }\n\n clear(): void {\n this.tokenIndex.clear();\n this.reverseIndex.clear();\n this.allKeys.clear();\n }\n\n // ==================== Statistics ====================\n\n getStats(): IndexStats {\n return {\n distinctValues: this.tokenIndex.size,\n totalEntries: this.allKeys.size,\n avgEntriesPerValue:\n this.tokenIndex.size > 0 ? this.allKeys.size / this.tokenIndex.size : 0,\n };\n }\n\n /**\n * Get extended statistics for full-text index.\n */\n getExtendedStats(): InvertedIndexStats {\n let maxDocuments = 0;\n let totalTokensPerDoc = 0;\n\n for (const keys of this.tokenIndex.values()) {\n if (keys.size > maxDocuments) {\n maxDocuments = keys.size;\n }\n }\n\n for (const tokens of this.reverseIndex.values()) {\n totalTokensPerDoc += tokens.size;\n }\n\n return {\n ...this.getStats(),\n totalTokens: this.tokenIndex.size,\n avgTokensPerDocument:\n this.reverseIndex.size > 0 ? totalTokensPerDoc / this.reverseIndex.size : 0,\n maxDocumentsPerToken: maxDocuments,\n };\n }\n\n /**\n * Get the tokenization pipeline.\n */\n getPipeline(): TokenizationPipeline {\n return this.pipeline;\n }\n\n /**\n * Check if a specific token exists in the index.\n */\n hasToken(token: string): boolean {\n return this.tokenIndex.has(token);\n }\n\n /**\n * Get the number of documents for a specific token.\n */\n getTokenDocumentCount(token: string): number {\n return this.tokenIndex.get(token)?.size ?? 0;\n }\n\n // ==================== Private Helpers ====================\n\n private valuesEqual(a: A[], b: A[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n }\n}\n","/**\n * CompoundIndex Implementation (Phase 9.03)\n *\n * Multi-attribute index for optimizing AND queries.\n * Creates a composite key from multiple attribute values for O(1) lookup.\n *\n * Benefits:\n * - 100-1000× speedup for compound AND queries\n * - Eliminates ResultSet intersection overhead\n * - Single lookup instead of multiple index scans\n *\n * @module query/indexes/CompoundIndex\n */\n\nimport type { Attribute } from '../Attribute';\nimport type { Index, IndexQuery, IndexStats } from './types';\nimport type { ResultSet } from '../resultset/ResultSet';\nimport { SetResultSet } from '../resultset/SetResultSet';\n\n/**\n * Compound query specification for multi-attribute matching.\n */\nexport interface CompoundQuery<A = unknown> {\n /** Query type - only 'compound' for compound indexes */\n type: 'compound';\n /** Array of attribute values in order of compound index attributes */\n values: A[];\n}\n\n/**\n * Options for compound index creation.\n */\nexport interface CompoundIndexOptions {\n /**\n * Separator for composite key generation.\n * Default: '|'\n * Choose a separator that won't appear in attribute values.\n */\n separator?: string;\n}\n\n/**\n * Compound index for O(1) multi-attribute queries.\n * Indexes multiple attributes as a single composite key.\n *\n * K = record key type, V = record value type\n */\nexport class CompoundIndex<K, V> implements Index<K, V, unknown> {\n readonly type = 'compound' as const;\n\n /** Attributes that make up this compound index (in order) */\n private readonly _attributes: Attribute<V, unknown>[];\n\n /** Map from composite key to set of record keys */\n private data: Map<string, Set<K>> = new Map();\n\n /** Set of all indexed keys */\n private allKeys: Set<K> = new Set();\n\n /** Key separator */\n private readonly separator: string;\n\n /** Retrieval cost (lower than individual indexes combined) */\n private static readonly RETRIEVAL_COST = 20;\n\n /**\n * Create a CompoundIndex.\n *\n * @param attributes - Array of attributes to index (order matters!)\n * @param options - Optional configuration\n *\n * @example\n * ```typescript\n * const statusAttr = simpleAttribute<Product, string>('status', p => p.status);\n * const categoryAttr = simpleAttribute<Product, string>('category', p => p.category);\n *\n * const compoundIndex = new CompoundIndex<string, Product>([statusAttr, categoryAttr]);\n * ```\n */\n constructor(\n attributes: Attribute<V, unknown>[],\n options: CompoundIndexOptions = {}\n ) {\n if (attributes.length < 2) {\n throw new Error('CompoundIndex requires at least 2 attributes');\n }\n this._attributes = attributes;\n this.separator = options.separator ?? '|';\n }\n\n /**\n * Get the first attribute (used for Index interface compatibility).\n * Note: CompoundIndex spans multiple attributes.\n */\n get attribute(): Attribute<V, unknown> {\n return this._attributes[0];\n }\n\n /**\n * Get all attributes in this compound index.\n */\n get attributes(): Attribute<V, unknown>[] {\n return [...this._attributes];\n }\n\n /**\n * Get attribute names as a combined identifier.\n */\n get compoundName(): string {\n return this._attributes.map((a) => a.name).join('+');\n }\n\n getRetrievalCost(): number {\n return CompoundIndex.RETRIEVAL_COST;\n }\n\n supportsQuery(queryType: string): boolean {\n return queryType === 'compound';\n }\n\n /**\n * Retrieve records matching compound query.\n *\n * @param query - Compound query with values matching each attribute\n * @returns ResultSet of matching keys\n *\n * @example\n * ```typescript\n * // Find products where status='active' AND category='electronics'\n * index.retrieve({\n * type: 'compound',\n * values: ['active', 'electronics']\n * });\n * ```\n */\n retrieve(query: IndexQuery<unknown>): ResultSet<K> {\n if (query.type !== 'compound') {\n throw new Error(`CompoundIndex only supports 'compound' query type, got: ${query.type}`);\n }\n\n const compoundQuery = query as unknown as CompoundQuery;\n const values = compoundQuery.values;\n\n if (values.length !== this._attributes.length) {\n throw new Error(\n `CompoundIndex requires ${this._attributes.length} values, got ${values.length}`\n );\n }\n\n const compositeKey = this.buildCompositeKey(values);\n const keys = this.data.get(compositeKey);\n\n return new SetResultSet(\n keys ? new Set(keys) : new Set(),\n CompoundIndex.RETRIEVAL_COST\n );\n }\n\n /**\n * Retrieve with explicit values (convenience method).\n *\n * @param values - Values in order of index attributes\n * @returns ResultSet of matching keys\n */\n retrieveByValues(...values: unknown[]): ResultSet<K> {\n return this.retrieve({ type: 'compound', values } as IndexQuery<unknown>);\n }\n\n add(key: K, record: V): void {\n const compositeKey = this.buildCompositeKeyFromRecord(record);\n if (compositeKey === null) return;\n\n let keys = this.data.get(compositeKey);\n if (!keys) {\n keys = new Set();\n this.data.set(compositeKey, keys);\n }\n keys.add(key);\n this.allKeys.add(key);\n }\n\n remove(key: K, record: V): void {\n const compositeKey = this.buildCompositeKeyFromRecord(record);\n if (compositeKey === null) return;\n\n const keys = this.data.get(compositeKey);\n if (keys) {\n keys.delete(key);\n if (keys.size === 0) {\n this.data.delete(compositeKey);\n }\n }\n this.allKeys.delete(key);\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n const oldKey = this.buildCompositeKeyFromRecord(oldRecord);\n const newKey = this.buildCompositeKeyFromRecord(newRecord);\n\n // Optimize: check if composite key changed\n if (oldKey === newKey) {\n return;\n }\n\n this.remove(key, oldRecord);\n this.add(key, newRecord);\n }\n\n clear(): void {\n this.data.clear();\n this.allKeys.clear();\n }\n\n getStats(): IndexStats {\n let totalEntries = 0;\n for (const keys of this.data.values()) {\n totalEntries += keys.size;\n }\n\n return {\n distinctValues: this.data.size,\n totalEntries,\n avgEntriesPerValue: this.data.size > 0 ? totalEntries / this.data.size : 0,\n };\n }\n\n /**\n * Get extended statistics for compound index.\n */\n getExtendedStats(): CompoundIndexStats {\n const stats = this.getStats();\n return {\n ...stats,\n attributeCount: this._attributes.length,\n attributeNames: this._attributes.map((a) => a.name),\n compositeKeyCount: this.data.size,\n };\n }\n\n /**\n * Check if this compound index can answer a query on the given attributes.\n * Compound indexes can be used if query attributes match in prefix order.\n *\n * @param attributeNames - Attribute names being queried\n * @returns true if this index can answer the query\n */\n canAnswerQuery(attributeNames: string[]): boolean {\n if (attributeNames.length !== this._attributes.length) {\n return false;\n }\n\n // Check if all attribute names match (order matters for now)\n for (let i = 0; i < attributeNames.length; i++) {\n if (attributeNames[i] !== this._attributes[i].name) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Build composite key from array of values.\n */\n private buildCompositeKey(values: unknown[]): string {\n return values.map((v) => this.encodeValue(v)).join(this.separator);\n }\n\n /**\n * Build composite key from record by extracting attribute values.\n * Returns null if any attribute value is undefined.\n */\n private buildCompositeKeyFromRecord(record: V): string | null {\n const values: unknown[] = [];\n\n for (const attr of this._attributes) {\n const value = attr.getValue(record);\n if (value === undefined) {\n return null; // Can't index record with missing attribute\n }\n values.push(value);\n }\n\n return this.buildCompositeKey(values);\n }\n\n /**\n * Encode value for composite key.\n * Handles common types and escapes separator.\n */\n private encodeValue(value: unknown): string {\n if (value === null) return '__null__';\n if (value === undefined) return '__undefined__';\n\n const str = String(value);\n // Escape any separator characters in the value\n return str.replace(\n new RegExp(this.escapeRegex(this.separator), 'g'),\n `\\\\${this.separator}`\n );\n }\n\n /**\n * Escape regex special characters.\n */\n private escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n }\n}\n\n/**\n * Extended statistics for compound index.\n */\nexport interface CompoundIndexStats extends IndexStats {\n /** Number of attributes in compound key */\n attributeCount: number;\n /** Names of indexed attributes */\n attributeNames: string[];\n /** Number of unique composite keys */\n compositeKeyCount: number;\n}\n\n/**\n * Helper to check if an index is a compound index.\n */\nexport function isCompoundIndex<K, V>(index: Index<K, V, unknown>): index is CompoundIndex<K, V> {\n return index.type === 'compound';\n}\n","/**\n * LazyHashIndex Implementation\n *\n * Hash-based index with deferred building (Phase 9.01).\n * Records are buffered until first query, then index is materialized.\n *\n * Benefits:\n * - Fast application startup (indexes built on-demand)\n * - Memory efficiency (unused indexes not built)\n * - Bulk import optimization (no index overhead during import)\n *\n * @module query/indexes/lazy/LazyHashIndex\n */\n\nimport type { Attribute } from '../../Attribute';\nimport type { Index, IndexQuery, IndexStats } from '../types';\nimport type { ResultSet } from '../../resultset/ResultSet';\nimport { HashIndex } from '../HashIndex';\nimport type { LazyIndex, LazyIndexOptions } from './types';\nimport type { IndexBuildProgressCallback } from '../../adaptive/types';\n\n/**\n * Lazy hash-based index for O(1) equality lookups.\n * Defers index construction until first query.\n *\n * K = record key type, V = record value type, A = attribute value type\n */\nexport class LazyHashIndex<K, V, A> implements LazyIndex<K, V, A> {\n readonly type = 'hash' as const;\n readonly isLazy = true as const;\n\n /** Underlying hash index (created on first query) */\n private innerIndex: HashIndex<K, V, A> | null = null;\n\n /** Pending records before materialization */\n private pendingRecords: Map<K, V> = new Map();\n\n /** Track if index has been built */\n private built = false;\n\n /** Progress callback */\n private readonly onProgress?: IndexBuildProgressCallback;\n\n /** Batch size for progress reporting */\n private readonly progressBatchSize: number;\n\n constructor(\n readonly attribute: Attribute<V, A>,\n options: LazyIndexOptions = {}\n ) {\n this.onProgress = options.onProgress;\n this.progressBatchSize = options.progressBatchSize ?? 1000;\n }\n\n get isBuilt(): boolean {\n return this.built;\n }\n\n get pendingCount(): number {\n return this.pendingRecords.size;\n }\n\n getRetrievalCost(): number {\n // Return HashIndex cost\n return 30;\n }\n\n supportsQuery(queryType: string): boolean {\n return ['equal', 'in', 'has'].includes(queryType);\n }\n\n retrieve(query: IndexQuery<A>): ResultSet<K> {\n // Materialize on first query\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.retrieve(query);\n }\n\n add(key: K, record: V): void {\n if (this.built) {\n this.innerIndex!.add(key, record);\n } else {\n this.pendingRecords.set(key, record);\n }\n }\n\n remove(key: K, record: V): void {\n if (this.built) {\n this.innerIndex!.remove(key, record);\n } else {\n this.pendingRecords.delete(key);\n }\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n if (this.built) {\n this.innerIndex!.update(key, oldRecord, newRecord);\n } else {\n // Just update pending record\n this.pendingRecords.set(key, newRecord);\n }\n }\n\n clear(): void {\n if (this.built) {\n this.innerIndex!.clear();\n }\n this.pendingRecords.clear();\n }\n\n getStats(): IndexStats {\n if (this.built) {\n return this.innerIndex!.getStats();\n }\n // Return pending stats\n return {\n distinctValues: 0,\n totalEntries: this.pendingRecords.size,\n avgEntriesPerValue: 0,\n };\n }\n\n /**\n * Force materialization of the index.\n * Called automatically on first query.\n */\n materialize(progressCallback?: IndexBuildProgressCallback): void {\n if (this.built) return;\n\n const callback = progressCallback ?? this.onProgress;\n const total = this.pendingRecords.size;\n\n // Create inner index\n this.innerIndex = new HashIndex<K, V, A>(this.attribute);\n\n // Build from pending records\n let processed = 0;\n for (const [key, record] of this.pendingRecords) {\n this.innerIndex.add(key, record);\n processed++;\n\n // Report progress\n if (callback && processed % this.progressBatchSize === 0) {\n const progress = Math.round((processed / total) * 100);\n callback(this.attribute.name, progress, processed, total);\n }\n }\n\n // Final progress report\n if (callback && total > 0) {\n callback(this.attribute.name, 100, total, total);\n }\n\n // Clear pending and mark as built\n this.pendingRecords.clear();\n this.built = true;\n }\n\n /**\n * Get the underlying HashIndex (for testing/debugging).\n * Returns null if not yet materialized.\n */\n getInnerIndex(): HashIndex<K, V, A> | null {\n return this.innerIndex;\n }\n}\n","/**\n * LazyNavigableIndex Implementation\n *\n * Sorted index with deferred building (Phase 9.01).\n * Records are buffered until first query, then index is materialized.\n *\n * Benefits:\n * - Fast application startup (indexes built on-demand)\n * - Memory efficiency (unused indexes not built)\n * - Bulk import optimization (no index overhead during import)\n *\n * @module query/indexes/lazy/LazyNavigableIndex\n */\n\nimport type { Attribute } from '../../Attribute';\nimport type { Index, IndexQuery, IndexStats } from '../types';\nimport type { ResultSet } from '../../resultset/ResultSet';\nimport type { Comparator } from '../../ds/types';\nimport { NavigableIndex } from '../NavigableIndex';\nimport type { LazyIndex, LazyIndexOptions } from './types';\nimport type { IndexBuildProgressCallback } from '../../adaptive/types';\n\n/**\n * Lazy sorted index for O(log N) range queries.\n * Defers index construction until first query.\n *\n * K = record key type, V = record value type, A = attribute value type (must be orderable)\n */\nexport class LazyNavigableIndex<K, V, A extends string | number>\n implements LazyIndex<K, V, A>\n{\n readonly type = 'navigable' as const;\n readonly isLazy = true as const;\n\n /** Underlying navigable index (created on first query) */\n private innerIndex: NavigableIndex<K, V, A> | null = null;\n\n /** Pending records before materialization */\n private pendingRecords: Map<K, V> = new Map();\n\n /** Track if index has been built */\n private built = false;\n\n /** Custom comparator (stored for later index creation) */\n private readonly comparator?: Comparator<A>;\n\n /** Progress callback */\n private readonly onProgress?: IndexBuildProgressCallback;\n\n /** Batch size for progress reporting */\n private readonly progressBatchSize: number;\n\n constructor(\n readonly attribute: Attribute<V, A>,\n comparator?: Comparator<A>,\n options: LazyIndexOptions = {}\n ) {\n this.comparator = comparator;\n this.onProgress = options.onProgress;\n this.progressBatchSize = options.progressBatchSize ?? 1000;\n }\n\n get isBuilt(): boolean {\n return this.built;\n }\n\n get pendingCount(): number {\n return this.pendingRecords.size;\n }\n\n getRetrievalCost(): number {\n // Return NavigableIndex cost\n return 40;\n }\n\n supportsQuery(queryType: string): boolean {\n return ['equal', 'in', 'has', 'gt', 'gte', 'lt', 'lte', 'between'].includes(queryType);\n }\n\n retrieve(query: IndexQuery<A>): ResultSet<K> {\n // Materialize on first query\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.retrieve(query);\n }\n\n add(key: K, record: V): void {\n if (this.built) {\n this.innerIndex!.add(key, record);\n } else {\n this.pendingRecords.set(key, record);\n }\n }\n\n remove(key: K, record: V): void {\n if (this.built) {\n this.innerIndex!.remove(key, record);\n } else {\n this.pendingRecords.delete(key);\n }\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n if (this.built) {\n this.innerIndex!.update(key, oldRecord, newRecord);\n } else {\n // Just update pending record\n this.pendingRecords.set(key, newRecord);\n }\n }\n\n clear(): void {\n if (this.built) {\n this.innerIndex!.clear();\n }\n this.pendingRecords.clear();\n }\n\n getStats(): IndexStats {\n if (this.built) {\n return this.innerIndex!.getStats();\n }\n // Return pending stats\n return {\n distinctValues: 0,\n totalEntries: this.pendingRecords.size,\n avgEntriesPerValue: 0,\n };\n }\n\n /**\n * Force materialization of the index.\n * Called automatically on first query.\n */\n materialize(progressCallback?: IndexBuildProgressCallback): void {\n if (this.built) return;\n\n const callback = progressCallback ?? this.onProgress;\n const total = this.pendingRecords.size;\n\n // Create inner index with comparator\n this.innerIndex = new NavigableIndex<K, V, A>(this.attribute, this.comparator);\n\n // Build from pending records\n let processed = 0;\n for (const [key, record] of this.pendingRecords) {\n this.innerIndex.add(key, record);\n processed++;\n\n // Report progress\n if (callback && processed % this.progressBatchSize === 0) {\n const progress = Math.round((processed / total) * 100);\n callback(this.attribute.name, progress, processed, total);\n }\n }\n\n // Final progress report\n if (callback && total > 0) {\n callback(this.attribute.name, 100, total, total);\n }\n\n // Clear pending and mark as built\n this.pendingRecords.clear();\n this.built = true;\n }\n\n /**\n * Get the underlying NavigableIndex (for testing/debugging).\n * Returns null if not yet materialized.\n */\n getInnerIndex(): NavigableIndex<K, V, A> | null {\n return this.innerIndex;\n }\n\n /**\n * Get the minimum indexed value.\n * Forces materialization if not built.\n */\n getMinValue(): A | undefined {\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.getMinValue();\n }\n\n /**\n * Get the maximum indexed value.\n * Forces materialization if not built.\n */\n getMaxValue(): A | undefined {\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.getMaxValue();\n }\n}\n","/**\n * LazyInvertedIndex Implementation\n *\n * Full-text search index with deferred building (Phase 9.01).\n * Records are buffered until first query, then index is materialized.\n *\n * Benefits:\n * - Fast application startup (indexes built on-demand)\n * - Memory efficiency (unused indexes not built)\n * - Bulk import optimization (no index overhead during import)\n *\n * @module query/indexes/lazy/LazyInvertedIndex\n */\n\nimport type { Attribute } from '../../Attribute';\nimport type { Index, IndexQuery, IndexStats } from '../types';\nimport type { ResultSet } from '../../resultset/ResultSet';\nimport { InvertedIndex, type InvertedIndexStats } from '../InvertedIndex';\nimport { TokenizationPipeline } from '../../tokenization';\nimport type { LazyIndex, LazyIndexOptions } from './types';\nimport type { IndexBuildProgressCallback } from '../../adaptive/types';\n\n/**\n * Lazy inverted index for full-text search.\n * Defers index construction until first query.\n *\n * K = record key type, V = record value type, A = attribute value type (should be string)\n */\nexport class LazyInvertedIndex<K, V, A extends string = string>\n implements LazyIndex<K, V, A>\n{\n readonly type = 'inverted' as const;\n readonly isLazy = true as const;\n\n /** Underlying inverted index (created on first query) */\n private innerIndex: InvertedIndex<K, V, A> | null = null;\n\n /** Pending records before materialization */\n private pendingRecords: Map<K, V> = new Map();\n\n /** Track if index has been built */\n private built = false;\n\n /** Tokenization pipeline (stored for later index creation) */\n private readonly pipeline: TokenizationPipeline;\n\n /** Progress callback */\n private readonly onProgress?: IndexBuildProgressCallback;\n\n /** Batch size for progress reporting */\n private readonly progressBatchSize: number;\n\n constructor(\n readonly attribute: Attribute<V, A>,\n pipeline?: TokenizationPipeline,\n options: LazyIndexOptions = {}\n ) {\n this.pipeline = pipeline ?? TokenizationPipeline.simple();\n this.onProgress = options.onProgress;\n this.progressBatchSize = options.progressBatchSize ?? 1000;\n }\n\n get isBuilt(): boolean {\n return this.built;\n }\n\n get pendingCount(): number {\n return this.pendingRecords.size;\n }\n\n getRetrievalCost(): number {\n // Return InvertedIndex cost\n return 50;\n }\n\n supportsQuery(queryType: string): boolean {\n return ['contains', 'containsAll', 'containsAny', 'has'].includes(queryType);\n }\n\n retrieve(query: IndexQuery<A>): ResultSet<K> {\n // Materialize on first query\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.retrieve(query);\n }\n\n add(key: K, record: V): void {\n if (this.built) {\n this.innerIndex!.add(key, record);\n } else {\n this.pendingRecords.set(key, record);\n }\n }\n\n remove(key: K, record: V): void {\n if (this.built) {\n this.innerIndex!.remove(key, record);\n } else {\n this.pendingRecords.delete(key);\n }\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n if (this.built) {\n this.innerIndex!.update(key, oldRecord, newRecord);\n } else {\n // Just update pending record\n this.pendingRecords.set(key, newRecord);\n }\n }\n\n clear(): void {\n if (this.built) {\n this.innerIndex!.clear();\n }\n this.pendingRecords.clear();\n }\n\n getStats(): IndexStats {\n if (this.built) {\n return this.innerIndex!.getStats();\n }\n // Return pending stats\n return {\n distinctValues: 0,\n totalEntries: this.pendingRecords.size,\n avgEntriesPerValue: 0,\n };\n }\n\n /**\n * Get extended statistics for full-text index.\n * Forces materialization if not built.\n */\n getExtendedStats(): InvertedIndexStats {\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.getExtendedStats();\n }\n\n /**\n * Force materialization of the index.\n * Called automatically on first query.\n */\n materialize(progressCallback?: IndexBuildProgressCallback): void {\n if (this.built) return;\n\n const callback = progressCallback ?? this.onProgress;\n const total = this.pendingRecords.size;\n\n // Create inner index with pipeline\n this.innerIndex = new InvertedIndex<K, V, A>(this.attribute, this.pipeline);\n\n // Build from pending records\n let processed = 0;\n for (const [key, record] of this.pendingRecords) {\n this.innerIndex.add(key, record);\n processed++;\n\n // Report progress\n if (callback && processed % this.progressBatchSize === 0) {\n const progress = Math.round((processed / total) * 100);\n callback(this.attribute.name, progress, processed, total);\n }\n }\n\n // Final progress report\n if (callback && total > 0) {\n callback(this.attribute.name, 100, total, total);\n }\n\n // Clear pending and mark as built\n this.pendingRecords.clear();\n this.built = true;\n }\n\n /**\n * Get the underlying InvertedIndex (for testing/debugging).\n * Returns null if not yet materialized.\n */\n getInnerIndex(): InvertedIndex<K, V, A> | null {\n return this.innerIndex;\n }\n\n /**\n * Get the tokenization pipeline.\n */\n getPipeline(): TokenizationPipeline {\n return this.pipeline;\n }\n\n /**\n * Check if a specific token exists in the index.\n * Forces materialization if not built.\n */\n hasToken(token: string): boolean {\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.hasToken(token);\n }\n\n /**\n * Get the number of documents for a specific token.\n * Forces materialization if not built.\n */\n getTokenDocumentCount(token: string): number {\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.getTokenDocumentCount(token);\n }\n}\n","/**\n * IntersectionResultSet Implementation\n *\n * Intersection of multiple result sets (AND logic).\n * Implements CQEngine \"smallest first\" strategy:\n * iterate the smallest set, check membership in others.\n *\n * @module query/resultset/IntersectionResultSet\n */\n\nimport type { ResultSet } from './ResultSet';\n\n/**\n * Intersection of multiple result sets (AND logic).\n * CQEngine strategy: iterate smallest set, check membership in others.\n *\n * K = record key type\n */\nexport class IntersectionResultSet<K> implements ResultSet<K> {\n /** Cached materialized results */\n private cached: K[] | null = null;\n\n /** Result sets sorted by merge cost */\n private sortedResultSets: ResultSet<K>[];\n\n /**\n * Create an IntersectionResultSet.\n *\n * @param resultSets - Result sets to intersect\n */\n constructor(resultSets: ResultSet<K>[]) {\n // Sort by merge cost (ascending) - iterate smallest first\n this.sortedResultSets = [...resultSets].sort(\n (a, b) => a.getMergeCost() - b.getMergeCost()\n );\n }\n\n /**\n * Lazy iteration over intersection.\n * Iterates smallest set, yields only keys present in all sets.\n */\n *[Symbol.iterator](): Generator<K> {\n // Use cached results if available\n if (this.cached) {\n yield* this.cached;\n return;\n }\n\n // Empty intersection if no result sets\n if (this.sortedResultSets.length === 0) {\n return;\n }\n\n // Get smallest set (first after sort)\n const [smallest, ...rest] = this.sortedResultSets;\n\n // Iterate smallest, check membership in all others\n for (const key of smallest) {\n if (rest.every((rs) => rs.contains(key))) {\n yield key;\n }\n }\n }\n\n /**\n * Retrieval cost is minimum of all (we only iterate smallest).\n */\n getRetrievalCost(): number {\n if (this.sortedResultSets.length === 0) {\n return 0;\n }\n return Math.min(...this.sortedResultSets.map((rs) => rs.getRetrievalCost()));\n }\n\n /**\n * Merge cost is estimated as smallest set size (upper bound).\n */\n getMergeCost(): number {\n if (this.sortedResultSets.length === 0) {\n return 0;\n }\n // After sorting, first has smallest merge cost\n return this.sortedResultSets[0].getMergeCost();\n }\n\n /**\n * Check if key is in all result sets.\n */\n contains(key: K): boolean {\n return this.sortedResultSets.every((rs) => rs.contains(key));\n }\n\n /**\n * Get size by materializing results.\n */\n size(): number {\n return this.toArray().length;\n }\n\n /**\n * Materialize to array with caching.\n */\n toArray(): K[] {\n if (!this.cached) {\n this.cached = [...this];\n }\n return this.cached;\n }\n\n /**\n * Check if empty (tries to avoid full materialization).\n */\n isEmpty(): boolean {\n // If cached, use cached value\n if (this.cached) {\n return this.cached.length === 0;\n }\n\n // If any source is empty, intersection is empty\n if (this.sortedResultSets.some((rs) => rs.isEmpty())) {\n return true;\n }\n\n // Check by trying to get first element\n for (const _ of this) {\n return false;\n }\n return true;\n }\n\n /**\n * Check if results have been materialized.\n */\n isMaterialized(): boolean {\n return this.cached !== null;\n }\n}\n","/**\n * UnionResultSet Implementation\n *\n * Union of multiple result sets (OR logic).\n * Deduplicates results using a Set during iteration.\n *\n * @module query/resultset/UnionResultSet\n */\n\nimport type { ResultSet } from './ResultSet';\n\n/**\n * Union of multiple result sets (OR logic).\n * Deduplicates results.\n *\n * K = record key type\n */\nexport class UnionResultSet<K> implements ResultSet<K> {\n /** Cached materialized results */\n private cached: K[] | null = null;\n\n /**\n * Create a UnionResultSet.\n *\n * @param resultSets - Result sets to union\n */\n constructor(private readonly resultSets: ResultSet<K>[]) {}\n\n /**\n * Lazy iteration over union with deduplication.\n */\n *[Symbol.iterator](): Generator<K> {\n // Use cached results if available\n if (this.cached) {\n yield* this.cached;\n return;\n }\n\n // Track seen keys to avoid duplicates\n const seen = new Set<K>();\n\n for (const rs of this.resultSets) {\n for (const key of rs) {\n if (!seen.has(key)) {\n seen.add(key);\n yield key;\n }\n }\n }\n }\n\n /**\n * Retrieval cost is sum of all costs.\n */\n getRetrievalCost(): number {\n return this.resultSets.reduce((sum, rs) => {\n const cost = rs.getRetrievalCost();\n // Avoid overflow\n if (cost === Number.MAX_SAFE_INTEGER || sum === Number.MAX_SAFE_INTEGER) {\n return Number.MAX_SAFE_INTEGER;\n }\n return Math.min(sum + cost, Number.MAX_SAFE_INTEGER);\n }, 0);\n }\n\n /**\n * Merge cost upper bound: sum of all sizes.\n */\n getMergeCost(): number {\n return this.resultSets.reduce((sum, rs) => sum + rs.getMergeCost(), 0);\n }\n\n /**\n * Check if key is in any result set.\n */\n contains(key: K): boolean {\n return this.resultSets.some((rs) => rs.contains(key));\n }\n\n /**\n * Get size by materializing results.\n */\n size(): number {\n return this.toArray().length;\n }\n\n /**\n * Materialize to array with caching.\n */\n toArray(): K[] {\n if (!this.cached) {\n this.cached = [...this];\n }\n return this.cached;\n }\n\n /**\n * Check if empty (all sources must be empty).\n */\n isEmpty(): boolean {\n // If cached, use cached value\n if (this.cached) {\n return this.cached.length === 0;\n }\n\n // Union is empty only if all sources are empty\n return this.resultSets.every((rs) => rs.isEmpty());\n }\n\n /**\n * Check if results have been materialized.\n */\n isMaterialized(): boolean {\n return this.cached !== null;\n }\n}\n","/**\n * FilteringResultSet Implementation\n *\n * Filters a source result set with a predicate.\n * Used when an index is available for part of a query,\n * but additional filtering is needed.\n *\n * @module query/resultset/FilteringResultSet\n */\n\nimport type { ResultSet } from './ResultSet';\n\n/**\n * Predicate function for filtering records.\n */\nexport type PredicateFn<V> = (record: V) => boolean;\n\n/**\n * Filters a source result set with a predicate.\n *\n * K = record key type, V = record value type\n */\nexport class FilteringResultSet<K, V> implements ResultSet<K> {\n /** Cached materialized results */\n private cached: K[] | null = null;\n\n /**\n * Create a FilteringResultSet.\n *\n * @param source - Source result set to filter\n * @param getRecord - Function to get record by key\n * @param predicate - Predicate function to filter records\n */\n constructor(\n private readonly source: ResultSet<K>,\n private readonly getRecord: (key: K) => V | undefined,\n private readonly predicate: PredicateFn<V>\n ) {}\n\n /**\n * Lazy iteration with filtering.\n */\n *[Symbol.iterator](): Generator<K> {\n // Use cached results if available\n if (this.cached) {\n yield* this.cached;\n return;\n }\n\n for (const key of this.source) {\n const record = this.getRecord(key);\n if (record !== undefined && this.predicate(record)) {\n yield key;\n }\n }\n }\n\n /**\n * Retrieval cost: source cost + filter overhead.\n */\n getRetrievalCost(): number {\n return this.source.getRetrievalCost() + 10;\n }\n\n /**\n * Merge cost: estimate half of source (pessimistic).\n */\n getMergeCost(): number {\n return Math.max(1, Math.ceil(this.source.getMergeCost() / 2));\n }\n\n /**\n * Check if key is in source and passes predicate.\n */\n contains(key: K): boolean {\n if (!this.source.contains(key)) {\n return false;\n }\n const record = this.getRecord(key);\n return record !== undefined && this.predicate(record);\n }\n\n /**\n * Get size by materializing results.\n */\n size(): number {\n return this.toArray().length;\n }\n\n /**\n * Materialize to array with caching.\n */\n toArray(): K[] {\n if (!this.cached) {\n this.cached = [...this];\n }\n return this.cached;\n }\n\n /**\n * Check if empty (tries to find at least one match).\n */\n isEmpty(): boolean {\n // If cached, use cached value\n if (this.cached) {\n return this.cached.length === 0;\n }\n\n // Try to find at least one matching element\n for (const _ of this) {\n return false;\n }\n return true;\n }\n\n /**\n * Check if results have been materialized.\n */\n isMaterialized(): boolean {\n return this.cached !== null;\n }\n}\n","/**\n * SortedResultSet Implementation\n *\n * ResultSet with sorting support.\n * If source is from NavigableIndex on sort field, results are already sorted.\n * Otherwise, performs in-memory sort.\n *\n * @module query/resultset/SortedResultSet\n */\n\nimport type { ResultSet } from './ResultSet';\n\n/**\n * Comparator function for sorting.\n */\nexport type CompareFn<V> = (a: V, b: V) => number;\n\n/**\n * ResultSet with sorting support.\n *\n * K = record key type, V = record value type\n */\nexport class SortedResultSet<K, V> implements ResultSet<K> {\n /** Cached sorted results */\n private cached: K[] | null = null;\n\n /**\n * Create a SortedResultSet.\n *\n * @param source - Source result set\n * @param getRecord - Function to get record by key\n * @param sortField - Field to sort by\n * @param direction - Sort direction ('asc' or 'desc')\n * @param isPreSorted - Whether source is already sorted (from NavigableIndex)\n */\n constructor(\n private readonly source: ResultSet<K>,\n private readonly getRecord: (key: K) => V | undefined,\n private readonly sortField: string,\n private readonly direction: 'asc' | 'desc',\n private readonly isPreSorted: boolean = false\n ) {}\n\n /**\n * Lazy iteration with sorting.\n */\n *[Symbol.iterator](): Generator<K> {\n // Use cached results if available\n if (this.cached) {\n yield* this.cached;\n return;\n }\n\n // If pre-sorted (from NavigableIndex), handle direction\n if (this.isPreSorted) {\n if (this.direction === 'desc') {\n // Reverse iteration for descending\n const keys = [...this.source];\n for (let i = keys.length - 1; i >= 0; i--) {\n yield keys[i];\n }\n } else {\n // Forward iteration for ascending\n yield* this.source;\n }\n return;\n }\n\n // In-memory sort\n yield* this.toArray();\n }\n\n /**\n * Materialize to sorted array with caching.\n */\n toArray(): K[] {\n if (this.cached) {\n return this.cached;\n }\n\n const keys = [...this.source];\n\n if (!this.isPreSorted) {\n // In-memory sort\n keys.sort((a, b) => {\n const recA = this.getRecord(a);\n const recB = this.getRecord(b);\n\n if (recA === undefined && recB === undefined) return 0;\n if (recA === undefined) return this.direction === 'asc' ? 1 : -1;\n if (recB === undefined) return this.direction === 'asc' ? -1 : 1;\n\n const valA = (recA as Record<string, unknown>)[this.sortField];\n const valB = (recB as Record<string, unknown>)[this.sortField];\n\n let cmp = 0;\n if (valA === undefined || valA === null) {\n if (valB === undefined || valB === null) {\n cmp = 0;\n } else {\n cmp = 1;\n }\n } else if (valB === undefined || valB === null) {\n cmp = -1;\n } else if (valA < valB) {\n cmp = -1;\n } else if (valA > valB) {\n cmp = 1;\n }\n\n return this.direction === 'desc' ? -cmp : cmp;\n });\n } else if (this.direction === 'desc') {\n // Pre-sorted, just reverse for descending\n keys.reverse();\n }\n\n this.cached = keys;\n return keys;\n }\n\n /**\n * Retrieval cost: source cost + sort overhead.\n * Pre-sorted has minimal overhead.\n */\n getRetrievalCost(): number {\n const baseCost = this.source.getRetrievalCost();\n // Pre-sorted: minimal overhead\n // In-memory sort: O(N log N) overhead\n const sortOverhead = this.isPreSorted ? 1 : 50;\n return baseCost + sortOverhead;\n }\n\n /**\n * Merge cost: same as source (sorting doesn't change size).\n */\n getMergeCost(): number {\n return this.source.getMergeCost();\n }\n\n /**\n * Check if key is in source.\n */\n contains(key: K): boolean {\n return this.source.contains(key);\n }\n\n /**\n * Get size (same as source).\n */\n size(): number {\n return this.source.size();\n }\n\n /**\n * Check if empty.\n */\n isEmpty(): boolean {\n return this.source.isEmpty();\n }\n\n /**\n * Check if results have been materialized.\n */\n isMaterialized(): boolean {\n return this.cached !== null;\n }\n\n /**\n * Check if this result set is pre-sorted.\n */\n isIndexSorted(): boolean {\n return this.isPreSorted;\n }\n\n /**\n * Get sort field.\n */\n getSortField(): string {\n return this.sortField;\n }\n\n /**\n * Get sort direction.\n */\n getSortDirection(): 'asc' | 'desc' {\n return this.direction;\n }\n}\n\n/**\n * Create a comparator function for a field.\n *\n * @param field - Field name to compare\n * @param direction - Sort direction\n */\nexport function createFieldComparator<V>(\n field: string,\n direction: 'asc' | 'desc'\n): CompareFn<V> {\n return (a: V, b: V): number => {\n const valA = (a as Record<string, unknown>)[field];\n const valB = (b as Record<string, unknown>)[field];\n\n let cmp = 0;\n if (valA === undefined || valA === null) {\n if (valB === undefined || valB === null) {\n cmp = 0;\n } else {\n cmp = 1;\n }\n } else if (valB === undefined || valB === null) {\n cmp = -1;\n } else if (valA < valB) {\n cmp = -1;\n } else if (valA > valB) {\n cmp = 1;\n }\n\n // Avoid -0 result when cmp is 0\n if (cmp === 0) return 0;\n return direction === 'desc' ? -cmp : cmp;\n };\n}\n","/**\n * LimitResultSet Implementation\n *\n * Applies offset/limit to source ResultSet.\n * Implements early termination for efficiency.\n *\n * @module query/resultset/LimitResultSet\n */\n\nimport type { ResultSet } from './ResultSet';\n\n/**\n * Applies offset/limit to source ResultSet.\n * Implements early termination for efficiency.\n *\n * K = record key type\n */\nexport class LimitResultSet<K> implements ResultSet<K> {\n /** Cached materialized results */\n private cached: K[] | null = null;\n\n /**\n * Create a LimitResultSet.\n *\n * @param source - Source result set\n * @param offset - Number of results to skip (default: 0)\n * @param limit - Maximum number of results (default: Infinity)\n */\n constructor(\n private readonly source: ResultSet<K>,\n private readonly offset: number = 0,\n private readonly limit: number = Infinity\n ) {}\n\n /**\n * Lazy iteration with offset/limit and early termination.\n */\n *[Symbol.iterator](): Generator<K> {\n // Use cached results if available\n if (this.cached) {\n yield* this.cached;\n return;\n }\n\n // If no offset and no limit, just pass through\n if (this.offset === 0 && this.limit === Infinity) {\n yield* this.source;\n return;\n }\n\n let skipped = 0;\n let returned = 0;\n\n for (const key of this.source) {\n // Skip offset\n if (skipped < this.offset) {\n skipped++;\n continue;\n }\n\n // Early termination when limit reached\n if (returned >= this.limit) {\n break;\n }\n\n yield key;\n returned++;\n }\n }\n\n /**\n * Retrieval cost: source cost (limit doesn't change retrieval cost).\n */\n getRetrievalCost(): number {\n return this.source.getRetrievalCost();\n }\n\n /**\n * Merge cost: min(source size, offset + limit).\n */\n getMergeCost(): number {\n const sourceCost = this.source.getMergeCost();\n if (this.limit === Infinity) {\n return Math.max(0, sourceCost - this.offset);\n }\n return Math.min(sourceCost, this.offset + this.limit);\n }\n\n /**\n * Check if key is in result (with offset/limit constraints).\n * This is expensive as it requires iteration to determine position.\n */\n contains(key: K): boolean {\n // First check if key is in source at all\n if (!this.source.contains(key)) {\n return false;\n }\n\n // Need to materialize to check if key is within offset/limit\n return this.toArray().includes(key);\n }\n\n /**\n * Get size by materializing results.\n */\n size(): number {\n return this.toArray().length;\n }\n\n /**\n * Materialize to array with caching.\n */\n toArray(): K[] {\n if (!this.cached) {\n this.cached = [...this];\n }\n return this.cached;\n }\n\n /**\n * Check if empty.\n */\n isEmpty(): boolean {\n // If cached, use cached value\n if (this.cached) {\n return this.cached.length === 0;\n }\n\n // If limit is 0, always empty\n if (this.limit === 0) {\n return true;\n }\n\n // Try to get first element\n for (const _ of this) {\n return false;\n }\n return true;\n }\n\n /**\n * Check if results have been materialized.\n */\n isMaterialized(): boolean {\n return this.cached !== null;\n }\n\n /**\n * Get the offset value.\n */\n getOffset(): number {\n return this.offset;\n }\n\n /**\n * Get the limit value.\n */\n getLimit(): number {\n return this.limit;\n }\n}\n","/**\n * IndexRegistry Implementation\n *\n * Central registry for managing indexes on a collection.\n * Provides index lookup, lifecycle management, and bulk operations.\n *\n * @module query/IndexRegistry\n */\n\nimport type { Index, IndexQuery } from './indexes/types';\nimport type { Attribute } from './Attribute';\nimport { isCompoundIndex, type CompoundIndex } from './indexes/CompoundIndex';\n\n/**\n * Registry for managing indexes on a collection.\n * Provides index lookup and lifecycle management.\n *\n * K = record key type, V = record value type\n */\nexport class IndexRegistry<K, V> {\n /** Indexes grouped by attribute name */\n private attributeIndexes: Map<string, Index<K, V, unknown>[]> = new Map();\n\n /** Compound indexes (Phase 9.03) - keyed by sorted attribute names */\n private compoundIndexes: Map<string, CompoundIndex<K, V>> = new Map();\n\n /** Fallback index for full scan (optional) */\n private fallbackIndex: Index<K, V, unknown> | null = null;\n\n /**\n * Register an index for an attribute.\n * Multiple indexes can be registered for the same attribute.\n *\n * @param index - Index to register\n */\n addIndex<A>(index: Index<K, V, A>): void {\n // Handle compound indexes specially (Phase 9.03)\n if (isCompoundIndex(index)) {\n this.addCompoundIndex(index as unknown as CompoundIndex<K, V>);\n return;\n }\n\n const attrName = index.attribute.name;\n let indexes = this.attributeIndexes.get(attrName);\n\n if (!indexes) {\n indexes = [];\n this.attributeIndexes.set(attrName, indexes);\n }\n\n // Avoid duplicate registration\n if (!indexes.includes(index as Index<K, V, unknown>)) {\n indexes.push(index as Index<K, V, unknown>);\n }\n }\n\n /**\n * Register a compound index (Phase 9.03).\n *\n * @param index - Compound index to register\n */\n addCompoundIndex(index: CompoundIndex<K, V>): void {\n const key = this.makeCompoundKey(index.attributes.map((a) => a.name));\n this.compoundIndexes.set(key, index);\n }\n\n /**\n * Remove an index from the registry.\n *\n * @param index - Index to remove\n * @returns true if index was found and removed\n */\n removeIndex<A>(index: Index<K, V, A>): boolean {\n // Handle compound indexes specially (Phase 9.03)\n if (isCompoundIndex(index)) {\n return this.removeCompoundIndex(index as unknown as CompoundIndex<K, V>);\n }\n\n const attrName = index.attribute.name;\n const indexes = this.attributeIndexes.get(attrName);\n\n if (!indexes) {\n return false;\n }\n\n const idx = indexes.indexOf(index as Index<K, V, unknown>);\n if (idx === -1) {\n return false;\n }\n\n indexes.splice(idx, 1);\n\n // Clean up empty arrays\n if (indexes.length === 0) {\n this.attributeIndexes.delete(attrName);\n }\n\n return true;\n }\n\n /**\n * Remove a compound index (Phase 9.03).\n *\n * @param index - Compound index to remove\n * @returns true if index was found and removed\n */\n removeCompoundIndex(index: CompoundIndex<K, V>): boolean {\n const key = this.makeCompoundKey(index.attributes.map((a) => a.name));\n return this.compoundIndexes.delete(key);\n }\n\n /**\n * Get all indexes for an attribute.\n *\n * @param attributeName - Attribute name\n * @returns Array of indexes (empty if none)\n */\n getIndexes(attributeName: string): Index<K, V, unknown>[] {\n return this.attributeIndexes.get(attributeName) ?? [];\n }\n\n /**\n * Get all registered indexes across all attributes.\n *\n * @returns Array of all indexes\n */\n getAllIndexes(): Index<K, V, unknown>[] {\n const all: Index<K, V, unknown>[] = [];\n for (const indexes of this.attributeIndexes.values()) {\n all.push(...indexes);\n }\n return all;\n }\n\n /**\n * Get all indexed attribute names.\n *\n * @returns Array of attribute names\n */\n getIndexedAttributes(): string[] {\n return Array.from(this.attributeIndexes.keys());\n }\n\n /**\n * Check if an attribute has any indexes.\n *\n * @param attributeName - Attribute name\n * @returns true if attribute has indexes\n */\n hasIndex(attributeName: string): boolean {\n const indexes = this.attributeIndexes.get(attributeName);\n return indexes !== undefined && indexes.length > 0;\n }\n\n /**\n * Find the best index for a query type on an attribute.\n * Returns the index with lowest retrieval cost that supports the query type.\n *\n * @param attributeName - Attribute name to search on\n * @param queryType - Query type (e.g., 'equal', 'gt', 'between')\n * @returns Best matching index or null if none found\n */\n findBestIndex(\n attributeName: string,\n queryType: string\n ): Index<K, V, unknown> | null {\n const indexes = this.getIndexes(attributeName);\n let best: Index<K, V, unknown> | null = null;\n let bestCost = Infinity;\n\n for (const index of indexes) {\n if (index.supportsQuery(queryType) && index.getRetrievalCost() < bestCost) {\n best = index;\n bestCost = index.getRetrievalCost();\n }\n }\n\n return best;\n }\n\n /**\n * Find all indexes that support a query type on an attribute.\n *\n * @param attributeName - Attribute name\n * @param queryType - Query type\n * @returns Array of matching indexes sorted by retrieval cost\n */\n findIndexes(\n attributeName: string,\n queryType: string\n ): Index<K, V, unknown>[] {\n const indexes = this.getIndexes(attributeName);\n return indexes\n .filter((index) => index.supportsQuery(queryType))\n .sort((a, b) => a.getRetrievalCost() - b.getRetrievalCost());\n }\n\n // ========================================\n // Phase 9.03: Compound Index Methods\n // ========================================\n\n /**\n * Find a compound index that covers the given attribute names (Phase 9.03).\n * The compound index must cover ALL the attributes (exact match or superset).\n *\n * @param attributeNames - Array of attribute names to search for\n * @returns Matching compound index or null\n */\n findCompoundIndex(attributeNames: string[]): CompoundIndex<K, V> | null {\n if (attributeNames.length < 2) {\n return null;\n }\n\n // Try exact match first (most efficient)\n const key = this.makeCompoundKey(attributeNames);\n const exactMatch = this.compoundIndexes.get(key);\n if (exactMatch) {\n return exactMatch;\n }\n\n // No exact match - compound indexes require exact attribute match\n // (unlike SQL where prefix matching is possible)\n return null;\n }\n\n /**\n * Check if a compound index exists for the given attributes (Phase 9.03).\n *\n * @param attributeNames - Array of attribute names\n * @returns true if a compound index exists\n */\n hasCompoundIndex(attributeNames: string[]): boolean {\n return this.findCompoundIndex(attributeNames) !== null;\n }\n\n /**\n * Get all compound indexes (Phase 9.03).\n *\n * @returns Array of all compound indexes\n */\n getCompoundIndexes(): CompoundIndex<K, V>[] {\n return Array.from(this.compoundIndexes.values());\n }\n\n /**\n * Create a compound key from attribute names (sorted for consistency).\n */\n private makeCompoundKey(attributeNames: string[]): string {\n return [...attributeNames].sort().join('+');\n }\n\n /**\n * Set a fallback index for queries without a suitable index.\n * Typically a FallbackIndex that performs full scan.\n *\n * @param fallback - Fallback index\n */\n setFallbackIndex(fallback: Index<K, V, unknown>): void {\n this.fallbackIndex = fallback;\n }\n\n /**\n * Get the fallback index.\n *\n * @returns Fallback index or null if not set\n */\n getFallbackIndex(): Index<K, V, unknown> | null {\n return this.fallbackIndex;\n }\n\n /**\n * Notify all indexes of a record addition.\n * Should be called when a new record is added to the collection.\n *\n * @param key - Record key\n * @param record - Record value\n */\n onRecordAdded(key: K, record: V): void {\n for (const indexes of this.attributeIndexes.values()) {\n for (const index of indexes) {\n index.add(key, record);\n }\n }\n // Also update compound indexes (Phase 9.03)\n for (const compoundIndex of this.compoundIndexes.values()) {\n compoundIndex.add(key, record);\n }\n }\n\n /**\n * Notify all indexes of a record update.\n * Should be called when a record's value changes.\n *\n * @param key - Record key\n * @param oldRecord - Previous record value\n * @param newRecord - New record value\n */\n onRecordUpdated(key: K, oldRecord: V, newRecord: V): void {\n for (const indexes of this.attributeIndexes.values()) {\n for (const index of indexes) {\n index.update(key, oldRecord, newRecord);\n }\n }\n // Also update compound indexes (Phase 9.03)\n for (const compoundIndex of this.compoundIndexes.values()) {\n compoundIndex.update(key, oldRecord, newRecord);\n }\n }\n\n /**\n * Notify all indexes of a record removal.\n * Should be called when a record is removed from the collection.\n *\n * @param key - Record key\n * @param record - Removed record value\n */\n onRecordRemoved(key: K, record: V): void {\n for (const indexes of this.attributeIndexes.values()) {\n for (const index of indexes) {\n index.remove(key, record);\n }\n }\n // Also update compound indexes (Phase 9.03)\n for (const compoundIndex of this.compoundIndexes.values()) {\n compoundIndex.remove(key, record);\n }\n }\n\n /**\n * Clear all indexes.\n * Does not remove index registrations, only clears their data.\n */\n clear(): void {\n for (const indexes of this.attributeIndexes.values()) {\n for (const index of indexes) {\n index.clear();\n }\n }\n // Also clear compound indexes (Phase 9.03)\n for (const compoundIndex of this.compoundIndexes.values()) {\n compoundIndex.clear();\n }\n }\n\n /**\n * Get total number of registered indexes.\n */\n get size(): number {\n let count = 0;\n for (const indexes of this.attributeIndexes.values()) {\n count += indexes.length;\n }\n // Include compound indexes (Phase 9.03)\n count += this.compoundIndexes.size;\n return count;\n }\n\n /**\n * Get statistics about the registry.\n */\n getStats(): IndexRegistryStats {\n const indexes = this.getAllIndexes();\n const indexStats = indexes.map((index) => ({\n attribute: index.attribute.name,\n type: index.type,\n stats: index.getStats(),\n }));\n\n // Add compound index stats (Phase 9.03)\n for (const compoundIndex of this.compoundIndexes.values()) {\n indexStats.push({\n attribute: compoundIndex.compoundName,\n type: 'compound',\n stats: compoundIndex.getStats(),\n });\n }\n\n return {\n totalIndexes: indexes.length + this.compoundIndexes.size,\n indexedAttributes: this.getIndexedAttributes().length,\n compoundIndexes: this.compoundIndexes.size,\n indexes: indexStats,\n };\n }\n}\n\n/**\n * Statistics about the IndexRegistry.\n */\nexport interface IndexRegistryStats {\n /** Total number of indexes */\n totalIndexes: number;\n /** Number of indexed attributes */\n indexedAttributes: number;\n /** Number of compound indexes (Phase 9.03) */\n compoundIndexes?: number;\n /** Stats for each index */\n indexes: Array<{\n attribute: string;\n type: string;\n stats: {\n distinctValues: number;\n totalEntries: number;\n avgEntriesPerValue: number;\n };\n }>;\n}\n","/**\n * QueryOptimizer Implementation\n *\n * Cost-based query optimizer for the Query Engine.\n * Selects optimal index and execution strategy for queries.\n *\n * Algorithm based on CQEngine CollectionQueryEngine:\n * - StandingQueryIndex: Check first (lowest cost = 10)\n * - AND queries: \"smallest first\" strategy - sort by merge cost, iterate smallest\n * - OR queries: Union all results with deduplication\n * - NOT queries: Get all keys, subtract matching keys\n *\n * @module query/QueryOptimizer\n */\n\nimport { IndexRegistry } from './IndexRegistry';\nimport { StandingQueryRegistry } from './StandingQueryRegistry';\nimport type {\n Query,\n SimpleQueryNode,\n LogicalQueryNode,\n QueryPlan,\n PlanStep,\n QueryOptions,\n FTSQueryNode,\n FTSScanStep,\n FusionStep,\n FusionStrategy,\n MatchQueryNode,\n MatchPhraseQueryNode,\n MatchPrefixQueryNode,\n} from './QueryTypes';\nimport { isLogicalQuery, isSimpleQuery, isFTSQuery } from './QueryTypes';\nimport type { FullTextIndex } from '../fts';\nimport type { IndexQuery } from './indexes/types';\nimport type { CompoundIndex } from './indexes/CompoundIndex';\n\n/**\n * Options for creating a QueryOptimizer.\n */\nexport interface QueryOptimizerOptions<K, V> {\n /** Index registry for attribute-based indexes */\n indexRegistry: IndexRegistry<K, V>;\n /** Standing query registry for pre-computed queries (optional) */\n standingQueryRegistry?: StandingQueryRegistry<K, V>;\n /** Full-text index registry for FTS queries (Phase 12) */\n fullTextIndexes?: Map<string, FullTextIndex>;\n}\n\n/**\n * Classified predicates by type for hybrid query planning.\n */\nexport interface ClassifiedPredicates {\n /** Exact match predicates (eq, neq, in) */\n exactPredicates: Query[];\n /** Range predicates (gt, gte, lt, lte, between) */\n rangePredicates: Query[];\n /** Full-text search predicates (match, matchPhrase, matchPrefix) */\n ftsPredicates: FTSQueryNode[];\n /** Other predicates (like, regex, contains, etc.) */\n otherPredicates: Query[];\n}\n\n/**\n * Cost-based query optimizer.\n * Selects optimal index and execution strategy for queries.\n *\n * K = record key type, V = record value type\n */\nexport class QueryOptimizer<K, V> {\n private readonly indexRegistry: IndexRegistry<K, V>;\n private readonly standingQueryRegistry?: StandingQueryRegistry<K, V>;\n private readonly fullTextIndexes: Map<string, FullTextIndex>;\n\n /**\n * Create a QueryOptimizer.\n *\n * @param indexRegistryOrOptions - IndexRegistry or options object\n * @param standingQueryRegistry - Optional StandingQueryRegistry (deprecated, use options)\n */\n constructor(\n indexRegistryOrOptions: IndexRegistry<K, V> | QueryOptimizerOptions<K, V>,\n standingQueryRegistry?: StandingQueryRegistry<K, V>\n ) {\n if ('indexRegistry' in indexRegistryOrOptions) {\n // Options object\n this.indexRegistry = indexRegistryOrOptions.indexRegistry;\n this.standingQueryRegistry = indexRegistryOrOptions.standingQueryRegistry;\n this.fullTextIndexes = indexRegistryOrOptions.fullTextIndexes ?? new Map();\n } else {\n // Legacy: direct IndexRegistry\n this.indexRegistry = indexRegistryOrOptions;\n this.standingQueryRegistry = standingQueryRegistry;\n this.fullTextIndexes = new Map();\n }\n }\n\n /**\n * Register a full-text index for a field (Phase 12).\n *\n * @param field - Field name\n * @param index - FullTextIndex instance\n */\n registerFullTextIndex(field: string, index: FullTextIndex): void {\n this.fullTextIndexes.set(field, index);\n }\n\n /**\n * Unregister a full-text index (Phase 12).\n *\n * @param field - Field name\n */\n unregisterFullTextIndex(field: string): void {\n this.fullTextIndexes.delete(field);\n }\n\n /**\n * Get registered full-text index for a field (Phase 12).\n *\n * @param field - Field name\n * @returns FullTextIndex or undefined\n */\n getFullTextIndex(field: string): FullTextIndex | undefined {\n return this.fullTextIndexes.get(field);\n }\n\n /**\n * Check if a full-text index exists for a field (Phase 12).\n *\n * @param field - Field name\n * @returns True if FTS index exists\n */\n hasFullTextIndex(field: string): boolean {\n return this.fullTextIndexes.has(field);\n }\n\n /**\n * Optimize a query and return an execution plan.\n *\n * Optimization order (by cost):\n * 1. StandingQueryIndex (cost: 10) - pre-computed results\n * 2. Other indexes via optimizeNode\n *\n * @param query - Query to optimize\n * @returns Query execution plan\n */\n optimize(query: Query): QueryPlan {\n // Check for standing query index first (lowest cost)\n if (this.standingQueryRegistry) {\n const standingIndex = this.standingQueryRegistry.getIndex(query);\n if (standingIndex) {\n return {\n root: {\n type: 'index-scan',\n index: standingIndex,\n query: { type: 'equal', value: null }, // Dummy query, index returns pre-computed results\n },\n estimatedCost: standingIndex.getRetrievalCost(),\n usesIndexes: true,\n };\n }\n }\n\n // Fall back to regular optimization\n const step = this.optimizeNode(query);\n return {\n root: step,\n estimatedCost: this.estimateCost(step),\n usesIndexes: this.usesIndexes(step),\n };\n }\n\n /**\n * Optimize a query with sort/limit/offset options.\n *\n * @param query - Query to optimize\n * @param options - Query options (sort, limit, offset)\n * @returns Query execution plan with options\n */\n optimizeWithOptions(query: Query, options: QueryOptions): QueryPlan {\n const basePlan = this.optimize(query);\n\n // If no options specified, return base plan\n if (!options.sort && options.limit === undefined && options.offset === undefined) {\n return basePlan;\n }\n\n let indexedSort = false;\n let sortField: string | undefined;\n let sortDirection: 'asc' | 'desc' | undefined;\n\n // Check if sort can use NavigableIndex\n if (options.sort) {\n const sortFields = Object.keys(options.sort);\n if (sortFields.length > 0) {\n sortField = sortFields[0];\n sortDirection = options.sort[sortField];\n\n // Look for a NavigableIndex on the sort field\n const sortIndex = this.indexRegistry.findBestIndex(sortField, 'gte');\n if (sortIndex?.type === 'navigable') {\n indexedSort = true;\n }\n }\n }\n\n return {\n ...basePlan,\n indexedSort,\n sort:\n sortField && sortDirection\n ? { field: sortField, direction: sortDirection }\n : undefined,\n limit: options.limit,\n offset: options.offset,\n };\n }\n\n /**\n * Optimize a single query node.\n */\n private optimizeNode(query: Query): PlanStep {\n if (isLogicalQuery(query)) {\n return this.optimizeLogical(query);\n } else if (isFTSQuery(query)) {\n return this.optimizeFTS(query);\n } else if (isSimpleQuery(query)) {\n return this.optimizeSimple(query);\n } else {\n // Unknown query type - fall back to full scan\n return { type: 'full-scan', predicate: query };\n }\n }\n\n /**\n * Optimize a full-text search query (Phase 12).\n */\n private optimizeFTS(query: FTSQueryNode): PlanStep {\n const field = query.attribute;\n\n // Check if we have a FTS index for this field\n if (!this.hasFullTextIndex(field)) {\n // No FTS index - fall back to full scan\n return { type: 'full-scan', predicate: query };\n }\n\n // Create FTS scan step\n return this.buildFTSScanStep(query);\n }\n\n /**\n * Build an FTS scan step from a query node (Phase 12).\n */\n private buildFTSScanStep(query: FTSQueryNode): FTSScanStep {\n const field = query.attribute;\n\n switch (query.type) {\n case 'match':\n return {\n type: 'fts-scan',\n field,\n query: query.query,\n ftsType: 'match',\n options: query.options,\n returnsScored: true,\n estimatedCost: this.estimateFTSCost(field),\n };\n\n case 'matchPhrase':\n return {\n type: 'fts-scan',\n field,\n query: query.query,\n ftsType: 'matchPhrase',\n options: query.slop !== undefined ? { fuzziness: query.slop } : undefined,\n returnsScored: true,\n estimatedCost: this.estimateFTSCost(field),\n };\n\n case 'matchPrefix':\n return {\n type: 'fts-scan',\n field,\n query: query.prefix,\n ftsType: 'matchPrefix',\n options: query.maxExpansions !== undefined ? { fuzziness: query.maxExpansions } : undefined,\n returnsScored: true,\n estimatedCost: this.estimateFTSCost(field),\n };\n\n default:\n throw new Error(`Unknown FTS query type: ${(query as FTSQueryNode).type}`);\n }\n }\n\n /**\n * Estimate cost of FTS query based on index size (Phase 12).\n */\n private estimateFTSCost(field: string): number {\n const index = this.fullTextIndexes.get(field);\n if (!index) {\n return Number.MAX_SAFE_INTEGER;\n }\n\n // FTS cost is based on document count\n // Roughly O(log N) for term lookup + O(M) for scoring M matching docs\n const docCount = index.getSize();\n\n // Base cost + log scale factor\n return 50 + Math.log2(docCount + 1) * 10;\n }\n\n /**\n * Classify predicates by type for hybrid query planning (Phase 12).\n *\n * @param predicates - Array of predicates to classify\n * @returns Classified predicates\n */\n classifyPredicates(predicates: Query[]): ClassifiedPredicates {\n const result: ClassifiedPredicates = {\n exactPredicates: [],\n rangePredicates: [],\n ftsPredicates: [],\n otherPredicates: [],\n };\n\n for (const pred of predicates) {\n if (isFTSQuery(pred)) {\n result.ftsPredicates.push(pred);\n } else if (isSimpleQuery(pred)) {\n switch (pred.type) {\n case 'eq':\n case 'neq':\n case 'in':\n result.exactPredicates.push(pred);\n break;\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte':\n case 'between':\n result.rangePredicates.push(pred);\n break;\n default:\n result.otherPredicates.push(pred);\n }\n } else if (isLogicalQuery(pred)) {\n // Logical predicates go to other\n result.otherPredicates.push(pred);\n } else {\n result.otherPredicates.push(pred);\n }\n }\n\n return result;\n }\n\n /**\n * Determine fusion strategy based on step types (Phase 12).\n *\n * Strategy selection:\n * - All binary (exact/range with no scores) → 'intersection'\n * - All scored (FTS) → 'score-filter' (filter by score, sort by score)\n * - Mixed (binary + scored) → 'rrf' (Reciprocal Rank Fusion)\n *\n * @param steps - Plan steps to fuse\n * @returns Fusion strategy\n */\n determineFusionStrategy(steps: PlanStep[]): FusionStrategy {\n const hasScored = steps.some((s) => this.stepReturnsScored(s));\n const hasBinary = steps.some((s) => !this.stepReturnsScored(s));\n\n if (hasScored && hasBinary) {\n // Mixed: use RRF to combine ranked and unranked results\n return 'rrf';\n } else if (hasScored) {\n // All scored: filter by score, combine scores\n return 'score-filter';\n } else {\n // All binary: simple intersection\n return 'intersection';\n }\n }\n\n /**\n * Check if a plan step returns scored results (Phase 12).\n */\n private stepReturnsScored(step: PlanStep): boolean {\n switch (step.type) {\n case 'fts-scan':\n return true;\n case 'fusion':\n return step.returnsScored;\n default:\n return false;\n }\n }\n\n /**\n * Optimize a simple (attribute-based) query.\n */\n private optimizeSimple(query: SimpleQueryNode): PlanStep {\n // Map query type to index query type\n const indexQueryType = this.mapQueryType(query.type);\n\n // Find best index for this attribute and query type\n const index = this.indexRegistry.findBestIndex(query.attribute, indexQueryType);\n\n if (index) {\n // Use index scan\n const indexQuery = this.buildIndexQuery(query);\n return { type: 'index-scan', index, query: indexQuery };\n }\n\n // No suitable index - fall back to full scan\n return { type: 'full-scan', predicate: query };\n }\n\n /**\n * Optimize a logical (AND/OR/NOT) query.\n */\n private optimizeLogical(query: LogicalQueryNode): PlanStep {\n switch (query.type) {\n case 'and':\n return this.optimizeAnd(query);\n case 'or':\n return this.optimizeOr(query);\n case 'not':\n return this.optimizeNot(query);\n default:\n throw new Error(`Unknown logical query type: ${query.type}`);\n }\n }\n\n /**\n * Optimize AND query.\n * Strategy: Find child with lowest cost, use as base, filter with rest.\n *\n * CQEngine \"smallest first\" strategy:\n * 1. Check for CompoundIndex covering all eq children (Phase 9.03)\n * 2. Sort children by merge cost\n * 3. Use intersection if multiple indexes available\n * 4. Apply remaining predicates as filters\n */\n private optimizeAnd(query: LogicalQueryNode): PlanStep {\n if (!query.children || query.children.length === 0) {\n throw new Error('AND query must have children');\n }\n\n // Single child - just optimize it directly\n if (query.children.length === 1) {\n return this.optimizeNode(query.children[0]);\n }\n\n // Phase 9.03: Check if a CompoundIndex can handle this AND query\n const compoundStep = this.tryCompoundIndex(query.children);\n if (compoundStep) {\n return compoundStep;\n }\n\n // Optimize all children\n const childSteps = query.children.map((child) => this.optimizeNode(child));\n\n // Sort by estimated cost (ascending)\n const sortedWithIndex = childSteps\n .map((step, index) => ({ step, originalIndex: index }))\n .sort((a, b) => this.estimateCost(a.step) - this.estimateCost(b.step));\n\n const sortedSteps = sortedWithIndex.map((s) => s.step);\n\n // Separate indexed steps from full scan steps\n const indexedSteps = sortedSteps.filter((s) => s.type === 'index-scan');\n const fullScanSteps = sortedSteps.filter((s) => s.type === 'full-scan');\n\n // No indexes available - fall back to single full scan\n if (indexedSteps.length === 0) {\n return { type: 'full-scan', predicate: query };\n }\n\n // One index available - use it as base, filter with remaining predicates\n if (indexedSteps.length === 1) {\n const [indexStep] = indexedSteps;\n\n if (fullScanSteps.length === 0) {\n return indexStep;\n }\n\n // Build filter predicate from remaining conditions\n const remainingPredicates = fullScanSteps.map((s) => {\n if (s.type === 'full-scan') {\n return s.predicate;\n }\n throw new Error('Unexpected step type in remaining predicates');\n });\n\n const filterPredicate: Query =\n remainingPredicates.length === 1\n ? remainingPredicates[0]\n : { type: 'and', children: remainingPredicates };\n\n return { type: 'filter', source: indexStep, predicate: filterPredicate };\n }\n\n // Multiple indexes available - use intersection\n // CQEngine strategy: iterate smallest, check membership in others\n return { type: 'intersection', steps: indexedSteps };\n }\n\n /**\n * Try to use a CompoundIndex for an AND query (Phase 9.03).\n *\n * Returns a compound index scan step if:\n * 1. All children are simple 'eq' queries\n * 2. A CompoundIndex exists covering all queried attributes\n *\n * @param children - Children of the AND query\n * @returns IndexScanStep using CompoundIndex, or null if not applicable\n */\n private tryCompoundIndex(children: Query[]): PlanStep | null {\n // Check if all children are simple 'eq' queries\n const eqQueries: SimpleQueryNode[] = [];\n const otherQueries: Query[] = [];\n\n for (const child of children) {\n if (isSimpleQuery(child) && child.type === 'eq') {\n eqQueries.push(child);\n } else {\n otherQueries.push(child);\n }\n }\n\n // Need at least 2 'eq' queries to use compound index\n if (eqQueries.length < 2) {\n return null;\n }\n\n // Extract attribute names from eq queries\n const attributeNames = eqQueries.map((q) => q.attribute);\n\n // Find a compound index covering these attributes\n const compoundIndex = this.indexRegistry.findCompoundIndex(attributeNames);\n if (!compoundIndex) {\n return null;\n }\n\n // Build values array in the order expected by the compound index\n const values = this.buildCompoundValues(compoundIndex, eqQueries);\n if (!values) {\n return null; // Attribute order mismatch\n }\n\n // Create compound index scan step\n const compoundStep: PlanStep = {\n type: 'index-scan',\n index: compoundIndex as unknown as import('./indexes/types').Index<unknown, unknown, unknown>,\n query: { type: 'compound', values },\n };\n\n // If there are other (non-eq) queries, apply them as filters\n if (otherQueries.length > 0) {\n const filterPredicate: Query =\n otherQueries.length === 1\n ? otherQueries[0]\n : { type: 'and', children: otherQueries };\n\n return { type: 'filter', source: compoundStep, predicate: filterPredicate };\n }\n\n return compoundStep;\n }\n\n /**\n * Build values array for compound index query in correct attribute order.\n *\n * @param compoundIndex - The compound index to use\n * @param eqQueries - Array of 'eq' queries\n * @returns Values array in compound index order, or null if mismatch\n */\n private buildCompoundValues(\n compoundIndex: CompoundIndex<K, V>,\n eqQueries: SimpleQueryNode[]\n ): unknown[] | null {\n const attributeNames = compoundIndex.attributes.map((a) => a.name);\n const values: unknown[] = [];\n\n // Build a map of attribute -> value from eq queries\n const queryMap = new Map<string, unknown>();\n for (const q of eqQueries) {\n queryMap.set(q.attribute, q.value);\n }\n\n // Build values array in compound index order\n for (const attrName of attributeNames) {\n if (!queryMap.has(attrName)) {\n return null; // Missing attribute value\n }\n values.push(queryMap.get(attrName));\n }\n\n return values;\n }\n\n /**\n * Optimize OR query.\n * Strategy: Union of all child results with deduplication.\n */\n private optimizeOr(query: LogicalQueryNode): PlanStep {\n if (!query.children || query.children.length === 0) {\n throw new Error('OR query must have children');\n }\n\n // Single child - just optimize it directly\n if (query.children.length === 1) {\n return this.optimizeNode(query.children[0]);\n }\n\n const childSteps = query.children.map((child) => this.optimizeNode(child));\n\n // If all children are full scans, do a single full scan\n if (childSteps.every((s) => s.type === 'full-scan')) {\n return { type: 'full-scan', predicate: query };\n }\n\n // Create union of all results\n return { type: 'union', steps: childSteps };\n }\n\n /**\n * Optimize NOT query.\n * Strategy: Get all keys, subtract matching keys.\n */\n private optimizeNot(query: LogicalQueryNode): PlanStep {\n if (!query.child) {\n throw new Error('NOT query must have a child');\n }\n\n const childStep = this.optimizeNode(query.child);\n\n return {\n type: 'not',\n source: childStep,\n allKeys: () => new Set(), // Will be provided by executor at runtime\n };\n }\n\n /**\n * Map query type to index query type.\n * Some query types have different names in indexes.\n */\n private mapQueryType(type: string): string {\n const mapping: Record<string, string> = {\n eq: 'equal',\n neq: 'equal', // Will negate in execution\n gt: 'gt',\n gte: 'gte',\n lt: 'lt',\n lte: 'lte',\n in: 'in',\n has: 'has',\n like: 'like',\n regex: 'regex',\n between: 'between',\n contains: 'contains',\n containsAll: 'containsAll',\n containsAny: 'containsAny',\n };\n return mapping[type] ?? type;\n }\n\n /**\n * Build an IndexQuery from a SimpleQueryNode.\n */\n private buildIndexQuery(query: SimpleQueryNode): IndexQuery<unknown> {\n switch (query.type) {\n case 'eq':\n case 'neq':\n return { type: 'equal', value: query.value };\n case 'gt':\n return { type: 'gt', value: query.value };\n case 'gte':\n return { type: 'gte', value: query.value };\n case 'lt':\n return { type: 'lt', value: query.value };\n case 'lte':\n return { type: 'lte', value: query.value };\n case 'in':\n return { type: 'in', values: query.values };\n case 'has':\n return { type: 'has' };\n case 'between':\n return {\n type: 'between',\n from: query.from,\n to: query.to,\n fromInclusive: query.fromInclusive,\n toInclusive: query.toInclusive,\n };\n case 'contains':\n return { type: 'contains', value: query.value };\n case 'containsAll':\n return { type: 'containsAll', values: query.values };\n case 'containsAny':\n return { type: 'containsAny', values: query.values };\n default:\n throw new Error(`Cannot build index query for type: ${query.type}`);\n }\n }\n\n /**\n * Estimate the execution cost of a plan step.\n */\n private estimateCost(step: PlanStep): number {\n switch (step.type) {\n case 'index-scan':\n return step.index.getRetrievalCost();\n\n case 'full-scan':\n return Number.MAX_SAFE_INTEGER;\n\n case 'intersection':\n // Cost is minimum of all (we only iterate smallest)\n return Math.min(...step.steps.map((s) => this.estimateCost(s)));\n\n case 'union':\n // Cost is sum of all\n return step.steps.reduce((sum, s) => {\n const cost = this.estimateCost(s);\n // Avoid overflow\n if (cost === Number.MAX_SAFE_INTEGER) {\n return Number.MAX_SAFE_INTEGER;\n }\n return Math.min(sum + cost, Number.MAX_SAFE_INTEGER);\n }, 0);\n\n case 'filter':\n // Filter adds overhead to source cost\n return this.estimateCost(step.source) + 10;\n\n case 'not':\n // NOT is expensive (needs all keys)\n return this.estimateCost(step.source) + 100;\n\n // Phase 12: FTS step types\n case 'fts-scan':\n return step.estimatedCost;\n\n case 'fusion':\n // Fusion cost is sum of all child costs + fusion overhead\n return step.steps.reduce((sum, s) => {\n const cost = this.estimateCost(s);\n if (cost === Number.MAX_SAFE_INTEGER) {\n return Number.MAX_SAFE_INTEGER;\n }\n return Math.min(sum + cost, Number.MAX_SAFE_INTEGER);\n }, 0) + 20; // Fusion overhead\n\n default:\n return Number.MAX_SAFE_INTEGER;\n }\n }\n\n /**\n * Check if a plan step uses any indexes.\n */\n private usesIndexes(step: PlanStep): boolean {\n switch (step.type) {\n case 'index-scan':\n return true;\n\n case 'full-scan':\n return false;\n\n case 'intersection':\n case 'union':\n return step.steps.some((s) => this.usesIndexes(s));\n\n case 'filter':\n return this.usesIndexes(step.source);\n\n case 'not':\n return this.usesIndexes(step.source);\n\n // Phase 12: FTS step types\n case 'fts-scan':\n return true; // FTS uses FullTextIndex\n\n case 'fusion':\n return step.steps.some((s) => this.usesIndexes(s));\n\n default:\n return false;\n }\n }\n}\n","/**\n * StandingQueryRegistry Implementation\n *\n * Registry for managing StandingQueryIndexes.\n * Used by Live Query system to maintain pre-computed results.\n *\n * Features:\n * - Reference counting for shared indexes\n * - Automatic cleanup when all subscribers unsubscribe\n * - Efficient update propagation to all indexes\n *\n * @module query/StandingQueryRegistry\n */\n\nimport {\n StandingQueryIndex,\n type StandingQueryChange,\n type StandingQueryIndexOptions,\n} from './indexes/StandingQueryIndex';\nimport type { Query } from './QueryTypes';\n\n/**\n * Options for creating a StandingQueryRegistry.\n */\nexport interface StandingQueryRegistryOptions<K, V> {\n /** Function to get record by key */\n getRecord: (key: K) => V | undefined;\n /** Function to get all entries for building index */\n getAllEntries: () => Iterable<[K, V]>;\n}\n\n/**\n * Statistics about the StandingQueryRegistry.\n */\nexport interface StandingQueryRegistryStats {\n /** Number of registered indexes */\n indexCount: number;\n /** Total reference count across all indexes */\n totalRefCount: number;\n /** Total number of results across all indexes */\n totalResults: number;\n}\n\n/**\n * Registry for managing StandingQueryIndexes.\n * Provides reference counting and lifecycle management.\n *\n * K = record key type, V = record value type\n */\nexport class StandingQueryRegistry<K, V> {\n /** Map from query hash to StandingQueryIndex */\n private indexes: Map<string, StandingQueryIndex<K, V>> = new Map();\n\n /** Reference count for each query (multiple subscriptions can use same index) */\n private refCounts: Map<string, number> = new Map();\n\n /** Record accessor */\n private readonly getRecord: (key: K) => V | undefined;\n\n /** All entries accessor (for building index) */\n private readonly getAllEntries: () => Iterable<[K, V]>;\n\n constructor(options: StandingQueryRegistryOptions<K, V>) {\n this.getRecord = options.getRecord;\n this.getAllEntries = options.getAllEntries;\n }\n\n /**\n * Register a standing query.\n * Creates new index or returns existing if query already registered.\n * Increments reference count.\n *\n * @param query - Query to register\n * @returns StandingQueryIndex for the query\n */\n register(query: Query): StandingQueryIndex<K, V> {\n const hash = this.hashQuery(query);\n\n let index = this.indexes.get(hash);\n if (index) {\n // Increment reference count\n this.refCounts.set(hash, (this.refCounts.get(hash) || 0) + 1);\n return index;\n }\n\n // Create new index\n const options: StandingQueryIndexOptions<K, V> = {\n query,\n getRecord: this.getRecord,\n };\n index = new StandingQueryIndex(options);\n\n // Build from existing data\n index.buildFromData(this.getAllEntries());\n\n this.indexes.set(hash, index);\n this.refCounts.set(hash, 1);\n\n return index;\n }\n\n /**\n * Unregister a standing query.\n * Decrements reference count. Only removes when refcount reaches 0.\n *\n * @param query - Query to unregister\n * @returns true if index was removed, false if still has references\n */\n unregister(query: Query): boolean {\n const hash = this.hashQuery(query);\n const refCount = this.refCounts.get(hash) || 0;\n\n if (refCount <= 1) {\n this.indexes.delete(hash);\n this.refCounts.delete(hash);\n return true;\n }\n\n this.refCounts.set(hash, refCount - 1);\n return false;\n }\n\n /**\n * Get index for a query if registered.\n *\n * @param query - Query to look up\n * @returns StandingQueryIndex or undefined if not registered\n */\n getIndex(query: Query): StandingQueryIndex<K, V> | undefined {\n const hash = this.hashQuery(query);\n return this.indexes.get(hash);\n }\n\n /**\n * Get index by hash directly.\n *\n * @param hash - Query hash\n * @returns StandingQueryIndex or undefined if not registered\n */\n getIndexByHash(hash: string): StandingQueryIndex<K, V> | undefined {\n return this.indexes.get(hash);\n }\n\n /**\n * Check if query has a standing index.\n *\n * @param query - Query to check\n * @returns true if index exists\n */\n hasIndex(query: Query): boolean {\n const hash = this.hashQuery(query);\n return this.indexes.has(hash);\n }\n\n /**\n * Get reference count for a query.\n *\n * @param query - Query to check\n * @returns Reference count (0 if not registered)\n */\n getRefCount(query: Query): number {\n const hash = this.hashQuery(query);\n return this.refCounts.get(hash) || 0;\n }\n\n /**\n * Notify all indexes of record addition.\n * Returns map of query hash to change type for affected queries.\n *\n * @param key - Record key\n * @param record - New record value\n * @returns Map of query hash to change type\n */\n onRecordAdded(key: K, record: V): Map<string, StandingQueryChange> {\n const changes = new Map<string, StandingQueryChange>();\n\n for (const [hash, index] of this.indexes) {\n const change = index.determineChange(key, undefined, record);\n if (change !== 'unchanged') {\n index.add(key, record);\n changes.set(hash, change);\n }\n }\n\n return changes;\n }\n\n /**\n * Notify all indexes of record update.\n * Returns map of query hash to change type for affected queries.\n *\n * @param key - Record key\n * @param oldRecord - Previous record value\n * @param newRecord - New record value\n * @returns Map of query hash to change type\n */\n onRecordUpdated(\n key: K,\n oldRecord: V,\n newRecord: V\n ): Map<string, StandingQueryChange> {\n const changes = new Map<string, StandingQueryChange>();\n\n for (const [hash, index] of this.indexes) {\n const change = index.determineChange(key, oldRecord, newRecord);\n if (change !== 'unchanged') {\n index.update(key, oldRecord, newRecord);\n changes.set(hash, change);\n }\n }\n\n return changes;\n }\n\n /**\n * Notify all indexes of record removal.\n * Returns map of query hash to change type for affected queries.\n *\n * @param key - Record key\n * @param record - Removed record value\n * @returns Map of query hash to change type\n */\n onRecordRemoved(key: K, record: V): Map<string, StandingQueryChange> {\n const changes = new Map<string, StandingQueryChange>();\n\n for (const [hash, index] of this.indexes) {\n const change = index.determineChange(key, record, undefined);\n if (change !== 'unchanged') {\n index.remove(key, record);\n changes.set(hash, change);\n }\n }\n\n return changes;\n }\n\n /**\n * Get all registered queries.\n *\n * @returns Array of registered queries\n */\n getRegisteredQueries(): Query[] {\n return Array.from(this.indexes.values()).map((idx) => idx.getQuery());\n }\n\n /**\n * Get all query hashes.\n *\n * @returns Array of query hashes\n */\n getQueryHashes(): string[] {\n return Array.from(this.indexes.keys());\n }\n\n /**\n * Get statistics about the registry.\n *\n * @returns Registry statistics\n */\n getStats(): StandingQueryRegistryStats {\n return {\n indexCount: this.indexes.size,\n totalRefCount: Array.from(this.refCounts.values()).reduce(\n (a, b) => a + b,\n 0\n ),\n totalResults: Array.from(this.indexes.values()).reduce(\n (sum, idx) => sum + idx.getResultCount(),\n 0\n ),\n };\n }\n\n /**\n * Clear all indexes.\n */\n clear(): void {\n for (const index of this.indexes.values()) {\n index.clear();\n }\n this.indexes.clear();\n this.refCounts.clear();\n }\n\n /**\n * Get number of registered indexes.\n */\n get size(): number {\n return this.indexes.size;\n }\n\n /**\n * Compute hash for a query.\n * Used as key in indexes map.\n */\n hashQuery(query: Query): string {\n return JSON.stringify(query);\n }\n}\n","/**\n * LiveQueryManager Implementation\n *\n * Manages live query subscriptions using StandingQueryIndexes.\n * Provides reactive updates when data changes.\n *\n * Features:\n * - Initial results on subscribe\n * - Delta updates on record changes\n * - Shared indexes for identical queries\n * - Automatic cleanup on unsubscribe\n *\n * @module query/LiveQueryManager\n */\n\nimport {\n StandingQueryRegistry,\n type StandingQueryRegistryOptions,\n type StandingQueryRegistryStats,\n} from './StandingQueryRegistry';\nimport type { StandingQueryChange } from './indexes/StandingQueryIndex';\nimport type { Query } from './QueryTypes';\n\n/**\n * Initial results event sent when subscribing.\n */\nexport interface LiveQueryInitialEvent<K> {\n type: 'initial';\n query: Query;\n results: K[];\n}\n\n/**\n * Delta event sent when data changes.\n */\nexport interface LiveQueryDeltaEvent<K, V> {\n type: 'delta';\n query: Query;\n key: K;\n record: V;\n change: StandingQueryChange;\n operation: 'added' | 'updated' | 'removed';\n newResultCount: number;\n}\n\n/**\n * Union type for all live query events.\n */\nexport type LiveQueryEvent<K, V> = LiveQueryInitialEvent<K> | LiveQueryDeltaEvent<K, V>;\n\n/**\n * Callback for live query events.\n */\nexport type LiveQueryCallback<K, V> = (event: LiveQueryEvent<K, V>) => void;\n\n/**\n * Options for creating a LiveQueryManager.\n */\nexport interface LiveQueryManagerOptions<K, V> {\n /** Function to get record by key */\n getRecord: (key: K) => V | undefined;\n /** Function to get all entries for building index */\n getAllEntries: () => Iterable<[K, V]>;\n}\n\n/**\n * Manages live query subscriptions using StandingQueryIndexes.\n * Provides reactive updates when data changes.\n *\n * K = record key type, V = record value type\n */\nexport class LiveQueryManager<K, V> {\n private registry: StandingQueryRegistry<K, V>;\n\n /** Subscription callbacks by query hash */\n private subscriptions: Map<string, Set<LiveQueryCallback<K, V>>> = new Map();\n\n constructor(options: LiveQueryManagerOptions<K, V>) {\n const registryOptions: StandingQueryRegistryOptions<K, V> = {\n getRecord: options.getRecord,\n getAllEntries: options.getAllEntries,\n };\n this.registry = new StandingQueryRegistry(registryOptions);\n }\n\n /**\n * Subscribe to a live query.\n * Sends initial results immediately, then delta updates on changes.\n *\n * @param query - Query to subscribe to\n * @param callback - Callback for query events\n * @returns Unsubscribe function\n */\n subscribe(query: Query, callback: LiveQueryCallback<K, V>): () => void {\n const hash = this.registry.hashQuery(query);\n\n // Register standing query index\n const index = this.registry.register(query);\n\n // Add callback to subscriptions\n let callbacks = this.subscriptions.get(hash);\n if (!callbacks) {\n callbacks = new Set();\n this.subscriptions.set(hash, callbacks);\n }\n callbacks.add(callback);\n\n // Send initial results\n const initialResults = Array.from(index.getResults());\n try {\n callback({\n type: 'initial',\n query,\n results: initialResults,\n });\n } catch (error) {\n console.error('LiveQueryManager initial callback error:', error);\n }\n\n // Return unsubscribe function\n return () => {\n callbacks?.delete(callback);\n if (callbacks?.size === 0) {\n this.subscriptions.delete(hash);\n }\n this.registry.unregister(query);\n };\n }\n\n /**\n * Get current results for a query (snapshot).\n * Does not subscribe to updates.\n *\n * @param query - Query to execute\n * @returns Array of matching keys\n */\n getResults(query: Query): K[] {\n const index = this.registry.getIndex(query);\n return index ? Array.from(index.getResults()) : [];\n }\n\n /**\n * Check if a query has active subscriptions.\n *\n * @param query - Query to check\n * @returns true if query has subscribers\n */\n hasSubscribers(query: Query): boolean {\n const hash = this.registry.hashQuery(query);\n const callbacks = this.subscriptions.get(hash);\n return callbacks !== undefined && callbacks.size > 0;\n }\n\n /**\n * Get subscriber count for a query.\n *\n * @param query - Query to check\n * @returns Number of subscribers\n */\n getSubscriberCount(query: Query): number {\n const hash = this.registry.hashQuery(query);\n const callbacks = this.subscriptions.get(hash);\n return callbacks?.size ?? 0;\n }\n\n /**\n * Notify of record addition.\n * Triggers subscription callbacks for affected queries.\n *\n * @param key - Record key\n * @param record - New record value\n */\n onRecordAdded(key: K, record: V): void {\n const changes = this.registry.onRecordAdded(key, record);\n this.notifySubscribers(key, record, changes, 'added');\n }\n\n /**\n * Notify of record update.\n * Triggers subscription callbacks for affected queries.\n *\n * @param key - Record key\n * @param oldRecord - Previous record value\n * @param newRecord - New record value\n */\n onRecordUpdated(key: K, oldRecord: V, newRecord: V): void {\n const changes = this.registry.onRecordUpdated(key, oldRecord, newRecord);\n this.notifySubscribers(key, newRecord, changes, 'updated');\n }\n\n /**\n * Notify of record removal.\n * Triggers subscription callbacks for affected queries.\n *\n * @param key - Record key\n * @param record - Removed record value\n */\n onRecordRemoved(key: K, record: V): void {\n const changes = this.registry.onRecordRemoved(key, record);\n this.notifySubscribers(key, record, changes, 'removed');\n }\n\n /**\n * Notify subscribers of changes.\n */\n private notifySubscribers(\n key: K,\n record: V,\n changes: Map<string, StandingQueryChange>,\n operation: 'added' | 'updated' | 'removed'\n ): void {\n for (const [hash, change] of changes) {\n const callbacks = this.subscriptions.get(hash);\n if (!callbacks || callbacks.size === 0) continue;\n\n const index = this.registry.getIndexByHash(hash);\n if (!index) continue;\n\n const query = index.getQuery();\n\n for (const callback of callbacks) {\n try {\n callback({\n type: 'delta',\n query,\n key,\n record,\n change,\n operation,\n newResultCount: index.getResultCount(),\n });\n } catch (error) {\n // Don't let one callback failure affect others\n console.error('LiveQueryManager callback error:', error);\n }\n }\n }\n }\n\n /**\n * Get the underlying registry for direct access.\n * Useful for testing and debugging.\n *\n * @returns StandingQueryRegistry instance\n */\n getRegistry(): StandingQueryRegistry<K, V> {\n return this.registry;\n }\n\n /**\n * Get all active query hashes.\n *\n * @returns Array of query hashes with active subscriptions\n */\n getActiveQueries(): string[] {\n return Array.from(this.subscriptions.keys());\n }\n\n /**\n * Get statistics about the manager.\n *\n * @returns Statistics object\n */\n getStats(): LiveQueryManagerStats {\n const registryStats = this.registry.getStats();\n const totalSubscribers = Array.from(this.subscriptions.values()).reduce(\n (sum, callbacks) => sum + callbacks.size,\n 0\n );\n\n return {\n ...registryStats,\n activeQueries: this.subscriptions.size,\n totalSubscribers,\n };\n }\n\n /**\n * Clear all subscriptions and indexes.\n */\n clear(): void {\n this.subscriptions.clear();\n this.registry.clear();\n }\n}\n\n/**\n * Statistics about the LiveQueryManager.\n */\nexport interface LiveQueryManagerStats extends StandingQueryRegistryStats {\n /** Number of active queries with subscribers */\n activeQueries: number;\n /** Total number of subscribers across all queries */\n totalSubscribers: number;\n}\n","/**\n * Types for Adaptive Indexing System (Phase 8.02)\n *\n * Defines interfaces for query pattern tracking, index suggestions,\n * and auto-indexing configuration.\n *\n * @module query/adaptive/types\n */\n\n/**\n * Query type for pattern tracking.\n * Matches the query types from QueryTypes.ts and indexes/types.ts\n */\nexport type TrackedQueryType =\n | 'eq'\n | 'neq'\n | 'gt'\n | 'gte'\n | 'lt'\n | 'lte'\n | 'between'\n | 'in'\n | 'has'\n | 'contains'\n | 'containsAll'\n | 'containsAny'\n | 'compound'; // Phase 9.03: Compound query patterns\n\n/**\n * Statistics for a single attribute + query type combination.\n */\nexport interface QueryStatistics {\n /** Attribute name being queried */\n attribute: string;\n /** Type of query (eq, gt, between, etc.) */\n queryType: TrackedQueryType;\n /** Number of times this pattern was queried */\n queryCount: number;\n /** Cumulative execution time in milliseconds */\n totalCost: number;\n /** Average execution time per query */\n averageCost: number;\n /** Timestamp of last query */\n lastQueried: number;\n /** Estimated result size (max observed) */\n estimatedCardinality: number;\n /** Whether an index exists for this attribute */\n hasIndex: boolean;\n}\n\n/**\n * Statistics for compound query patterns (Phase 9.03).\n * Tracks AND combinations of attributes for compound index suggestions.\n */\nexport interface CompoundQueryStatistics {\n /** Attribute names in the compound query (sorted) */\n attributes: string[];\n /** Combined key for identification */\n compoundKey: string;\n /** Number of times this pattern was queried */\n queryCount: number;\n /** Cumulative execution time in milliseconds */\n totalCost: number;\n /** Average execution time per query */\n averageCost: number;\n /** Timestamp of last query */\n lastQueried: number;\n /** Whether a compound index exists for this combination */\n hasCompoundIndex: boolean;\n}\n\n/**\n * Index type recommendation.\n */\nexport type RecommendedIndexType = 'hash' | 'navigable' | 'inverted' | 'compound';\n\n/**\n * Priority level for index suggestions.\n */\nexport type SuggestionPriority = 'high' | 'medium' | 'low';\n\n/**\n * Index suggestion generated by IndexAdvisor.\n */\nexport interface IndexSuggestion {\n /** Attribute to index (or compound key for compound indexes) */\n attribute: string;\n /** Recommended index type */\n indexType: RecommendedIndexType;\n /** Human-readable explanation */\n reason: string;\n /** Expected performance improvement multiplier */\n estimatedBenefit: number;\n /** Estimated memory overhead in bytes */\n estimatedCost: number;\n /** Priority based on query patterns */\n priority: SuggestionPriority;\n /** Query count that triggered this suggestion */\n queryCount: number;\n /** Average query cost in milliseconds */\n averageCost: number;\n /** For compound indexes: array of attribute names in order */\n compoundAttributes?: string[];\n}\n\n/**\n * Options for getting index suggestions.\n */\nexport interface IndexSuggestionOptions {\n /** Minimum query count to consider (default: 10) */\n minQueryCount?: number;\n /** Minimum average cost in ms to consider (default: 1) */\n minAverageCost?: number;\n /** Whether to exclude already indexed attributes (default: true) */\n excludeExistingIndexes?: boolean;\n /** Maximum number of suggestions to return (default: unlimited) */\n maxSuggestions?: number;\n}\n\n/**\n * Configuration for Index Advisor.\n */\nexport interface AdvisorConfig {\n /** Enable advisor mode (default: true) */\n enabled: boolean;\n /** Minimum query count before suggesting (default: 10) */\n minQueryCount?: number;\n /** Minimum average cost in ms to suggest (default: 1) */\n minAverageCost?: number;\n}\n\n/**\n * Callback for index creation events.\n */\nexport type IndexCreatedCallback = (attribute: string, indexType: RecommendedIndexType) => void;\n\n/**\n * Configuration for Auto-Index Manager.\n */\nexport interface AutoIndexConfig {\n /** Enable auto-indexing (default: false) */\n enabled: boolean;\n /** Number of queries before auto-creating index (default: 10) */\n threshold?: number;\n /** Maximum number of auto-created indexes (default: 20) */\n maxIndexes?: number;\n /** Callback when index is automatically created */\n onIndexCreated?: IndexCreatedCallback;\n}\n\n/**\n * Default indexing strategy.\n * - 'none': No automatic indexing (default)\n * - 'scalar': Index all top-level scalar (primitive) fields\n * - 'all': Index all fields including nested (not recommended)\n */\nexport type DefaultIndexingStrategy = 'none' | 'scalar' | 'all';\n\n/**\n * Complete adaptive indexing configuration.\n */\nexport interface AdaptiveIndexingConfig {\n /** Index Advisor configuration */\n advisor?: AdvisorConfig;\n /** Auto-Index Manager configuration */\n autoIndex?: AutoIndexConfig;\n}\n\n/**\n * Progress callback for lazy index building (Phase 9.01).\n */\nexport type IndexBuildProgressCallback = (\n attributeName: string,\n progress: number, // 0-100\n recordsProcessed: number,\n totalRecords: number\n) => void;\n\n/**\n * Extended options for IndexedLWWMap/IndexedORMap.\n */\nexport interface IndexedMapOptions {\n /** Adaptive indexing configuration */\n adaptiveIndexing?: AdaptiveIndexingConfig;\n /** Default indexing strategy (default: 'none') */\n defaultIndexing?: DefaultIndexingStrategy;\n /**\n * Enable lazy index building (Phase 9.01).\n * When true, indexes are not built until first query.\n * Default: false\n */\n lazyIndexBuilding?: boolean;\n /**\n * Callback for index building progress (Phase 9.01).\n * Called during lazy index materialization.\n */\n onIndexBuilding?: IndexBuildProgressCallback;\n}\n\n/**\n * Default values for adaptive indexing configuration.\n */\nexport const ADAPTIVE_INDEXING_DEFAULTS = {\n advisor: {\n enabled: true,\n minQueryCount: 10,\n minAverageCost: 1,\n },\n autoIndex: {\n enabled: false,\n threshold: 10,\n maxIndexes: 20,\n },\n} as const;\n\n/**\n * Sampling rate for query tracking (1 = track all, 10 = track 1 in 10).\n * Used to reduce overhead in high-throughput scenarios.\n */\nexport const TRACKING_SAMPLE_RATE = 1;\n\n/**\n * Memory overhead estimation constants (bytes per record).\n */\nexport const MEMORY_OVERHEAD_ESTIMATES = {\n /** Hash index overhead per record */\n hash: 24,\n /** Navigable index overhead per record */\n navigable: 32,\n /** Inverted index overhead per record (depends on token count) */\n inverted: 48,\n /** Compound index overhead per record (includes composite key) */\n compound: 40,\n} as const;\n","/**\n * QueryPatternTracker (Phase 8.02.1)\n *\n * Collects runtime statistics on query execution patterns.\n * Used by IndexAdvisor to generate index suggestions.\n *\n * Features:\n * - Tracks query count, cost, and cardinality per attribute\n * - Low overhead (< 1% of query time)\n * - Optional sampling for high-throughput scenarios\n * - Memory-bounded (circular buffer for old stats)\n *\n * @module query/adaptive/QueryPatternTracker\n */\n\nimport type { QueryStatistics, TrackedQueryType, CompoundQueryStatistics } from './types';\nimport { TRACKING_SAMPLE_RATE } from './types';\n\n/**\n * Options for QueryPatternTracker.\n */\nexport interface QueryPatternTrackerOptions {\n /**\n * Sampling rate: 1 = track all queries, N = track 1 in N queries.\n * Higher values reduce overhead but decrease accuracy.\n * Default: 1 (track all)\n */\n samplingRate?: number;\n\n /**\n * Maximum number of unique attribute+queryType combinations to track.\n * Prevents unbounded memory growth.\n * Default: 1000\n */\n maxTrackedPatterns?: number;\n\n /**\n * Time-to-live for statistics in milliseconds.\n * Statistics older than this are considered stale.\n * Default: 24 hours\n */\n statsTtl?: number;\n}\n\n/**\n * Internal storage key for statistics.\n */\ntype StatsKey = string;\n\n/**\n * Create a stats key from attribute and query type.\n */\nfunction makeStatsKey(attribute: string, queryType: TrackedQueryType): StatsKey {\n return `${attribute}:${queryType}`;\n}\n\n/**\n * Parse a stats key back to attribute and query type.\n */\nfunction parseStatsKey(key: StatsKey): { attribute: string; queryType: TrackedQueryType } {\n const colonIndex = key.lastIndexOf(':');\n return {\n attribute: key.slice(0, colonIndex),\n queryType: key.slice(colonIndex + 1) as TrackedQueryType,\n };\n}\n\n/**\n * QueryPatternTracker collects runtime statistics on query execution.\n *\n * @example\n * ```typescript\n * const tracker = new QueryPatternTracker();\n *\n * // Record queries during execution\n * tracker.recordQuery('category', 'eq', 5.2, 100, false);\n * tracker.recordQuery('category', 'eq', 4.8, 100, false);\n *\n * // Record compound AND queries (Phase 9.03)\n * tracker.recordCompoundQuery(['status', 'category'], 10.5, 50, false);\n *\n * // Get statistics\n * const stats = tracker.getStatistics();\n * // [{ attribute: 'category', queryType: 'eq', queryCount: 2, averageCost: 5.0, ... }]\n * ```\n */\nexport class QueryPatternTracker {\n private stats = new Map<StatsKey, QueryStatistics>();\n private compoundStats = new Map<string, CompoundQueryStatistics>();\n private queryCounter = 0;\n private readonly samplingRate: number;\n private readonly maxTrackedPatterns: number;\n private readonly statsTtl: number;\n\n constructor(options: QueryPatternTrackerOptions = {}) {\n this.samplingRate = options.samplingRate ?? TRACKING_SAMPLE_RATE;\n this.maxTrackedPatterns = options.maxTrackedPatterns ?? 1000;\n this.statsTtl = options.statsTtl ?? 24 * 60 * 60 * 1000; // 24 hours\n }\n\n /**\n * Record a query execution for pattern tracking.\n *\n * @param attribute - The attribute being queried\n * @param queryType - The type of query (eq, gt, between, etc.)\n * @param executionTime - Query execution time in milliseconds\n * @param resultSize - Number of results returned\n * @param hasIndex - Whether an index was used\n */\n recordQuery(\n attribute: string,\n queryType: TrackedQueryType,\n executionTime: number,\n resultSize: number,\n hasIndex: boolean\n ): void {\n // Sampling: skip if not selected\n this.queryCounter++;\n if (this.samplingRate > 1 && this.queryCounter % this.samplingRate !== 0) {\n return;\n }\n\n const key = makeStatsKey(attribute, queryType);\n const existing = this.stats.get(key);\n const now = Date.now();\n\n if (existing) {\n // Update existing statistics\n existing.queryCount++;\n existing.totalCost += executionTime;\n existing.averageCost = existing.totalCost / existing.queryCount;\n existing.lastQueried = now;\n existing.estimatedCardinality = Math.max(existing.estimatedCardinality, resultSize);\n existing.hasIndex = hasIndex;\n } else {\n // Check capacity before adding new entry\n if (this.stats.size >= this.maxTrackedPatterns) {\n this.evictOldest();\n }\n\n // Create new statistics entry\n this.stats.set(key, {\n attribute,\n queryType,\n queryCount: this.samplingRate, // Adjust for sampling\n totalCost: executionTime * this.samplingRate,\n averageCost: executionTime,\n lastQueried: now,\n estimatedCardinality: resultSize,\n hasIndex,\n });\n }\n }\n\n /**\n * Record a compound (AND) query execution for pattern tracking (Phase 9.03).\n *\n * @param attributes - Array of attribute names being queried together\n * @param executionTime - Query execution time in milliseconds\n * @param resultSize - Number of results returned\n * @param hasCompoundIndex - Whether a compound index was used\n */\n recordCompoundQuery(\n attributes: string[],\n executionTime: number,\n resultSize: number,\n hasCompoundIndex: boolean\n ): void {\n // Need at least 2 attributes for a compound query\n if (attributes.length < 2) return;\n\n // Sampling: skip if not selected\n this.queryCounter++;\n if (this.samplingRate > 1 && this.queryCounter % this.samplingRate !== 0) {\n return;\n }\n\n // Sort attributes for consistent key generation\n const sortedAttrs = [...attributes].sort();\n const compoundKey = sortedAttrs.join('+');\n const existing = this.compoundStats.get(compoundKey);\n const now = Date.now();\n\n if (existing) {\n // Update existing statistics\n existing.queryCount++;\n existing.totalCost += executionTime;\n existing.averageCost = existing.totalCost / existing.queryCount;\n existing.lastQueried = now;\n existing.hasCompoundIndex = hasCompoundIndex;\n } else {\n // Check capacity before adding new entry\n if (this.compoundStats.size >= this.maxTrackedPatterns) {\n this.evictOldestCompound();\n }\n\n // Create new statistics entry\n this.compoundStats.set(compoundKey, {\n attributes: sortedAttrs,\n compoundKey,\n queryCount: this.samplingRate, // Adjust for sampling\n totalCost: executionTime * this.samplingRate,\n averageCost: executionTime,\n lastQueried: now,\n hasCompoundIndex,\n });\n }\n }\n\n /**\n * Get all compound query statistics (Phase 9.03).\n *\n * @returns Array of compound query statistics, sorted by query count descending\n */\n getCompoundStatistics(): CompoundQueryStatistics[] {\n this.pruneStaleCompound();\n return Array.from(this.compoundStats.values()).sort((a, b) => b.queryCount - a.queryCount);\n }\n\n /**\n * Get compound statistics for a specific attribute combination.\n *\n * @param attributes - Array of attribute names\n * @returns Compound query statistics or undefined\n */\n getCompoundStats(attributes: string[]): CompoundQueryStatistics | undefined {\n const sortedAttrs = [...attributes].sort();\n const compoundKey = sortedAttrs.join('+');\n return this.compoundStats.get(compoundKey);\n }\n\n /**\n * Check if attributes appear in any tracked compound queries.\n *\n * @param attribute - The attribute name to check\n * @returns True if attribute is part of any compound query pattern\n */\n isInCompoundPattern(attribute: string): boolean {\n for (const stat of this.compoundStats.values()) {\n if (stat.attributes.includes(attribute)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Update compound index status.\n *\n * @param attributes - Array of attribute names\n * @param hasCompoundIndex - Whether a compound index exists\n */\n updateCompoundIndexStatus(attributes: string[], hasCompoundIndex: boolean): void {\n const sortedAttrs = [...attributes].sort();\n const compoundKey = sortedAttrs.join('+');\n const stat = this.compoundStats.get(compoundKey);\n if (stat) {\n stat.hasCompoundIndex = hasCompoundIndex;\n }\n }\n\n /**\n * Get all query statistics.\n *\n * @returns Array of query statistics, sorted by query count descending\n */\n getStatistics(): QueryStatistics[] {\n this.pruneStale();\n return Array.from(this.stats.values()).sort((a, b) => b.queryCount - a.queryCount);\n }\n\n /**\n * Get statistics for a specific attribute.\n *\n * @param attribute - The attribute name\n * @returns Array of query statistics for this attribute\n */\n getAttributeStats(attribute: string): QueryStatistics[] {\n return Array.from(this.stats.values()).filter((s) => s.attribute === attribute);\n }\n\n /**\n * Get statistics for a specific attribute and query type.\n *\n * @param attribute - The attribute name\n * @param queryType - The query type\n * @returns Query statistics or undefined\n */\n getStats(attribute: string, queryType: TrackedQueryType): QueryStatistics | undefined {\n const key = makeStatsKey(attribute, queryType);\n return this.stats.get(key);\n }\n\n /**\n * Check if an attribute has been queried.\n *\n * @param attribute - The attribute name\n * @returns True if the attribute has query statistics\n */\n hasStats(attribute: string): boolean {\n for (const key of this.stats.keys()) {\n if (key.startsWith(attribute + ':')) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get the total number of queries recorded.\n *\n * @returns Total query count across all patterns\n */\n getTotalQueryCount(): number {\n let total = 0;\n for (const stat of this.stats.values()) {\n total += stat.queryCount;\n }\n return total;\n }\n\n /**\n * Get the number of unique attribute+queryType patterns tracked.\n *\n * @returns Number of unique patterns\n */\n getPatternCount(): number {\n return this.stats.size;\n }\n\n /**\n * Update index status for an attribute.\n * Called when an index is added or removed.\n *\n * @param attribute - The attribute name\n * @param hasIndex - Whether an index now exists\n */\n updateIndexStatus(attribute: string, hasIndex: boolean): void {\n for (const [key, stat] of this.stats.entries()) {\n const parsed = parseStatsKey(key);\n if (parsed.attribute === attribute) {\n stat.hasIndex = hasIndex;\n }\n }\n }\n\n /**\n * Reset query count for an attribute after index creation.\n * This prevents immediate re-suggestion of the same index.\n *\n * @param attribute - The attribute name\n */\n resetAttributeStats(attribute: string): void {\n for (const key of Array.from(this.stats.keys())) {\n const parsed = parseStatsKey(key);\n if (parsed.attribute === attribute) {\n this.stats.delete(key);\n }\n }\n }\n\n /**\n * Clear all statistics.\n */\n clear(): void {\n this.stats.clear();\n this.compoundStats.clear();\n this.queryCounter = 0;\n }\n\n /**\n * Get a summary of tracking overhead.\n *\n * @returns Tracking overhead info\n */\n getTrackingInfo(): {\n patternsTracked: number;\n compoundPatternsTracked: number;\n totalQueries: number;\n samplingRate: number;\n memoryEstimate: number;\n } {\n // Rough memory estimate: ~200 bytes per stats entry, ~300 for compound (larger attribute arrays)\n const memoryEstimate = this.stats.size * 200 + this.compoundStats.size * 300;\n\n return {\n patternsTracked: this.stats.size,\n compoundPatternsTracked: this.compoundStats.size,\n totalQueries: this.queryCounter,\n samplingRate: this.samplingRate,\n memoryEstimate,\n };\n }\n\n /**\n * Evict the oldest (least recently queried) entry.\n */\n private evictOldest(): void {\n let oldestKey: StatsKey | null = null;\n let oldestTime = Infinity;\n\n for (const [key, stat] of this.stats.entries()) {\n if (stat.lastQueried < oldestTime) {\n oldestTime = stat.lastQueried;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n this.stats.delete(oldestKey);\n }\n }\n\n /**\n * Prune stale statistics older than TTL.\n */\n private pruneStale(): void {\n const cutoff = Date.now() - this.statsTtl;\n\n for (const [key, stat] of this.stats.entries()) {\n if (stat.lastQueried < cutoff) {\n this.stats.delete(key);\n }\n }\n }\n\n /**\n * Evict the oldest compound query entry (Phase 9.03).\n */\n private evictOldestCompound(): void {\n let oldestKey: string | null = null;\n let oldestTime = Infinity;\n\n for (const [key, stat] of this.compoundStats.entries()) {\n if (stat.lastQueried < oldestTime) {\n oldestTime = stat.lastQueried;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n this.compoundStats.delete(oldestKey);\n }\n }\n\n /**\n * Prune stale compound statistics (Phase 9.03).\n */\n private pruneStaleCompound(): void {\n const cutoff = Date.now() - this.statsTtl;\n\n for (const [key, stat] of this.compoundStats.entries()) {\n if (stat.lastQueried < cutoff) {\n this.compoundStats.delete(key);\n }\n }\n }\n}\n","/**\n * IndexAdvisor (Phase 8.02.2)\n *\n * Analyzes query patterns and generates index suggestions.\n * Used in production mode to help developers optimize their indexes.\n *\n * Features:\n * - Cost/benefit analysis for index suggestions\n * - Automatic index type selection based on query type\n * - Priority-based ranking of suggestions\n * - Memory cost estimation\n *\n * @module query/adaptive/IndexAdvisor\n */\n\nimport type { QueryPatternTracker } from './QueryPatternTracker';\nimport type {\n CompoundQueryStatistics,\n IndexSuggestion,\n IndexSuggestionOptions,\n QueryStatistics,\n RecommendedIndexType,\n SuggestionPriority,\n TrackedQueryType,\n} from './types';\nimport { ADAPTIVE_INDEXING_DEFAULTS, MEMORY_OVERHEAD_ESTIMATES } from './types';\n\n/**\n * IndexAdvisor analyzes query patterns and generates index suggestions.\n *\n * @example\n * ```typescript\n * const tracker = new QueryPatternTracker();\n * const advisor = new IndexAdvisor(tracker);\n *\n * // After application runs...\n * const suggestions = advisor.getSuggestions();\n * // [\n * // {\n * // attribute: 'category',\n * // indexType: 'hash',\n * // reason: 'Queried 1000× with average cost 5.2ms. Expected 500× speedup.',\n * // priority: 'high'\n * // }\n * // ]\n * ```\n */\nexport class IndexAdvisor {\n constructor(private readonly tracker: QueryPatternTracker) {}\n\n /**\n * Get index suggestions based on query patterns.\n *\n * @param options - Suggestion options\n * @returns Array of index suggestions sorted by priority\n */\n getSuggestions(options: IndexSuggestionOptions = {}): IndexSuggestion[] {\n const {\n minQueryCount = ADAPTIVE_INDEXING_DEFAULTS.advisor.minQueryCount,\n minAverageCost = ADAPTIVE_INDEXING_DEFAULTS.advisor.minAverageCost,\n excludeExistingIndexes = true,\n maxSuggestions,\n } = options;\n\n const stats = this.tracker.getStatistics();\n const suggestions: IndexSuggestion[] = [];\n\n // Group stats by attribute to avoid duplicate suggestions\n const attributeStats = this.groupByAttribute(stats);\n\n for (const [attribute, attrStats] of attributeStats.entries()) {\n // Find the best (most queried) pattern for this attribute\n const bestStat = this.findBestPattern(attrStats, excludeExistingIndexes);\n if (!bestStat) continue;\n\n // Skip if below thresholds\n if (bestStat.queryCount < minQueryCount) continue;\n if (bestStat.averageCost < minAverageCost) continue;\n\n // Generate suggestion\n const suggestion = this.generateSuggestion(bestStat, attrStats);\n if (suggestion) {\n suggestions.push(suggestion);\n }\n }\n\n // Phase 9.03: Add compound index suggestions\n const compoundSuggestions = this.getCompoundSuggestions({\n minQueryCount,\n minAverageCost,\n excludeExistingIndexes,\n });\n suggestions.push(...compoundSuggestions);\n\n // Sort by priority and benefit\n suggestions.sort((a, b) => {\n const priorityOrder = { high: 3, medium: 2, low: 1 };\n const priorityDiff = priorityOrder[b.priority] - priorityOrder[a.priority];\n if (priorityDiff !== 0) return priorityDiff;\n return b.estimatedBenefit - a.estimatedBenefit;\n });\n\n // Apply max suggestions limit\n if (maxSuggestions !== undefined && suggestions.length > maxSuggestions) {\n return suggestions.slice(0, maxSuggestions);\n }\n\n return suggestions;\n }\n\n /**\n * Get a suggestion for a specific attribute.\n *\n * @param attribute - The attribute name\n * @returns Index suggestion or null if not recommended\n */\n getSuggestionForAttribute(attribute: string): IndexSuggestion | null {\n const attrStats = this.tracker.getAttributeStats(attribute);\n if (attrStats.length === 0) return null;\n\n const bestStat = this.findBestPattern(attrStats, true);\n if (!bestStat) return null;\n\n return this.generateSuggestion(bestStat, attrStats);\n }\n\n /**\n * Check if an attribute should be indexed based on patterns.\n *\n * @param attribute - The attribute name\n * @param threshold - Minimum query count threshold\n * @returns True if attribute should be indexed\n */\n shouldIndex(attribute: string, threshold: number = ADAPTIVE_INDEXING_DEFAULTS.autoIndex.threshold!): boolean {\n const attrStats = this.tracker.getAttributeStats(attribute);\n if (attrStats.length === 0) return false;\n\n // Check if any pattern exceeds threshold\n for (const stat of attrStats) {\n if (!stat.hasIndex && stat.queryCount >= threshold) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Get recommended index type for a query type.\n *\n * @param queryType - The query type\n * @returns Recommended index type or null if not indexable\n */\n getRecommendedIndexType(queryType: TrackedQueryType): RecommendedIndexType | null {\n return this.selectIndexType(queryType);\n }\n\n /**\n * Group statistics by attribute.\n */\n private groupByAttribute(stats: QueryStatistics[]): Map<string, QueryStatistics[]> {\n const grouped = new Map<string, QueryStatistics[]>();\n\n for (const stat of stats) {\n const existing = grouped.get(stat.attribute);\n if (existing) {\n existing.push(stat);\n } else {\n grouped.set(stat.attribute, [stat]);\n }\n }\n\n return grouped;\n }\n\n /**\n * Find the best (most beneficial) pattern for an attribute.\n */\n private findBestPattern(\n stats: QueryStatistics[],\n excludeExistingIndexes: boolean\n ): QueryStatistics | null {\n let best: QueryStatistics | null = null;\n let bestScore = -1;\n\n for (const stat of stats) {\n // Skip if already indexed\n if (excludeExistingIndexes && stat.hasIndex) continue;\n\n // Skip if query type is not indexable\n if (!this.selectIndexType(stat.queryType)) continue;\n\n // Score: queryCount × averageCost (total potential savings)\n const score = stat.queryCount * stat.averageCost;\n if (score > bestScore) {\n bestScore = score;\n best = stat;\n }\n }\n\n return best;\n }\n\n /**\n * Generate a suggestion for a query pattern.\n */\n private generateSuggestion(\n stat: QueryStatistics,\n allAttrStats: QueryStatistics[]\n ): IndexSuggestion | null {\n const indexType = this.selectIndexType(stat.queryType);\n if (!indexType) return null;\n\n // Check if this index type would help other query patterns too\n const benefitingPatterns = this.countBenefitingPatterns(allAttrStats, indexType);\n\n const estimatedBenefit = this.estimateBenefit(stat, benefitingPatterns);\n const estimatedCost = this.estimateMemoryCost(stat, indexType);\n const priority = this.calculatePriority(stat, estimatedBenefit);\n\n // Calculate total query count across all patterns for this attribute\n const totalQueryCount = allAttrStats.reduce((sum, s) => sum + s.queryCount, 0);\n\n return {\n attribute: stat.attribute,\n indexType,\n reason: this.generateReason(stat, estimatedBenefit, benefitingPatterns),\n estimatedBenefit,\n estimatedCost,\n priority,\n queryCount: totalQueryCount,\n averageCost: stat.averageCost,\n };\n }\n\n /**\n * Select appropriate index type based on query type.\n */\n private selectIndexType(queryType: TrackedQueryType): RecommendedIndexType | null {\n switch (queryType) {\n case 'eq':\n case 'neq':\n case 'in':\n case 'has':\n return 'hash';\n\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte':\n case 'between':\n return 'navigable';\n\n case 'contains':\n case 'containsAll':\n case 'containsAny':\n return 'inverted';\n\n default:\n return null;\n }\n }\n\n /**\n * Count how many query patterns would benefit from an index type.\n */\n private countBenefitingPatterns(\n stats: QueryStatistics[],\n indexType: RecommendedIndexType\n ): number {\n let count = 0;\n\n for (const stat of stats) {\n if (stat.hasIndex) continue;\n const recommended = this.selectIndexType(stat.queryType);\n if (recommended === indexType) {\n count++;\n }\n }\n\n return count;\n }\n\n /**\n * Estimate performance benefit of adding an index.\n *\n * Heuristic based on:\n * - Full scan vs indexed: typically 100-1000× speedup\n * - Query frequency amplifies benefit\n */\n private estimateBenefit(stat: QueryStatistics, benefitingPatterns: number): number {\n // Base benefit depends on query cost (higher cost = more benefit)\n let baseBenefit: number;\n if (stat.averageCost > 10) {\n baseBenefit = 1000; // 1000× speedup for expensive queries\n } else if (stat.averageCost > 1) {\n baseBenefit = 100; // 100× speedup for medium queries\n } else {\n baseBenefit = 10; // 10× speedup for fast queries\n }\n\n // Scale by query frequency (more queries = more cumulative benefit)\n const frequencyMultiplier = Math.min(stat.queryCount / 10, 100);\n\n // Bonus for benefiting multiple patterns\n const patternBonus = benefitingPatterns > 1 ? benefitingPatterns : 1;\n\n return Math.floor(baseBenefit * frequencyMultiplier * patternBonus);\n }\n\n /**\n * Estimate memory cost of adding an index.\n */\n private estimateMemoryCost(stat: QueryStatistics, indexType: RecommendedIndexType): number {\n const bytesPerRecord = MEMORY_OVERHEAD_ESTIMATES[indexType];\n\n // Use estimated cardinality as record count estimate\n // Add 50% buffer for index structure overhead\n return Math.floor(stat.estimatedCardinality * bytesPerRecord * 1.5);\n }\n\n /**\n * Calculate priority based on query patterns and benefit.\n */\n private calculatePriority(stat: QueryStatistics, estimatedBenefit: number): SuggestionPriority {\n // High priority: frequently queried AND expensive\n if (stat.queryCount > 100 && stat.averageCost > 10) {\n return 'high';\n }\n\n // High priority: very frequently queried\n if (stat.queryCount > 500) {\n return 'high';\n }\n\n // Medium priority: moderate frequency OR cost\n if (stat.queryCount > 50 || stat.averageCost > 5) {\n return 'medium';\n }\n\n // Medium priority: high estimated benefit\n if (estimatedBenefit > 1000) {\n return 'medium';\n }\n\n return 'low';\n }\n\n /**\n * Generate human-readable reason for the suggestion.\n */\n private generateReason(\n stat: QueryStatistics,\n benefit: number,\n benefitingPatterns: number\n ): string {\n const costStr = stat.averageCost.toFixed(2);\n let reason = `Queried ${stat.queryCount}× with average cost ${costStr}ms. `;\n reason += `Expected ~${benefit}× cumulative speedup with index.`;\n\n if (benefitingPatterns > 1) {\n reason += ` Would benefit ${benefitingPatterns} query patterns.`;\n }\n\n return reason;\n }\n\n // ========================================\n // Phase 9.03: Compound Index Suggestions\n // ========================================\n\n /**\n * Get compound index suggestions based on AND query patterns.\n *\n * @param options - Suggestion options\n * @returns Array of compound index suggestions\n */\n getCompoundSuggestions(options: IndexSuggestionOptions = {}): IndexSuggestion[] {\n const {\n minQueryCount = ADAPTIVE_INDEXING_DEFAULTS.advisor.minQueryCount,\n minAverageCost = ADAPTIVE_INDEXING_DEFAULTS.advisor.minAverageCost,\n excludeExistingIndexes = true,\n } = options;\n\n const compoundStats = this.tracker.getCompoundStatistics();\n const suggestions: IndexSuggestion[] = [];\n\n for (const stat of compoundStats) {\n // Skip if already has compound index\n if (excludeExistingIndexes && stat.hasCompoundIndex) continue;\n\n // Skip if below thresholds\n if (stat.queryCount < minQueryCount) continue;\n if (stat.averageCost < minAverageCost) continue;\n\n const suggestion = this.generateCompoundSuggestion(stat);\n if (suggestion) {\n suggestions.push(suggestion);\n }\n }\n\n return suggestions;\n }\n\n /**\n * Get a suggestion for a specific compound attribute combination.\n *\n * @param attributes - Array of attribute names\n * @returns Compound index suggestion or null if not recommended\n */\n getCompoundSuggestionFor(attributes: string[]): IndexSuggestion | null {\n const stat = this.tracker.getCompoundStats(attributes);\n if (!stat) return null;\n\n return this.generateCompoundSuggestion(stat);\n }\n\n /**\n * Check if a compound index should be created for the given attributes.\n *\n * @param attributes - Array of attribute names\n * @param threshold - Minimum query count threshold\n * @returns True if compound index should be created\n */\n shouldCreateCompoundIndex(\n attributes: string[],\n threshold: number = ADAPTIVE_INDEXING_DEFAULTS.autoIndex.threshold!\n ): boolean {\n const stat = this.tracker.getCompoundStats(attributes);\n if (!stat) return false;\n\n return !stat.hasCompoundIndex && stat.queryCount >= threshold;\n }\n\n /**\n * Generate a suggestion for a compound query pattern.\n */\n private generateCompoundSuggestion(stat: CompoundQueryStatistics): IndexSuggestion | null {\n const estimatedBenefit = this.estimateCompoundBenefit(stat);\n const estimatedCost = this.estimateCompoundMemoryCost(stat);\n const priority = this.calculateCompoundPriority(stat, estimatedBenefit);\n\n return {\n attribute: stat.compoundKey,\n indexType: 'compound',\n reason: this.generateCompoundReason(stat, estimatedBenefit),\n estimatedBenefit,\n estimatedCost,\n priority,\n queryCount: stat.queryCount,\n averageCost: stat.averageCost,\n compoundAttributes: stat.attributes,\n };\n }\n\n /**\n * Estimate performance benefit of adding a compound index.\n *\n * Compound indexes provide significant speedup for AND queries:\n * - Eliminates intersection operations (100-1000× for each attribute)\n * - Single O(1) lookup instead of multiple index scans\n */\n private estimateCompoundBenefit(stat: CompoundQueryStatistics): number {\n // Base benefit: compound indexes are more powerful than individual indexes combined\n // Each additional attribute in the compound key roughly doubles the benefit\n const attributeMultiplier = Math.pow(2, stat.attributes.length - 1);\n\n // Cost-based benefit (higher cost = more benefit from indexing)\n let baseBenefit: number;\n if (stat.averageCost > 20) {\n baseBenefit = 1000; // Very expensive AND queries benefit most\n } else if (stat.averageCost > 5) {\n baseBenefit = 500;\n } else if (stat.averageCost > 1) {\n baseBenefit = 100;\n } else {\n baseBenefit = 50;\n }\n\n // Scale by query frequency\n const frequencyMultiplier = Math.min(stat.queryCount / 10, 100);\n\n return Math.floor(baseBenefit * attributeMultiplier * frequencyMultiplier);\n }\n\n /**\n * Estimate memory cost of adding a compound index.\n */\n private estimateCompoundMemoryCost(stat: CompoundQueryStatistics): number {\n const bytesPerRecord = MEMORY_OVERHEAD_ESTIMATES.compound;\n\n // Compound indexes have slightly higher overhead per attribute\n const attributeOverhead = stat.attributes.length * 8; // ~8 bytes per attr in composite key\n\n // Assume ~1000 records as baseline estimate\n const estimatedRecords = 1000;\n\n return Math.floor(estimatedRecords * (bytesPerRecord + attributeOverhead) * 1.5);\n }\n\n /**\n * Calculate priority for compound index suggestion.\n */\n private calculateCompoundPriority(\n stat: CompoundQueryStatistics,\n estimatedBenefit: number\n ): SuggestionPriority {\n // High priority: frequently queried compound patterns with high cost\n if (stat.queryCount > 100 && stat.averageCost > 10) {\n return 'high';\n }\n\n // High priority: very frequently queried\n if (stat.queryCount > 500) {\n return 'high';\n }\n\n // Medium priority: moderate frequency or cost\n if (stat.queryCount > 50 || stat.averageCost > 5) {\n return 'medium';\n }\n\n // Medium priority: high estimated benefit\n if (estimatedBenefit > 2000) {\n return 'medium';\n }\n\n return 'low';\n }\n\n /**\n * Generate human-readable reason for compound index suggestion.\n */\n private generateCompoundReason(stat: CompoundQueryStatistics, benefit: number): string {\n const costStr = stat.averageCost.toFixed(2);\n const attrList = stat.attributes.join(', ');\n let reason = `Compound AND query on [${attrList}] executed ${stat.queryCount}× with average cost ${costStr}ms. `;\n reason += `Expected ~${benefit}× cumulative speedup with compound index. `;\n reason += `Eliminates ${stat.attributes.length - 1} ResultSet intersection(s).`;\n\n return reason;\n }\n}\n","/**\n * AutoIndexManager (Phase 8.02.3)\n *\n * Automatically creates indexes based on query patterns.\n * Intended for development mode to simplify index management.\n *\n * Features:\n * - Automatic index creation after threshold queries\n * - Safety limits to prevent memory exhaustion\n * - Callback notifications for index creation events\n * - Integration with IndexAdvisor for type selection\n *\n * @module query/adaptive/AutoIndexManager\n */\n\nimport type { IndexAdvisor } from './IndexAdvisor';\nimport type { QueryPatternTracker } from './QueryPatternTracker';\nimport type {\n AutoIndexConfig,\n RecommendedIndexType,\n TrackedQueryType,\n} from './types';\nimport { ADAPTIVE_INDEXING_DEFAULTS } from './types';\nimport type { Attribute } from '../Attribute';\n\n/**\n * Interface for indexed map operations.\n * Used to decouple AutoIndexManager from IndexedLWWMap/IndexedORMap.\n */\nexport interface IndexableMap<K, V> {\n /** Get all current indexes */\n getIndexes(): { attribute: { name: string }; type: string }[];\n\n /** Check if attribute has an index */\n hasIndexOn(attributeName: string): boolean;\n\n /** Add a hash index */\n addHashIndex<A>(attribute: Attribute<V, A>): void;\n\n /** Add a navigable index */\n addNavigableIndex<A extends string | number>(attribute: Attribute<V, A>): void;\n\n /** Add an inverted index */\n addInvertedIndex<A extends string>(attribute: Attribute<V, A>): void;\n}\n\n/**\n * Registered attribute info for auto-indexing.\n */\ninterface RegisteredAttribute<V, A> {\n attribute: Attribute<V, A>;\n allowedIndexTypes?: RecommendedIndexType[];\n}\n\n/**\n * AutoIndexManager automatically creates indexes based on query patterns.\n *\n * @example\n * ```typescript\n * const manager = new AutoIndexManager(tracker, advisor, {\n * enabled: true,\n * threshold: 10,\n * maxIndexes: 20,\n * onIndexCreated: (attr, type) => console.log(`Created ${type} on ${attr}`)\n * });\n *\n * manager.registerAttribute(simpleAttribute('category', p => p.category));\n * manager.setMap(indexedMap);\n *\n * // After 10 queries on 'category', index is auto-created\n * ```\n */\nexport class AutoIndexManager<K, V> {\n private readonly config: Required<AutoIndexConfig>;\n private readonly attributeQueryCounts = new Map<string, number>();\n private readonly registeredAttributes = new Map<string, RegisteredAttribute<V, unknown>>();\n private readonly createdIndexes = new Set<string>();\n private map: IndexableMap<K, V> | null = null;\n\n constructor(\n private readonly tracker: QueryPatternTracker,\n private readonly advisor: IndexAdvisor,\n config: AutoIndexConfig\n ) {\n this.config = {\n enabled: config.enabled,\n threshold: config.threshold ?? ADAPTIVE_INDEXING_DEFAULTS.autoIndex.threshold!,\n maxIndexes: config.maxIndexes ?? ADAPTIVE_INDEXING_DEFAULTS.autoIndex.maxIndexes!,\n onIndexCreated: config.onIndexCreated ?? (() => {}),\n };\n }\n\n /**\n * Set the indexed map to create indexes on.\n */\n setMap(map: IndexableMap<K, V>): void {\n this.map = map;\n // Count existing indexes\n for (const index of map.getIndexes()) {\n this.createdIndexes.add(index.attribute.name);\n }\n }\n\n /**\n * Register an attribute that can be auto-indexed.\n *\n * @param attribute - The attribute to register\n * @param allowedIndexTypes - Optional list of allowed index types\n */\n registerAttribute<A>(\n attribute: Attribute<V, A>,\n allowedIndexTypes?: RecommendedIndexType[]\n ): void {\n this.registeredAttributes.set(attribute.name, {\n attribute: attribute as unknown as Attribute<V, unknown>,\n allowedIndexTypes,\n });\n }\n\n /**\n * Unregister an attribute.\n *\n * @param attributeName - Name of attribute to unregister\n */\n unregisterAttribute(attributeName: string): void {\n this.registeredAttributes.delete(attributeName);\n }\n\n /**\n * Check if an attribute is registered.\n *\n * @param attributeName - Name of attribute to check\n * @returns True if attribute is registered\n */\n hasAttribute(attributeName: string): boolean {\n return this.registeredAttributes.has(attributeName);\n }\n\n /**\n * Get a registered attribute.\n *\n * @param attributeName - Name of attribute\n * @returns The attribute or undefined\n */\n getAttribute(attributeName: string): Attribute<V, unknown> | undefined {\n return this.registeredAttributes.get(attributeName)?.attribute;\n }\n\n /**\n * Get all registered attribute names.\n *\n * @returns Array of registered attribute names\n */\n getRegisteredAttributeNames(): string[] {\n return Array.from(this.registeredAttributes.keys());\n }\n\n /**\n * Called when a query is executed. Tracks patterns and triggers auto-indexing.\n *\n * @param attribute - The attribute being queried\n * @param queryType - The type of query\n */\n onQueryExecuted(attribute: string, queryType: TrackedQueryType): void {\n if (!this.config.enabled) return;\n if (!this.map) return;\n\n // Skip if already indexed\n if (this.createdIndexes.has(attribute)) return;\n if (this.map.hasIndexOn(attribute)) {\n this.createdIndexes.add(attribute);\n return;\n }\n\n // Increment query count for this attribute\n const key = `${attribute}:${queryType}`;\n const count = (this.attributeQueryCounts.get(key) || 0) + 1;\n this.attributeQueryCounts.set(key, count);\n\n // Check if threshold reached\n if (count === this.config.threshold) {\n this.tryCreateIndex(attribute, queryType);\n }\n }\n\n /**\n * Check if we're at the index limit.\n *\n * @returns True if max indexes reached\n */\n isAtLimit(): boolean {\n if (!this.map) return false;\n return this.map.getIndexes().length >= this.config.maxIndexes;\n }\n\n /**\n * Get number of auto-created indexes.\n *\n * @returns Number of indexes created by this manager\n */\n getAutoCreatedIndexCount(): number {\n return this.createdIndexes.size;\n }\n\n /**\n * Get remaining index capacity.\n *\n * @returns Number of indexes that can still be created\n */\n getRemainingCapacity(): number {\n if (!this.map) return this.config.maxIndexes;\n return Math.max(0, this.config.maxIndexes - this.map.getIndexes().length);\n }\n\n /**\n * Reset query counts (e.g., after clearing data).\n */\n resetCounts(): void {\n this.attributeQueryCounts.clear();\n }\n\n /**\n * Get current configuration.\n */\n getConfig(): Readonly<AutoIndexConfig> {\n return this.config;\n }\n\n /**\n * Update configuration at runtime.\n *\n * @param updates - Partial config updates\n */\n updateConfig(updates: Partial<AutoIndexConfig>): void {\n if (updates.enabled !== undefined) {\n this.config.enabled = updates.enabled;\n }\n if (updates.threshold !== undefined) {\n this.config.threshold = updates.threshold;\n }\n if (updates.maxIndexes !== undefined) {\n this.config.maxIndexes = updates.maxIndexes;\n }\n if (updates.onIndexCreated !== undefined) {\n this.config.onIndexCreated = updates.onIndexCreated;\n }\n }\n\n /**\n * Try to create an index for the attribute.\n */\n private tryCreateIndex(attribute: string, queryType: TrackedQueryType): void {\n if (!this.map) return;\n\n // Safety check: don't exceed max indexes\n if (this.isAtLimit()) {\n // Optionally log warning\n return;\n }\n\n // Check if attribute is registered\n const registered = this.registeredAttributes.get(attribute);\n if (!registered) {\n // Attribute not registered - cannot create index\n return;\n }\n\n // Determine index type\n const indexType = this.advisor.getRecommendedIndexType(queryType);\n if (!indexType) return;\n\n // Check if index type is allowed for this attribute\n if (\n registered.allowedIndexTypes &&\n !registered.allowedIndexTypes.includes(indexType)\n ) {\n return;\n }\n\n // Create the index\n this.createIndex(attribute, indexType, registered.attribute);\n }\n\n /**\n * Create an index on the map.\n */\n private createIndex(\n attributeName: string,\n indexType: RecommendedIndexType,\n attribute: Attribute<V, unknown>\n ): void {\n if (!this.map) return;\n\n try {\n switch (indexType) {\n case 'hash':\n this.map.addHashIndex(attribute);\n break;\n case 'navigable':\n this.map.addNavigableIndex(attribute as Attribute<V, string | number>);\n break;\n case 'inverted':\n this.map.addInvertedIndex(attribute as Attribute<V, string>);\n break;\n }\n\n // Track creation\n this.createdIndexes.add(attributeName);\n\n // Update tracker - mark as indexed\n this.tracker.updateIndexStatus(attributeName, true);\n\n // Notify callback\n this.config.onIndexCreated(attributeName, indexType);\n } catch (error) {\n // Index creation failed - log but don't throw\n console.error(`AutoIndexManager: Failed to create ${indexType} index on '${attributeName}':`, error);\n }\n }\n}\n","/**\n * DefaultIndexingStrategy (Phase 8.02.4)\n *\n * Automatically indexes fields based on data structure analysis.\n * Applied on first record insertion to index scalar fields.\n *\n * Features:\n * - Runtime type introspection\n * - Heuristic-based index type selection\n * - Support for 'scalar' and 'all' strategies\n *\n * @module query/adaptive/DefaultIndexingStrategy\n */\n\nimport type { Attribute } from '../Attribute';\nimport { simpleAttribute } from '../Attribute';\nimport type { DefaultIndexingStrategy as StrategyType } from './types';\n\n/**\n * Field info extracted from a sample record.\n */\nexport interface FieldInfo {\n /** Field name (path for nested: 'address.city') */\n name: string;\n /** JavaScript type */\n type: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'null' | 'undefined';\n /** Whether this is a scalar (primitive) value */\n isScalar: boolean;\n /** Nested depth (0 = top-level) */\n depth: number;\n /** Sample value for heuristics */\n sampleValue: unknown;\n}\n\n/**\n * Index recommendation for a field.\n */\nexport interface FieldIndexRecommendation {\n /** Field name */\n field: string;\n /** Recommended index type */\n indexType: 'hash' | 'navigable';\n /** Reason for recommendation */\n reason: string;\n}\n\n/**\n * Interface for indexed map operations used by DefaultIndexingStrategy.\n */\nexport interface DefaultIndexableMap<V> {\n /** Add a hash index */\n addHashIndex<A>(attribute: Attribute<V, A>): void;\n\n /** Add a navigable index */\n addNavigableIndex<A extends string | number>(attribute: Attribute<V, A>): void;\n\n /** Check if attribute has an index */\n hasIndexOn(attributeName: string): boolean;\n}\n\n/**\n * DefaultIndexingStrategy analyzes record structure and creates indexes.\n *\n * @example\n * ```typescript\n * const strategy = new DefaultIndexingStrategy<Product>('scalar');\n *\n * // On first record insertion\n * strategy.applyToMap(indexedMap, {\n * id: '1',\n * name: 'Widget',\n * price: 29.99,\n * inStock: true\n * });\n *\n * // Creates:\n * // - HashIndex on 'id'\n * // - HashIndex on 'name'\n * // - NavigableIndex on 'price'\n * // - HashIndex on 'inStock'\n * ```\n */\nexport class DefaultIndexingStrategy<V> {\n private applied = false;\n\n constructor(private readonly strategy: StrategyType) {}\n\n /**\n * Check if strategy has been applied.\n */\n isApplied(): boolean {\n return this.applied;\n }\n\n /**\n * Analyze a sample record and apply indexes to the map.\n *\n * @param map - The indexed map to add indexes to\n * @param sample - A sample record to analyze\n */\n applyToMap(map: DefaultIndexableMap<V>, sample: V): void {\n if (this.strategy === 'none') return;\n if (this.applied) return;\n\n const recommendations = this.analyzeAndRecommend(sample);\n\n for (const rec of recommendations) {\n if (map.hasIndexOn(rec.field)) continue;\n\n const attribute = this.createAttribute(rec.field);\n\n try {\n if (rec.indexType === 'hash') {\n map.addHashIndex(attribute);\n } else {\n map.addNavigableIndex(attribute as Attribute<V, string | number>);\n }\n } catch (error) {\n // Log but don't fail if index creation fails\n console.warn(`DefaultIndexing: Failed to create ${rec.indexType} index on '${rec.field}':`, error);\n }\n }\n\n this.applied = true;\n }\n\n /**\n * Analyze a sample record and return index recommendations.\n *\n * @param sample - A sample record to analyze\n * @returns Array of field index recommendations\n */\n analyzeAndRecommend(sample: V): FieldIndexRecommendation[] {\n const fields = this.extractFields(sample, '', 0);\n const recommendations: FieldIndexRecommendation[] = [];\n\n for (const field of fields) {\n const rec = this.recommendIndex(field);\n if (rec) {\n recommendations.push(rec);\n }\n }\n\n return recommendations;\n }\n\n /**\n * Extract field info from a record recursively.\n */\n private extractFields(value: unknown, prefix: string, depth: number): FieldInfo[] {\n const fields: FieldInfo[] = [];\n\n if (value === null || value === undefined) {\n return fields;\n }\n\n if (typeof value !== 'object') {\n return fields;\n }\n\n // Handle arrays (skip for now - need MultiValueAttribute)\n if (Array.isArray(value)) {\n return fields;\n }\n\n for (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n const fieldName = prefix ? `${prefix}.${key}` : key;\n const fieldType = this.getType(val);\n\n fields.push({\n name: fieldName,\n type: fieldType,\n isScalar: this.isScalar(fieldType),\n depth,\n sampleValue: val,\n });\n\n // Recurse into nested objects if strategy is 'all'\n if (this.strategy === 'all' && fieldType === 'object' && val !== null) {\n fields.push(...this.extractFields(val, fieldName, depth + 1));\n }\n }\n\n return fields;\n }\n\n /**\n * Get JavaScript type of a value.\n */\n private getType(value: unknown): FieldInfo['type'] {\n if (value === null) return 'null';\n if (value === undefined) return 'undefined';\n if (Array.isArray(value)) return 'array';\n\n const type = typeof value;\n if (type === 'string') return 'string';\n if (type === 'number') return 'number';\n if (type === 'boolean') return 'boolean';\n if (type === 'object') return 'object';\n\n return 'undefined';\n }\n\n /**\n * Check if a type is scalar (primitive).\n */\n private isScalar(type: FieldInfo['type']): boolean {\n return type === 'string' || type === 'number' || type === 'boolean';\n }\n\n /**\n * Recommend an index for a field.\n */\n private recommendIndex(field: FieldInfo): FieldIndexRecommendation | null {\n // Only index scalars\n if (!field.isScalar) return null;\n\n // Only index top-level for 'scalar' strategy\n if (this.strategy === 'scalar' && field.depth > 0) {\n return null;\n }\n\n // Skip fields that look like high-cardinality text (descriptions, etc.)\n if (field.type === 'string' && this.looksLikeDescription(field)) {\n return null;\n }\n\n // Determine index type\n const indexType = this.selectIndexType(field);\n const reason = this.generateReason(field, indexType);\n\n return {\n field: field.name,\n indexType,\n reason,\n };\n }\n\n /**\n * Check if a string field looks like a description (high-cardinality text).\n */\n private looksLikeDescription(field: FieldInfo): boolean {\n if (field.type !== 'string') return false;\n\n // Heuristic: skip if name contains common description-like words\n const descriptionPatterns = [\n 'description',\n 'desc',\n 'content',\n 'body',\n 'text',\n 'message',\n 'comment',\n 'note',\n 'bio',\n 'summary',\n 'abstract',\n ];\n\n const lowerName = field.name.toLowerCase();\n for (const pattern of descriptionPatterns) {\n if (lowerName.includes(pattern)) {\n return true;\n }\n }\n\n // Heuristic: skip if sample value is long (> 100 chars)\n if (typeof field.sampleValue === 'string' && field.sampleValue.length > 100) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Select appropriate index type for a field.\n */\n private selectIndexType(field: FieldInfo): 'hash' | 'navigable' {\n // Numbers are usually range-queried\n if (field.type === 'number') {\n // Exception: fields ending in 'Id' are usually equality\n if (field.name.toLowerCase().endsWith('id')) {\n return 'hash';\n }\n return 'navigable';\n }\n\n // Booleans are always equality\n if (field.type === 'boolean') {\n return 'hash';\n }\n\n // Strings: check for common patterns\n if (field.type === 'string') {\n // IDs are equality\n if (field.name.toLowerCase().endsWith('id') || field.name.toLowerCase() === 'id') {\n return 'hash';\n }\n\n // Dates/timestamps might benefit from range queries\n if (this.looksLikeDate(field)) {\n return 'navigable';\n }\n\n // Default: hash for strings\n return 'hash';\n }\n\n return 'hash';\n }\n\n /**\n * Check if a field looks like a date/timestamp.\n */\n private looksLikeDate(field: FieldInfo): boolean {\n const lowerName = field.name.toLowerCase();\n\n // Check for explicit date/time patterns\n const datePatterns = ['date', 'time', 'timestamp'];\n for (const pattern of datePatterns) {\n if (lowerName.includes(pattern)) {\n return true;\n }\n }\n\n // Check for common date-related suffixes (must end with these)\n const dateSuffixes = ['_at', 'At', 'created', 'updated'];\n for (const suffix of dateSuffixes) {\n if (field.name.endsWith(suffix)) {\n return true;\n }\n }\n\n // Check if sample value looks like ISO date\n if (typeof field.sampleValue === 'string') {\n const isoDatePattern = /^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2})?/;\n if (isoDatePattern.test(field.sampleValue)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Generate reason for the recommendation.\n */\n private generateReason(field: FieldInfo, indexType: 'hash' | 'navigable'): string {\n if (indexType === 'navigable') {\n if (field.type === 'number') {\n return `Numeric field '${field.name}' likely used for range queries`;\n }\n if (this.looksLikeDate(field)) {\n return `Date-like field '${field.name}' likely used for range queries`;\n }\n }\n\n if (field.name.toLowerCase().endsWith('id') || field.name.toLowerCase() === 'id') {\n return `ID field '${field.name}' typically used for equality lookups`;\n }\n\n if (field.type === 'boolean') {\n return `Boolean field '${field.name}' used for equality filtering`;\n }\n\n return `Scalar field '${field.name}' of type ${field.type}`;\n }\n\n /**\n * Create an attribute for a field path.\n */\n private createAttribute(fieldPath: string): Attribute<V, unknown> {\n const parts = fieldPath.split('.');\n\n if (parts.length === 1) {\n // Simple top-level field\n return simpleAttribute(fieldPath, (record: V) => {\n return (record as Record<string, unknown>)[fieldPath];\n });\n }\n\n // Nested field (e.g., 'address.city')\n return simpleAttribute(fieldPath, (record: V) => {\n let current: unknown = record;\n for (const part of parts) {\n if (current === null || current === undefined) return undefined;\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n });\n }\n}\n","/**\n * Reciprocal Rank Fusion (RRF)\n *\n * Implements RRF algorithm for merging ranked results from multiple search methods.\n * Used in hybrid queries that combine exact matches, range queries, and full-text search.\n *\n * Formula: RRF_score(d) = Σ 1 / (k + rank_i(d))\n *\n * Reference: Cormack, Clarke, Buettcher (2009) - \"Reciprocal Rank Fusion outperforms\n * Condorcet and individual Rank Learning Methods\"\n *\n * @module search/ReciprocalRankFusion\n */\n\n/**\n * A ranked result from a single search method.\n */\nexport interface RankedResult {\n /** Unique document identifier */\n docId: string;\n /** Original score from the search method (e.g., BM25 score) */\n score: number;\n /** Source of this result: 'exact' | 'fulltext' | 'range' | custom */\n source: string;\n}\n\n/**\n * Configuration for RRF algorithm.\n */\nexport interface RRFConfig {\n /**\n * Ranking constant k.\n * Higher values reduce the impact of high rankings.\n * Default: 60 (standard value from literature)\n */\n k?: number;\n}\n\n/**\n * Merged result with combined RRF score.\n */\nexport interface MergedResult {\n /** Unique document identifier */\n docId: string;\n /** Combined RRF score */\n score: number;\n /** Combined sources (e.g., \"exact+fulltext\") */\n source: string;\n /** Original scores from each source */\n originalScores: Record<string, number>;\n}\n\n/**\n * Reciprocal Rank Fusion implementation.\n *\n * Merges results from multiple ranked lists using the RRF formula.\n * Documents appearing in multiple result sets get boosted scores.\n *\n * @example\n * ```typescript\n * const rrf = new ReciprocalRankFusion({ k: 60 });\n *\n * const exactResults = [\n * { docId: 'doc1', score: 1.0, source: 'exact' },\n * { docId: 'doc2', score: 1.0, source: 'exact' },\n * ];\n *\n * const ftsResults = [\n * { docId: 'doc2', score: 2.5, source: 'fulltext' },\n * { docId: 'doc3', score: 1.8, source: 'fulltext' },\n * ];\n *\n * const merged = rrf.merge([exactResults, ftsResults]);\n * // doc2 ranks highest (appears in both sets)\n * ```\n */\nexport class ReciprocalRankFusion {\n private readonly k: number;\n\n constructor(config?: RRFConfig) {\n this.k = config?.k ?? 60;\n }\n\n /**\n * Merge multiple ranked result lists using RRF.\n *\n * Formula: RRF_score(d) = Σ 1 / (k + rank_i(d))\n *\n * @param resultSets - Array of ranked result lists from different search methods\n * @returns Merged results sorted by RRF score (descending)\n */\n merge(resultSets: RankedResult[][]): MergedResult[] {\n // Filter out empty sets\n const nonEmptySets = resultSets.filter((set) => set.length > 0);\n\n if (nonEmptySets.length === 0) {\n return [];\n }\n\n // Map to accumulate RRF scores and track sources\n const scoreMap = new Map<\n string,\n {\n rrfScore: number;\n sources: Set<string>;\n originalScores: Record<string, number>;\n }\n >();\n\n // Process each result set\n for (const resultSet of nonEmptySets) {\n for (let rank = 0; rank < resultSet.length; rank++) {\n const result = resultSet[rank];\n const { docId, score, source } = result;\n\n // RRF formula: 1 / (k + rank)\n // Note: rank is 0-indexed, but RRF typically uses 1-indexed ranks\n const rrfContribution = 1 / (this.k + rank + 1);\n\n const existing = scoreMap.get(docId);\n if (existing) {\n existing.rrfScore += rrfContribution;\n existing.sources.add(source);\n existing.originalScores[source] = score;\n } else {\n scoreMap.set(docId, {\n rrfScore: rrfContribution,\n sources: new Set([source]),\n originalScores: { [source]: score },\n });\n }\n }\n }\n\n // Convert to array and sort by RRF score\n const merged: MergedResult[] = [];\n for (const [docId, data] of scoreMap) {\n merged.push({\n docId,\n score: data.rrfScore,\n source: Array.from(data.sources).sort().join('+'),\n originalScores: data.originalScores,\n });\n }\n\n // Sort by score descending\n merged.sort((a, b) => b.score - a.score);\n\n return merged;\n }\n\n /**\n * Merge with weighted RRF for different method priorities.\n *\n * Weighted formula: RRF_score(d) = Σ weight_i * (1 / (k + rank_i(d)))\n *\n * @param resultSets - Array of ranked result lists\n * @param weights - Weights for each result set (same order as resultSets)\n * @returns Merged results sorted by weighted RRF score (descending)\n *\n * @example\n * ```typescript\n * const rrf = new ReciprocalRankFusion();\n *\n * // Prioritize exact matches (weight 2.0) over FTS (weight 1.0)\n * const merged = rrf.mergeWeighted(\n * [exactResults, ftsResults],\n * [2.0, 1.0]\n * );\n * ```\n */\n mergeWeighted(resultSets: RankedResult[][], weights: number[]): MergedResult[] {\n // Validate weights array length\n if (weights.length !== resultSets.length) {\n throw new Error(\n `Weights array length (${weights.length}) must match resultSets length (${resultSets.length})`\n );\n }\n\n // Filter out empty sets (and their corresponding weights)\n const nonEmptyPairs: Array<{ resultSet: RankedResult[]; weight: number }> = [];\n for (let i = 0; i < resultSets.length; i++) {\n if (resultSets[i].length > 0) {\n nonEmptyPairs.push({ resultSet: resultSets[i], weight: weights[i] });\n }\n }\n\n if (nonEmptyPairs.length === 0) {\n return [];\n }\n\n // Map to accumulate weighted RRF scores\n const scoreMap = new Map<\n string,\n {\n rrfScore: number;\n sources: Set<string>;\n originalScores: Record<string, number>;\n }\n >();\n\n // Process each result set with its weight\n for (const { resultSet, weight } of nonEmptyPairs) {\n for (let rank = 0; rank < resultSet.length; rank++) {\n const result = resultSet[rank];\n const { docId, score, source } = result;\n\n // Weighted RRF formula: weight * (1 / (k + rank))\n const rrfContribution = weight * (1 / (this.k + rank + 1));\n\n const existing = scoreMap.get(docId);\n if (existing) {\n existing.rrfScore += rrfContribution;\n existing.sources.add(source);\n existing.originalScores[source] = score;\n } else {\n scoreMap.set(docId, {\n rrfScore: rrfContribution,\n sources: new Set([source]),\n originalScores: { [source]: score },\n });\n }\n }\n }\n\n // Convert to array and sort by RRF score\n const merged: MergedResult[] = [];\n for (const [docId, data] of scoreMap) {\n merged.push({\n docId,\n score: data.rrfScore,\n source: Array.from(data.sources).sort().join('+'),\n originalScores: data.originalScores,\n });\n }\n\n // Sort by score descending\n merged.sort((a, b) => b.score - a.score);\n\n return merged;\n }\n\n /**\n * Get the k constant used for RRF calculation.\n */\n getK(): number {\n return this.k;\n }\n}\n","/**\n * IndexedLWWMap Implementation\n *\n * LWWMap with index support for O(1) to O(log N) queries.\n * Wraps LWWMap with indexing capabilities using the Wrapper Pattern.\n *\n * Features:\n * - Hash and Navigable indexes for efficient queries\n * - Live queries with StandingQueryIndex\n * - Automatic index updates on CRDT operations\n * - Cost-based query optimization\n * - Adaptive indexing with query pattern tracking (Phase 8.02)\n *\n * @module IndexedLWWMap\n */\n\nimport { LWWMap, LWWRecord } from './LWWMap';\nimport { HLC } from './HLC';\nimport { IndexRegistry, IndexRegistryStats } from './query/IndexRegistry';\nimport { QueryOptimizer } from './query/QueryOptimizer';\nimport { StandingQueryRegistry } from './query/StandingQueryRegistry';\nimport {\n LiveQueryManager,\n LiveQueryCallback,\n LiveQueryEvent,\n} from './query/LiveQueryManager';\nimport type { Index, IndexStats, IndexQuery } from './query/indexes/types';\nimport { HashIndex } from './query/indexes/HashIndex';\nimport { NavigableIndex } from './query/indexes/NavigableIndex';\nimport { FallbackIndex } from './query/indexes/FallbackIndex';\nimport { InvertedIndex } from './query/indexes/InvertedIndex';\nimport { TokenizationPipeline } from './query/tokenization';\nimport {\n LazyHashIndex,\n LazyNavigableIndex,\n LazyInvertedIndex,\n} from './query/indexes/lazy';\nimport { Attribute, simpleAttribute } from './query/Attribute';\nimport type { Query, QueryPlan, PlanStep, SimpleQueryNode } from './query/QueryTypes';\nimport { isSimpleQuery } from './query/QueryTypes';\nimport type { ResultSet } from './query/resultset/ResultSet';\nimport { SetResultSet } from './query/resultset/SetResultSet';\nimport { IntersectionResultSet } from './query/resultset/IntersectionResultSet';\nimport { UnionResultSet } from './query/resultset/UnionResultSet';\nimport { FilteringResultSet } from './query/resultset/FilteringResultSet';\nimport { evaluatePredicate, PredicateNode } from './predicate';\n\n// Adaptive indexing imports (Phase 8.02)\nimport {\n QueryPatternTracker,\n IndexAdvisor,\n AutoIndexManager,\n DefaultIndexingStrategy,\n} from './query/adaptive';\nimport type {\n IndexedMapOptions,\n IndexSuggestion,\n IndexSuggestionOptions,\n QueryStatistics,\n TrackedQueryType,\n RecommendedIndexType,\n IndexBuildProgressCallback,\n} from './query/adaptive/types';\nimport { ADAPTIVE_INDEXING_DEFAULTS } from './query/adaptive/types';\nimport type { LazyIndex } from './query/indexes/lazy';\n\n/**\n * LWWMap with index support for O(1) to O(log N) queries.\n *\n * K = key type (extends string for compatibility)\n * V = value type\n */\nexport class IndexedLWWMap<K extends string, V> extends LWWMap<K, V> {\n private indexRegistry: IndexRegistry<K, V>;\n private standingQueryRegistry: StandingQueryRegistry<K, V>;\n private liveQueryManager: LiveQueryManager<K, V>;\n private queryOptimizer: QueryOptimizer<K, V>;\n\n // Adaptive indexing (Phase 8.02)\n private readonly queryTracker: QueryPatternTracker;\n private readonly indexAdvisor: IndexAdvisor;\n private readonly autoIndexManager: AutoIndexManager<K, V> | null;\n private readonly defaultIndexingStrategy: DefaultIndexingStrategy<V> | null;\n private readonly options: IndexedMapOptions;\n\n constructor(hlc: HLC, options: IndexedMapOptions = {}) {\n super(hlc);\n this.options = options;\n\n this.indexRegistry = new IndexRegistry();\n this.standingQueryRegistry = new StandingQueryRegistry({\n getRecord: (key) => this.get(key),\n getAllEntries: () => this.entries(),\n });\n this.liveQueryManager = new LiveQueryManager({\n getRecord: (key) => this.get(key),\n getAllEntries: () => this.entries(),\n });\n this.queryOptimizer = new QueryOptimizer({\n indexRegistry: this.indexRegistry,\n standingQueryRegistry: this.standingQueryRegistry,\n });\n\n // Set up fallback index for full scans\n this.indexRegistry.setFallbackIndex(\n new FallbackIndex<K, V>(\n () => this.keys(),\n (key) => this.get(key),\n (record, query) => this.matchesIndexQuery(record, query)\n )\n );\n\n // Initialize adaptive indexing (Phase 8.02)\n this.queryTracker = new QueryPatternTracker();\n this.indexAdvisor = new IndexAdvisor(this.queryTracker);\n\n // Initialize auto-index manager if enabled\n if (options.adaptiveIndexing?.autoIndex?.enabled) {\n this.autoIndexManager = new AutoIndexManager(\n this.queryTracker,\n this.indexAdvisor,\n options.adaptiveIndexing.autoIndex\n );\n this.autoIndexManager.setMap(this);\n } else {\n this.autoIndexManager = null;\n }\n\n // Initialize default indexing strategy\n if (options.defaultIndexing && options.defaultIndexing !== 'none') {\n this.defaultIndexingStrategy = new DefaultIndexingStrategy<V>(options.defaultIndexing);\n } else {\n this.defaultIndexingStrategy = null;\n }\n }\n\n // ==================== Index Management ====================\n\n /**\n * Add a hash index on an attribute.\n * If lazyIndexBuilding is enabled, creates a LazyHashIndex instead.\n *\n * @param attribute - Attribute to index\n * @returns Created HashIndex (or LazyHashIndex)\n */\n addHashIndex<A>(attribute: Attribute<V, A>): HashIndex<K, V, A> | LazyHashIndex<K, V, A> {\n if (this.options.lazyIndexBuilding) {\n const index = new LazyHashIndex<K, V, A>(attribute, {\n onProgress: this.options.onIndexBuilding,\n });\n this.indexRegistry.addIndex(index);\n this.buildIndex(index);\n return index;\n }\n\n const index = new HashIndex<K, V, A>(attribute);\n this.indexRegistry.addIndex(index);\n this.buildIndex(index);\n return index;\n }\n\n /**\n * Add a navigable index on an attribute.\n * Navigable indexes support range queries (gt, gte, lt, lte, between).\n * If lazyIndexBuilding is enabled, creates a LazyNavigableIndex instead.\n *\n * @param attribute - Attribute to index\n * @param comparator - Optional custom comparator\n * @returns Created NavigableIndex (or LazyNavigableIndex)\n */\n addNavigableIndex<A extends string | number>(\n attribute: Attribute<V, A>,\n comparator?: (a: A, b: A) => number\n ): NavigableIndex<K, V, A> | LazyNavigableIndex<K, V, A> {\n if (this.options.lazyIndexBuilding) {\n const index = new LazyNavigableIndex<K, V, A>(attribute, comparator, {\n onProgress: this.options.onIndexBuilding,\n });\n this.indexRegistry.addIndex(index);\n this.buildIndex(index);\n return index;\n }\n\n const index = new NavigableIndex<K, V, A>(attribute, comparator);\n this.indexRegistry.addIndex(index);\n this.buildIndex(index);\n return index;\n }\n\n /**\n * Add an inverted index for full-text search on an attribute.\n * Inverted indexes support text search queries (contains, containsAll, containsAny).\n * If lazyIndexBuilding is enabled, creates a LazyInvertedIndex instead.\n *\n * @param attribute - Text attribute to index\n * @param pipeline - Optional custom tokenization pipeline\n * @returns Created InvertedIndex (or LazyInvertedIndex)\n *\n * @example\n * ```typescript\n * const nameAttr = simpleAttribute<Product, string>('name', p => p.name);\n * products.addInvertedIndex(nameAttr);\n *\n * // Search for products containing \"wireless\"\n * products.query({ type: 'contains', attribute: 'name', value: 'wireless' });\n * ```\n */\n addInvertedIndex<A extends string = string>(\n attribute: Attribute<V, A>,\n pipeline?: TokenizationPipeline\n ): InvertedIndex<K, V, A> | LazyInvertedIndex<K, V, A> {\n if (this.options.lazyIndexBuilding) {\n const index = new LazyInvertedIndex<K, V, A>(attribute, pipeline, {\n onProgress: this.options.onIndexBuilding,\n });\n this.indexRegistry.addIndex(index);\n this.buildIndex(index);\n return index;\n }\n\n const index = new InvertedIndex<K, V, A>(attribute, pipeline);\n this.indexRegistry.addIndex(index);\n this.buildIndex(index);\n return index;\n }\n\n /**\n * Add a custom index.\n *\n * @param index - Index to add\n */\n addIndex<A>(index: Index<K, V, A>): void {\n this.indexRegistry.addIndex(index);\n this.buildIndex(index);\n }\n\n /**\n * Remove an index.\n *\n * @param index - Index to remove\n * @returns true if index was found and removed\n */\n removeIndex<A>(index: Index<K, V, A>): boolean {\n return this.indexRegistry.removeIndex(index);\n }\n\n /**\n * Get all indexes.\n *\n * @returns Array of all indexes\n */\n getIndexes(): Index<K, V, unknown>[] {\n return this.indexRegistry.getAllIndexes();\n }\n\n /**\n * Check if an attribute is indexed.\n *\n * @param attributeName - Attribute name\n * @returns true if attribute has indexes\n */\n hasIndexOn(attributeName: string): boolean {\n return this.indexRegistry.hasIndex(attributeName);\n }\n\n /**\n * Build index from existing data.\n */\n private buildIndex<A>(index: Index<K, V, A>): void {\n for (const [key, value] of this.entries()) {\n index.add(key, value);\n }\n }\n\n // ==================== Query Execution ====================\n\n /**\n * Execute a query using indexes.\n * Returns lazy ResultSet of matching keys.\n *\n * Also tracks query patterns for adaptive indexing (Phase 8.02).\n *\n * @param query - Query to execute\n * @returns ResultSet of matching keys\n */\n query(query: Query): ResultSet<K> {\n const start = performance.now();\n const plan = this.queryOptimizer.optimize(query);\n const resultSet = this.executePlan(plan.root);\n\n // Materialize for statistics (Phase 8.02)\n const results = resultSet.toArray();\n const duration = performance.now() - start;\n\n // Track query pattern for adaptive indexing\n this.trackQueryPattern(query, duration, results.length, plan.usesIndexes);\n\n // Return a new SetResultSet with the materialized results\n return new SetResultSet(new Set(results), resultSet.getRetrievalCost());\n }\n\n /**\n * Execute a query and return materialized results.\n * Returns array of [key, value] pairs.\n *\n * @param query - Query to execute\n * @returns Array of [key, value] pairs\n */\n queryEntries(query: Query): [K, V][] {\n const keys = this.query(query);\n const results: [K, V][] = [];\n\n for (const key of keys) {\n const value = this.get(key);\n if (value !== undefined) {\n results.push([key, value]);\n }\n }\n\n return results;\n }\n\n /**\n * Execute a query and return matching values.\n *\n * @param query - Query to execute\n * @returns Array of matching values\n */\n queryValues(query: Query): V[] {\n const keys = this.query(query);\n const results: V[] = [];\n\n for (const key of keys) {\n const value = this.get(key);\n if (value !== undefined) {\n results.push(value);\n }\n }\n\n return results;\n }\n\n /**\n * Count matching records without materializing results.\n *\n * @param query - Query to execute\n * @returns Number of matching records\n */\n count(query: Query): number {\n const resultSet = this.query(query);\n return resultSet.size();\n }\n\n /**\n * Execute plan and return result set.\n */\n private executePlan(step: PlanStep): ResultSet<K> {\n switch (step.type) {\n case 'index-scan':\n return step.index.retrieve(step.query) as ResultSet<K>;\n\n case 'full-scan': {\n const fallback = this.indexRegistry.getFallbackIndex();\n if (fallback) {\n // FallbackIndex uses predicate internally - cast through unknown for compatibility\n return fallback.retrieve(step.predicate as unknown as IndexQuery<unknown>) as ResultSet<K>;\n }\n // Manual full scan fallback\n return this.fullScan(step.predicate as Query);\n }\n\n case 'intersection':\n return new IntersectionResultSet(\n step.steps.map((s) => this.executePlan(s))\n );\n\n case 'union':\n return new UnionResultSet(step.steps.map((s) => this.executePlan(s)));\n\n case 'filter':\n return new FilteringResultSet(\n this.executePlan(step.source),\n (key) => this.get(key),\n (record) => {\n if (record === undefined) return false;\n return this.matchesPredicate(record, step.predicate as Query);\n }\n );\n\n case 'not': {\n const matching = new Set(this.executePlan(step.source).toArray());\n const allKeysSet = new Set(this.keys());\n for (const key of matching) {\n allKeysSet.delete(key);\n }\n return new SetResultSet(allKeysSet, 100);\n }\n\n default:\n throw new Error(`Unknown plan step type: ${(step as PlanStep).type}`);\n }\n }\n\n /**\n * Perform full scan with predicate evaluation.\n */\n private fullScan(query: Query): ResultSet<K> {\n const result = new Set<K>();\n for (const [key, value] of this.entries()) {\n if (this.matchesPredicate(value, query)) {\n result.add(key);\n }\n }\n return new SetResultSet(result, Number.MAX_SAFE_INTEGER);\n }\n\n /**\n * Check if record matches predicate.\n * Converts Query to PredicateNode format for evaluation.\n */\n private matchesPredicate(record: V, query: Query): boolean {\n try {\n const predicate = this.queryToPredicate(query);\n return evaluatePredicate(predicate, record);\n } catch {\n return false;\n }\n }\n\n /**\n * Check if record matches IndexQuery (used by FallbackIndex).\n * This is a simplified matcher for full scan fallback.\n */\n private matchesIndexQuery(record: V, query: IndexQuery<unknown>): boolean {\n // Full scan matcher - evaluates the stored predicate\n // FallbackIndex passes the original query predicate\n if ('attribute' in (query as unknown as Record<string, unknown>)) {\n // This is a Query-like object passed through\n return this.matchesPredicate(record, query as unknown as Query);\n }\n // For simple IndexQuery without attribute context, always match\n return true;\n }\n\n /**\n * Convert Query to PredicateNode format.\n */\n private queryToPredicate(query: Query): PredicateNode {\n if ('type' in query) {\n switch (query.type) {\n case 'eq':\n return {\n op: 'eq',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'neq':\n return {\n op: 'neq',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'gt':\n return {\n op: 'gt',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'gte':\n return {\n op: 'gte',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'lt':\n return {\n op: 'lt',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'lte':\n return {\n op: 'lte',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'and':\n return {\n op: 'and',\n children: ((query as { children: Query[] }).children || []).map(\n (c) => this.queryToPredicate(c)\n ),\n };\n case 'or':\n return {\n op: 'or',\n children: ((query as { children: Query[] }).children || []).map(\n (c) => this.queryToPredicate(c)\n ),\n };\n case 'not':\n return {\n op: 'not',\n children: [\n this.queryToPredicate((query as { child: Query }).child),\n ],\n };\n case 'contains':\n return {\n op: 'contains',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'containsAll':\n return {\n op: 'containsAll',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { values: unknown[] }).values,\n };\n case 'containsAny':\n return {\n op: 'containsAny',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { values: unknown[] }).values,\n };\n default:\n return { op: 'eq', value: null };\n }\n }\n return { op: 'eq', value: null };\n }\n\n // ==================== Live Queries ====================\n\n /**\n * Subscribe to a live query.\n * Callback receives initial results and delta updates.\n *\n * @param query - Query to subscribe to\n * @param callback - Callback for query events\n * @returns Unsubscribe function\n */\n subscribeLiveQuery(\n query: Query,\n callback: LiveQueryCallback<K, V>\n ): () => void {\n return this.liveQueryManager.subscribe(query, callback);\n }\n\n /**\n * Get current live query results (snapshot).\n *\n * @param query - Query to execute\n * @returns Array of matching keys\n */\n getLiveQueryResults(query: Query): K[] {\n return this.liveQueryManager.getResults(query);\n }\n\n /**\n * Check if a query has active subscribers.\n *\n * @param query - Query to check\n * @returns true if query has subscribers\n */\n hasLiveQuerySubscribers(query: Query): boolean {\n return this.liveQueryManager.hasSubscribers(query);\n }\n\n // ==================== Override CRDT Operations ====================\n\n /**\n * Set a value (with index updates).\n */\n public set(key: K, value: V, ttlMs?: number): LWWRecord<V> {\n const oldValue = this.get(key);\n const result = super.set(key, value, ttlMs);\n\n // Apply default indexing on first record (Phase 8.02)\n if (this.defaultIndexingStrategy && !this.defaultIndexingStrategy.isApplied()) {\n this.defaultIndexingStrategy.applyToMap(this, value);\n }\n\n if (oldValue !== undefined) {\n this.indexRegistry.onRecordUpdated(key, oldValue, value);\n this.liveQueryManager.onRecordUpdated(key, oldValue, value);\n } else {\n this.indexRegistry.onRecordAdded(key, value);\n this.liveQueryManager.onRecordAdded(key, value);\n }\n\n return result;\n }\n\n /**\n * Remove a value (with index updates).\n */\n public remove(key: K): LWWRecord<V> {\n const oldValue = this.get(key);\n const result = super.remove(key);\n\n if (oldValue !== undefined) {\n this.indexRegistry.onRecordRemoved(key, oldValue);\n this.liveQueryManager.onRecordRemoved(key, oldValue);\n }\n\n return result;\n }\n\n /**\n * Merge a remote record (with index updates).\n */\n public merge(key: K, remote: LWWRecord<V>): boolean {\n const oldValue = this.get(key);\n const merged = super.merge(key, remote);\n\n if (merged) {\n const newValue = this.get(key);\n\n if (oldValue === undefined && newValue !== undefined) {\n // New record\n this.indexRegistry.onRecordAdded(key, newValue);\n this.liveQueryManager.onRecordAdded(key, newValue);\n } else if (oldValue !== undefined && newValue === undefined) {\n // Deleted (tombstone)\n this.indexRegistry.onRecordRemoved(key, oldValue);\n this.liveQueryManager.onRecordRemoved(key, oldValue);\n } else if (oldValue !== undefined && newValue !== undefined) {\n // Updated\n this.indexRegistry.onRecordUpdated(key, oldValue, newValue);\n this.liveQueryManager.onRecordUpdated(key, oldValue, newValue);\n }\n }\n\n return merged;\n }\n\n /**\n * Clear all data (and indexes).\n */\n public clear(): void {\n super.clear();\n this.indexRegistry.clear();\n this.liveQueryManager.clear();\n }\n\n // ==================== Iterator Methods ====================\n\n /**\n * Returns all keys (non-tombstoned, non-expired).\n */\n public keys(): Iterable<K> {\n const self = this;\n return {\n *[Symbol.iterator]() {\n for (const [key] of self.entries()) {\n yield key;\n }\n },\n };\n }\n\n // ==================== Stats ====================\n\n /**\n * Get index statistics.\n */\n getIndexStats(): Map<string, IndexStats> {\n const stats = new Map<string, IndexStats>();\n for (const index of this.indexRegistry.getAllIndexes()) {\n stats.set(index.attribute.name, index.getStats());\n }\n return stats;\n }\n\n /**\n * Get index registry statistics.\n */\n getIndexRegistryStats(): IndexRegistryStats {\n return this.indexRegistry.getStats();\n }\n\n /**\n * Get query optimizer for plan inspection.\n */\n getQueryOptimizer(): QueryOptimizer<K, V> {\n return this.queryOptimizer;\n }\n\n /**\n * Get live query manager for direct access.\n */\n getLiveQueryManager(): LiveQueryManager<K, V> {\n return this.liveQueryManager;\n }\n\n /**\n * Get standing query registry for direct access.\n */\n getStandingQueryRegistry(): StandingQueryRegistry<K, V> {\n return this.standingQueryRegistry;\n }\n\n /**\n * Explain query execution plan.\n *\n * @param query - Query to explain\n * @returns Query execution plan\n */\n explainQuery(query: Query): QueryPlan {\n return this.queryOptimizer.optimize(query);\n }\n\n // ==================== Adaptive Indexing (Phase 8.02) ====================\n\n /**\n * Register an attribute for auto-indexing.\n * Required before auto-index can create indexes on this attribute.\n *\n * @param attribute - The attribute to register\n * @param allowedIndexTypes - Optional list of allowed index types\n */\n registerAttribute<A>(\n attribute: Attribute<V, A>,\n allowedIndexTypes?: RecommendedIndexType[]\n ): void {\n if (this.autoIndexManager) {\n this.autoIndexManager.registerAttribute(attribute, allowedIndexTypes);\n }\n }\n\n /**\n * Unregister an attribute from auto-indexing.\n *\n * @param attributeName - Name of attribute to unregister\n */\n unregisterAttribute(attributeName: string): void {\n if (this.autoIndexManager) {\n this.autoIndexManager.unregisterAttribute(attributeName);\n }\n }\n\n /**\n * Get index suggestions based on query patterns.\n * Use this in production to get recommendations for manual index creation.\n *\n * @param options - Suggestion options\n * @returns Array of index suggestions sorted by priority\n *\n * @example\n * ```typescript\n * const suggestions = products.getIndexSuggestions();\n * // [{ attribute: 'category', indexType: 'hash', priority: 'high', ... }]\n * ```\n */\n getIndexSuggestions(options?: IndexSuggestionOptions): IndexSuggestion[] {\n return this.indexAdvisor.getSuggestions(options);\n }\n\n /**\n * Get query pattern statistics.\n * Useful for debugging and understanding query patterns.\n *\n * @returns Array of query statistics\n */\n getQueryStatistics(): QueryStatistics[] {\n return this.queryTracker.getStatistics();\n }\n\n /**\n * Reset query statistics.\n * Call this to clear accumulated query patterns.\n */\n resetQueryStatistics(): void {\n this.queryTracker.clear();\n if (this.autoIndexManager) {\n this.autoIndexManager.resetCounts();\n }\n }\n\n /**\n * Get query pattern tracker for advanced usage.\n */\n getQueryTracker(): QueryPatternTracker {\n return this.queryTracker;\n }\n\n /**\n * Get index advisor for advanced usage.\n */\n getIndexAdvisor(): IndexAdvisor {\n return this.indexAdvisor;\n }\n\n /**\n * Get auto-index manager (if enabled).\n */\n getAutoIndexManager(): AutoIndexManager<K, V> | null {\n return this.autoIndexManager;\n }\n\n /**\n * Check if auto-indexing is enabled.\n */\n isAutoIndexingEnabled(): boolean {\n return this.autoIndexManager !== null;\n }\n\n // ==================== Lazy Indexing (Phase 9.01) ====================\n\n /**\n * Check if lazy index building is enabled.\n */\n isLazyIndexingEnabled(): boolean {\n return this.options.lazyIndexBuilding === true;\n }\n\n /**\n * Force materialization of all lazy indexes.\n * Useful to pre-warm indexes before critical operations.\n *\n * @param progressCallback - Optional progress callback\n */\n materializeAllIndexes(progressCallback?: IndexBuildProgressCallback): void {\n const callback = progressCallback ?? this.options.onIndexBuilding;\n\n for (const index of this.indexRegistry.getAllIndexes()) {\n if ('isLazy' in index && (index as LazyIndex<K, V, unknown>).isLazy) {\n const lazyIndex = index as LazyIndex<K, V, unknown>;\n if (!lazyIndex.isBuilt) {\n lazyIndex.materialize(callback);\n }\n }\n }\n }\n\n /**\n * Get count of pending records across all lazy indexes.\n * Returns 0 if no lazy indexes or all are materialized.\n */\n getPendingIndexCount(): number {\n let total = 0;\n for (const index of this.indexRegistry.getAllIndexes()) {\n if ('isLazy' in index && (index as LazyIndex<K, V, unknown>).isLazy) {\n const lazyIndex = index as LazyIndex<K, V, unknown>;\n total += lazyIndex.pendingCount;\n }\n }\n return total;\n }\n\n /**\n * Check if any lazy indexes are still pending (not built).\n */\n hasUnbuiltIndexes(): boolean {\n for (const index of this.indexRegistry.getAllIndexes()) {\n if ('isLazy' in index && (index as LazyIndex<K, V, unknown>).isLazy) {\n const lazyIndex = index as LazyIndex<K, V, unknown>;\n if (!lazyIndex.isBuilt) {\n return true;\n }\n }\n }\n return false;\n }\n\n /**\n * Track query pattern for adaptive indexing.\n */\n private trackQueryPattern(\n query: Query,\n duration: number,\n resultSize: number,\n usedIndex: boolean\n ): void {\n // Only track if advisor is enabled (default: true)\n const advisorEnabled = this.options.adaptiveIndexing?.advisor?.enabled ??\n ADAPTIVE_INDEXING_DEFAULTS.advisor.enabled;\n\n if (!advisorEnabled && !this.autoIndexManager) {\n return;\n }\n\n // Extract attribute from query\n const attribute = this.extractAttribute(query);\n if (!attribute) return;\n\n // Extract query type\n const queryType = this.extractQueryType(query);\n if (!queryType) return;\n\n // Check if this attribute has an index\n const hasIndex = this.indexRegistry.hasIndex(attribute);\n\n // Record query in tracker\n this.queryTracker.recordQuery(\n attribute,\n queryType,\n duration,\n resultSize,\n hasIndex\n );\n\n // Notify auto-index manager if enabled\n if (this.autoIndexManager) {\n this.autoIndexManager.onQueryExecuted(attribute, queryType);\n }\n }\n\n /**\n * Extract attribute name from query.\n */\n private extractAttribute(query: Query): string | null {\n if (isSimpleQuery(query)) {\n return (query as SimpleQueryNode).attribute;\n }\n\n // For compound queries, extract from first child\n if (query.type === 'and' || query.type === 'or') {\n const children = (query as { children?: Query[] }).children;\n if (children && children.length > 0) {\n return this.extractAttribute(children[0]);\n }\n }\n\n if (query.type === 'not') {\n const child = (query as { child?: Query }).child;\n if (child) {\n return this.extractAttribute(child);\n }\n }\n\n return null;\n }\n\n /**\n * Extract query type from query.\n */\n private extractQueryType(query: Query): TrackedQueryType | null {\n if (isSimpleQuery(query)) {\n const type = query.type;\n // Only track types that can be indexed\n const indexableTypes: TrackedQueryType[] = [\n 'eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'between', 'in', 'has',\n 'contains', 'containsAll', 'containsAny',\n ];\n if (indexableTypes.includes(type as TrackedQueryType)) {\n return type as TrackedQueryType;\n }\n }\n\n // For compound queries, extract from first child\n if (query.type === 'and' || query.type === 'or') {\n const children = (query as { children?: Query[] }).children;\n if (children && children.length > 0) {\n return this.extractQueryType(children[0]);\n }\n }\n\n if (query.type === 'not') {\n const child = (query as { child?: Query }).child;\n if (child) {\n return this.extractQueryType(child);\n }\n }\n\n return null;\n }\n}\n","/**\n * English stopwords list (174 common words).\n * These words are filtered out during tokenization as they\n * don't contribute to search relevance.\n */\nexport const ENGLISH_STOPWORDS = new Set([\n // Articles\n 'a',\n 'an',\n 'the',\n\n // Pronouns\n 'i',\n 'me',\n 'my',\n 'myself',\n 'we',\n 'our',\n 'ours',\n 'ourselves',\n 'you',\n 'your',\n 'yours',\n 'yourself',\n 'yourselves',\n 'he',\n 'him',\n 'his',\n 'himself',\n 'she',\n 'her',\n 'hers',\n 'herself',\n 'it',\n 'its',\n 'itself',\n 'they',\n 'them',\n 'their',\n 'theirs',\n 'themselves',\n 'what',\n 'which',\n 'who',\n 'whom',\n 'this',\n 'that',\n 'these',\n 'those',\n\n // Auxiliary verbs\n 'am',\n 'is',\n 'are',\n 'was',\n 'were',\n 'be',\n 'been',\n 'being',\n 'have',\n 'has',\n 'had',\n 'having',\n 'do',\n 'does',\n 'did',\n 'doing',\n 'will',\n 'would',\n 'shall',\n 'should',\n 'can',\n 'could',\n 'may',\n 'might',\n 'must',\n 'ought',\n\n // Prepositions\n 'about',\n 'above',\n 'across',\n 'after',\n 'against',\n 'along',\n 'among',\n 'around',\n 'at',\n 'before',\n 'behind',\n 'below',\n 'beneath',\n 'beside',\n 'between',\n 'beyond',\n 'by',\n 'down',\n 'during',\n 'except',\n 'for',\n 'from',\n 'in',\n 'inside',\n 'into',\n 'near',\n 'of',\n 'off',\n 'on',\n 'onto',\n 'out',\n 'outside',\n 'over',\n 'past',\n 'since',\n 'through',\n 'throughout',\n 'to',\n 'toward',\n 'towards',\n 'under',\n 'underneath',\n 'until',\n 'up',\n 'upon',\n 'with',\n 'within',\n 'without',\n\n // Conjunctions\n 'and',\n 'but',\n 'or',\n 'nor',\n 'so',\n 'yet',\n 'both',\n 'either',\n 'neither',\n 'not',\n 'only',\n 'as',\n 'if',\n 'than',\n 'when',\n 'while',\n 'although',\n 'because',\n 'unless',\n 'whether',\n\n // Adverbs\n 'here',\n 'there',\n 'where',\n 'when',\n 'how',\n 'why',\n 'all',\n 'each',\n 'every',\n 'any',\n 'some',\n 'no',\n 'none',\n 'more',\n 'most',\n 'other',\n 'such',\n 'own',\n 'same',\n 'too',\n 'very',\n 'just',\n 'also',\n 'now',\n 'then',\n 'again',\n 'ever',\n 'once',\n\n // Misc\n 'few',\n 'many',\n 'much',\n 'several',\n 's',\n 't',\n 'd',\n 'll',\n 'm',\n 've',\n 're',\n]);\n\n","/**\n * Porter Stemming Algorithm\n *\n * Reduces English words to their stem (root form).\n * Based on the algorithm by Martin Porter (1980).\n *\n * @see https://tartarus.org/martin/PorterStemmer/\n *\n * @param word - Word to stem (should be lowercase)\n * @returns Stemmed word\n */\nexport function porterStem(word: string): string {\n if (!word || word.length < 3) {\n return word;\n }\n\n // Work with the word\n let stem = word;\n\n // Step 1a: Plurals\n if (stem.endsWith('sses')) {\n stem = stem.slice(0, -2);\n } else if (stem.endsWith('ies')) {\n stem = stem.slice(0, -2);\n } else if (!stem.endsWith('ss') && stem.endsWith('s')) {\n stem = stem.slice(0, -1);\n }\n\n // Step 1b: -ed and -ing\n const step1bRegex = /^(.+?)(eed|ed|ing)$/;\n const step1bMatch = stem.match(step1bRegex);\n\n if (step1bMatch) {\n const [, base, suffix] = step1bMatch;\n\n if (suffix === 'eed') {\n // Only remove if stem has measure > 0\n if (getMeasure(base) > 0) {\n stem = base + 'ee';\n }\n } else if (hasVowel(base)) {\n stem = base;\n\n // Additional processing after -ed/-ing removal\n if (stem.endsWith('at') || stem.endsWith('bl') || stem.endsWith('iz')) {\n stem = stem + 'e';\n } else if (endsWithDoubleConsonant(stem) && !stem.match(/[lsz]$/)) {\n stem = stem.slice(0, -1);\n } else if (getMeasure(stem) === 1 && endsWithCVC(stem)) {\n stem = stem + 'e';\n }\n }\n }\n\n // Step 1c: Terminal y\n if (stem.endsWith('y') && hasVowel(stem.slice(0, -1))) {\n stem = stem.slice(0, -1) + 'i';\n }\n\n // Step 2: Double suffixes\n const step2Suffixes: Array<[RegExp, string, number]> = [\n [/ational$/, 'ate', 0],\n [/tional$/, 'tion', 0],\n [/enci$/, 'ence', 0],\n [/anci$/, 'ance', 0],\n [/izer$/, 'ize', 0],\n [/abli$/, 'able', 0],\n [/alli$/, 'al', 0],\n [/entli$/, 'ent', 0],\n [/eli$/, 'e', 0],\n [/ousli$/, 'ous', 0],\n [/ization$/, 'ize', 0],\n [/ation$/, 'ate', 0],\n [/ator$/, 'ate', 0],\n [/alism$/, 'al', 0],\n [/iveness$/, 'ive', 0],\n [/fulness$/, 'ful', 0],\n [/ousness$/, 'ous', 0],\n [/aliti$/, 'al', 0],\n [/iviti$/, 'ive', 0],\n [/biliti$/, 'ble', 0],\n ];\n\n for (const [regex, replacement, minMeasure] of step2Suffixes) {\n if (regex.test(stem)) {\n const base = stem.replace(regex, '');\n if (getMeasure(base) > minMeasure) {\n stem = base + replacement;\n break;\n }\n }\n }\n\n // Step 3: -icate, -ful, -ness, etc.\n const step3Suffixes: Array<[RegExp, string, number]> = [\n [/icate$/, 'ic', 0],\n [/ative$/, '', 0],\n [/alize$/, 'al', 0],\n [/iciti$/, 'ic', 0],\n [/ical$/, 'ic', 0],\n [/ful$/, '', 0],\n [/ness$/, '', 0],\n ];\n\n for (const [regex, replacement, minMeasure] of step3Suffixes) {\n if (regex.test(stem)) {\n const base = stem.replace(regex, '');\n if (getMeasure(base) > minMeasure) {\n stem = base + replacement;\n break;\n }\n }\n }\n\n // Step 4: Final suffixes\n const step4Suffixes: Array<[RegExp, number]> = [\n [/al$/, 1],\n [/ance$/, 1],\n [/ence$/, 1],\n [/er$/, 1],\n [/ic$/, 1],\n [/able$/, 1],\n [/ible$/, 1],\n [/ant$/, 1],\n [/ement$/, 1],\n [/ment$/, 1],\n [/ent$/, 1],\n [/ion$/, 1],\n [/ou$/, 1],\n [/ism$/, 1],\n [/ate$/, 1],\n [/iti$/, 1],\n [/ous$/, 1],\n [/ive$/, 1],\n [/ize$/, 1],\n ];\n\n for (const [regex, minMeasure] of step4Suffixes) {\n if (regex.test(stem)) {\n const base = stem.replace(regex, '');\n if (getMeasure(base) > minMeasure) {\n // Special case for -ion (must be preceded by s or t)\n if (regex.source === 'ion$') {\n if (base.match(/[st]$/)) {\n stem = base;\n }\n } else {\n stem = base;\n }\n break;\n }\n }\n }\n\n // Step 5a: Final -e\n if (stem.endsWith('e')) {\n const base = stem.slice(0, -1);\n const measure = getMeasure(base);\n if (measure > 1 || (measure === 1 && !endsWithCVC(base))) {\n stem = base;\n }\n }\n\n // Step 5b: Double consonant\n if (getMeasure(stem) > 1 && endsWithDoubleConsonant(stem) && stem.endsWith('l')) {\n stem = stem.slice(0, -1);\n }\n\n return stem;\n}\n\n/**\n * Check if a character is a vowel.\n */\nfunction isVowel(char: string, prevChar?: string): boolean {\n if ('aeiou'.includes(char)) {\n return true;\n }\n // Y is a vowel if preceded by a consonant\n if (char === 'y' && prevChar && !'aeiou'.includes(prevChar)) {\n return true;\n }\n return false;\n}\n\n/**\n * Check if a string contains a vowel.\n */\nfunction hasVowel(str: string): boolean {\n for (let i = 0; i < str.length; i++) {\n if (isVowel(str[i], i > 0 ? str[i - 1] : undefined)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Calculate the \"measure\" of a word (number of VC sequences).\n * [C](VC){m}[V] where m is the measure.\n */\nfunction getMeasure(str: string): number {\n // Convert to CV pattern\n let pattern = '';\n for (let i = 0; i < str.length; i++) {\n pattern += isVowel(str[i], i > 0 ? str[i - 1] : undefined) ? 'v' : 'c';\n }\n\n // Count VC sequences\n const matches = pattern.match(/vc/g);\n return matches ? matches.length : 0;\n}\n\n/**\n * Check if word ends with a double consonant (e.g., -ll, -ss, -zz).\n */\nfunction endsWithDoubleConsonant(str: string): boolean {\n if (str.length < 2) return false;\n const last = str[str.length - 1];\n const secondLast = str[str.length - 2];\n return last === secondLast && !'aeiou'.includes(last);\n}\n\n/**\n * Check if word ends with CVC pattern where last C is not w, x, or y.\n */\nfunction endsWithCVC(str: string): boolean {\n if (str.length < 3) return false;\n\n const last3 = str.slice(-3);\n const c1 = !'aeiou'.includes(last3[0]);\n const v = isVowel(last3[1], last3[0]);\n const c2 = !'aeiou'.includes(last3[2]) && !'wxy'.includes(last3[2]);\n\n return c1 && v && c2;\n}\n\n","/**\n * FTS Tokenizer with Porter Stemming and Stopwords\n *\n * Provides text tokenization for BM25 full-text search.\n * Features:\n * - Unicode-aware word boundary detection\n * - English stopwords filtering (174 words)\n * - Porter stemming algorithm for word normalization\n * - Configurable min/max token length\n *\n * @module fts/Tokenizer\n */\n\nimport type { Tokenizer as ITokenizer } from '../query/tokenization/Tokenizer';\nimport type { TokenizerOptions } from './types';\nimport { ENGLISH_STOPWORDS } from '../query/tokenization/stopwords';\nimport { porterStem } from '../query/tokenization/porter-stemmer';\n\nexport { ENGLISH_STOPWORDS, porterStem };\n\n/**\n * FTS Tokenizer\n *\n * Splits text into searchable tokens with normalization.\n *\n * @example\n * ```typescript\n * const tokenizer = new BM25Tokenizer();\n * const tokens = tokenizer.tokenize('The quick brown foxes');\n * // ['quick', 'brown', 'fox']\n * ```\n */\nexport class BM25Tokenizer implements ITokenizer {\n private readonly options: Required<TokenizerOptions>;\n\n /**\n * Create a new BM25Tokenizer.\n *\n * @param options - Configuration options\n */\n constructor(options?: TokenizerOptions) {\n this.options = {\n lowercase: true,\n stopwords: ENGLISH_STOPWORDS,\n stemmer: porterStem,\n minLength: 2,\n maxLength: 40,\n ...options,\n };\n }\n\n /**\n * Tokenize text into an array of normalized tokens.\n *\n * @param text - Text to tokenize\n * @returns Array of tokens\n */\n tokenize(text: string): string[] {\n // Handle null/undefined/empty\n if (!text || typeof text !== 'string') {\n return [];\n }\n\n // 1. Lowercase if enabled\n let processed = this.options.lowercase ? text.toLowerCase() : text;\n\n // 2. Split on non-alphanumeric characters (Unicode-aware)\n // This regex matches Unicode letters and numbers\n const words = processed.split(/[^\\p{L}\\p{N}]+/u).filter((w) => w.length > 0);\n\n // 3. Filter and process each word\n const tokens: string[] = [];\n\n for (const word of words) {\n // Skip if too short before any processing\n if (word.length < this.options.minLength) {\n continue;\n }\n\n // Skip stopwords (before stemming)\n if (this.options.stopwords.has(word)) {\n continue;\n }\n\n // Apply stemmer\n const stemmed = this.options.stemmer(word);\n\n // Skip if too short after stemming\n if (stemmed.length < this.options.minLength) {\n continue;\n }\n\n // Skip if too long\n if (stemmed.length > this.options.maxLength) {\n continue;\n }\n\n tokens.push(stemmed);\n }\n\n return tokens;\n }\n}\n","/**\n * FTS Inverted Index\n *\n * Data structure for full-text search that maps terms to documents.\n * Supports efficient term lookup, document frequency calculation,\n * and IDF (Inverse Document Frequency) for BM25 scoring.\n *\n * @module fts/BM25InvertedIndex\n */\n\nimport type { TermInfo } from './types';\n\n/**\n * Inverted Index for Full-Text Search (BM25)\n *\n * Maps terms to the documents containing them, along with term frequency\n * information needed for BM25 scoring.\n *\n * @example\n * ```typescript\n * const index = new BM25InvertedIndex();\n * index.addDocument('doc1', ['hello', 'world']);\n * index.addDocument('doc2', ['hello', 'there']);\n *\n * const docs = index.getDocumentsForTerm('hello');\n * // [{ docId: 'doc1', termFrequency: 1 }, { docId: 'doc2', termFrequency: 1 }]\n * ```\n */\nexport class BM25InvertedIndex {\n /** term → list of documents containing term */\n private index: Map<string, TermInfo[]>;\n\n /** document → total term count (for length normalization) */\n private docLengths: Map<string, number>;\n\n /** document → set of terms (for efficient removal) */\n private docTerms: Map<string, Set<string>>;\n\n /** Inverse Document Frequency cache */\n private idfCache: Map<string, number>;\n\n /** Total number of documents */\n private totalDocs: number;\n\n /** Average document length */\n private avgDocLength: number;\n\n constructor() {\n this.index = new Map();\n this.docLengths = new Map();\n this.docTerms = new Map();\n this.idfCache = new Map();\n this.totalDocs = 0;\n this.avgDocLength = 0;\n }\n\n /**\n * Add a document to the index.\n *\n * @param docId - Unique document identifier\n * @param tokens - Array of tokens (already tokenized/stemmed)\n */\n addDocument(docId: string, tokens: string[]): void {\n // Count term frequencies\n const termFreqs = new Map<string, number>();\n const uniqueTerms = new Set<string>();\n\n for (const token of tokens) {\n termFreqs.set(token, (termFreqs.get(token) || 0) + 1);\n uniqueTerms.add(token);\n }\n\n // Update inverted index\n for (const [term, freq] of termFreqs) {\n if (!this.index.has(term)) {\n this.index.set(term, []);\n }\n this.index.get(term)!.push({\n docId,\n termFrequency: freq,\n });\n }\n\n // Store document info\n this.docLengths.set(docId, tokens.length);\n this.docTerms.set(docId, uniqueTerms);\n\n // Update stats\n this.totalDocs++;\n this.updateAvgDocLength();\n\n // Invalidate IDF cache\n this.idfCache.clear();\n }\n\n /**\n * Remove a document from the index.\n *\n * @param docId - Document identifier to remove\n */\n removeDocument(docId: string): void {\n const terms = this.docTerms.get(docId);\n if (!terms) {\n return; // Document doesn't exist\n }\n\n // Remove from inverted index\n for (const term of terms) {\n const termInfos = this.index.get(term);\n if (termInfos) {\n const filtered = termInfos.filter((info) => info.docId !== docId);\n if (filtered.length === 0) {\n this.index.delete(term);\n } else {\n this.index.set(term, filtered);\n }\n }\n }\n\n // Remove document info\n this.docLengths.delete(docId);\n this.docTerms.delete(docId);\n\n // Update stats\n this.totalDocs--;\n this.updateAvgDocLength();\n\n // Invalidate IDF cache\n this.idfCache.clear();\n }\n\n /**\n * Get all documents containing a term.\n *\n * @param term - Term to look up\n * @returns Array of TermInfo objects\n */\n getDocumentsForTerm(term: string): TermInfo[] {\n return this.index.get(term) || [];\n }\n\n /**\n * Calculate IDF (Inverse Document Frequency) for a term.\n *\n * Uses BM25 IDF formula:\n * IDF = log((N - df + 0.5) / (df + 0.5) + 1)\n *\n * Where:\n * - N = total documents\n * - df = document frequency (docs containing term)\n *\n * @param term - Term to calculate IDF for\n * @returns IDF value (0 if term doesn't exist)\n */\n getIDF(term: string): number {\n // Check cache first\n if (this.idfCache.has(term)) {\n return this.idfCache.get(term)!;\n }\n\n const termInfos = this.index.get(term);\n if (!termInfos || termInfos.length === 0) {\n return 0;\n }\n\n const docFreq = termInfos.length;\n\n // BM25 IDF formula\n const idf = Math.log((this.totalDocs - docFreq + 0.5) / (docFreq + 0.5) + 1);\n\n // Cache the result\n this.idfCache.set(term, idf);\n\n return idf;\n }\n\n /**\n * Get the length of a document (number of tokens).\n *\n * @param docId - Document identifier\n * @returns Document length (0 if not found)\n */\n getDocLength(docId: string): number {\n return this.docLengths.get(docId) || 0;\n }\n\n /**\n * Get the average document length.\n *\n * @returns Average length across all documents\n */\n getAvgDocLength(): number {\n return this.avgDocLength;\n }\n\n /**\n * Get the total number of documents in the index.\n *\n * @returns Total document count\n */\n getTotalDocs(): number {\n return this.totalDocs;\n }\n\n /**\n * Get iterator for document lengths (useful for serialization).\n *\n * @returns Iterator of [docId, length] pairs\n */\n getDocLengths(): IterableIterator<[string, number]> {\n return this.docLengths.entries();\n }\n\n /**\n * Get the number of documents in the index (alias for getTotalDocs).\n *\n * @returns Number of indexed documents\n */\n getSize(): number {\n return this.totalDocs;\n }\n\n /**\n * Clear all data from the index.\n */\n clear(): void {\n this.index.clear();\n this.docLengths.clear();\n this.docTerms.clear();\n this.idfCache.clear();\n this.totalDocs = 0;\n this.avgDocLength = 0;\n }\n\n /**\n * Check if a document exists in the index.\n *\n * @param docId - Document identifier\n * @returns True if document exists\n */\n hasDocument(docId: string): boolean {\n return this.docTerms.has(docId);\n }\n\n /**\n * Get all unique terms in the index.\n *\n * @returns Iterator of all terms\n */\n getTerms(): IterableIterator<string> {\n return this.index.keys();\n }\n\n /**\n * Get the number of unique terms in the index.\n *\n * @returns Number of unique terms\n */\n getTermCount(): number {\n return this.index.size;\n }\n\n /**\n * Update the average document length after add/remove.\n */\n private updateAvgDocLength(): void {\n if (this.totalDocs === 0) {\n this.avgDocLength = 0;\n return;\n }\n\n let sum = 0;\n for (const length of this.docLengths.values()) {\n sum += length;\n }\n this.avgDocLength = sum / this.totalDocs;\n }\n}\n","/**\n * BM25 Scorer\n *\n * Implements the Okapi BM25 ranking algorithm for full-text search.\n * BM25 is a probabilistic relevance ranking function used to estimate\n * the relevance of documents to a given search query.\n *\n * @see https://en.wikipedia.org/wiki/Okapi_BM25\n * @module fts/BM25Scorer\n */\n\nimport type { BM25Options, ScoredDocument } from './types';\nimport type { BM25InvertedIndex } from './BM25InvertedIndex';\n\n/**\n * BM25 Scorer for relevance ranking\n *\n * The BM25 formula:\n * score(D,Q) = Σ IDF(qi) × (f(qi,D) × (k1 + 1)) / (f(qi,D) + k1 × (1 - b + b × |D| / avgdl))\n *\n * Where:\n * - D = document\n * - Q = query\n * - qi = query term i\n * - f(qi,D) = term frequency of qi in D\n * - |D| = length of D (number of terms)\n * - avgdl = average document length\n * - k1 = term frequency saturation parameter (default: 1.2)\n * - b = document length normalization parameter (default: 0.75)\n *\n * @example\n * ```typescript\n * const index = new BM25InvertedIndex();\n * index.addDocument('doc1', ['hello', 'world']);\n * index.addDocument('doc2', ['hello', 'there']);\n *\n * const scorer = new BM25Scorer();\n * const results = scorer.score(['hello'], index);\n * // [{ docId: 'doc1', score: 0.28, matchedTerms: ['hello'] }, ...]\n * ```\n */\nexport class BM25Scorer {\n /**\n * Term frequency saturation parameter.\n * Higher values give more weight to repeated terms.\n * Typical range: 1.2 - 2.0\n */\n private readonly k1: number;\n\n /**\n * Document length normalization parameter.\n * 0 = no length normalization\n * 1 = full length normalization\n * Typical value: 0.75\n */\n private readonly b: number;\n\n /**\n * Create a new BM25 scorer.\n *\n * @param options - BM25 configuration options\n */\n constructor(options?: BM25Options) {\n this.k1 = options?.k1 ?? 1.2;\n this.b = options?.b ?? 0.75;\n }\n\n /**\n * Score documents against a query.\n *\n * @param queryTerms - Array of query terms (already tokenized/stemmed)\n * @param index - The inverted index to search\n * @returns Array of scored documents, sorted by relevance (descending)\n */\n score(queryTerms: string[], index: BM25InvertedIndex): ScoredDocument[] {\n if (queryTerms.length === 0 || index.getTotalDocs() === 0) {\n return [];\n }\n\n const avgDocLength = index.getAvgDocLength();\n\n // Map to accumulate scores per document\n const docScores = new Map<string, { score: number; terms: Set<string> }>();\n\n // Process each query term\n for (const term of queryTerms) {\n const idf = index.getIDF(term);\n if (idf === 0) {\n continue; // Term not in index\n }\n\n const termInfos = index.getDocumentsForTerm(term);\n\n for (const { docId, termFrequency } of termInfos) {\n const docLength = index.getDocLength(docId);\n\n // BM25 term score calculation\n const numerator = termFrequency * (this.k1 + 1);\n const denominator = termFrequency + this.k1 * (1 - this.b + this.b * (docLength / avgDocLength));\n const termScore = idf * (numerator / denominator);\n\n // Accumulate score for this document\n const current = docScores.get(docId) || { score: 0, terms: new Set() };\n current.score += termScore;\n current.terms.add(term);\n docScores.set(docId, current);\n }\n }\n\n // Convert to array and sort by score (descending)\n const results: ScoredDocument[] = [];\n for (const [docId, { score, terms }] of docScores) {\n results.push({\n docId,\n score,\n matchedTerms: Array.from(terms),\n });\n }\n\n results.sort((a, b) => b.score - a.score);\n\n return results;\n }\n\n /**\n * Score a single document against query terms.\n * Uses pre-computed IDF from index but calculates TF locally.\n *\n * Complexity: O(Q × D) where Q = query terms, D = document tokens\n *\n * @param queryTerms - Tokenized query terms\n * @param docTokens - Tokenized document terms\n * @param index - Inverted index for IDF and avgDocLength\n * @returns BM25 score (0 if no matching terms)\n */\n scoreSingleDocument(\n queryTerms: string[],\n docTokens: string[],\n index: BM25InvertedIndex\n ): number {\n if (queryTerms.length === 0 || docTokens.length === 0) {\n return 0;\n }\n\n const avgDocLength = index.getAvgDocLength();\n const docLength = docTokens.length;\n\n if (avgDocLength === 0) {\n return 0;\n }\n\n // Build term frequency map for document\n const termFreqs = new Map<string, number>();\n for (const token of docTokens) {\n termFreqs.set(token, (termFreqs.get(token) || 0) + 1);\n }\n\n let score = 0;\n\n for (const term of queryTerms) {\n const tf = termFreqs.get(term) || 0;\n if (tf === 0) {\n continue;\n }\n\n // Get IDF from index (uses cached value)\n const idf = index.getIDF(term);\n if (idf <= 0) {\n continue;\n }\n\n // BM25 term score calculation\n const numerator = tf * (this.k1 + 1);\n const denominator = tf + this.k1 * (1 - this.b + this.b * (docLength / avgDocLength));\n const termScore = idf * (numerator / denominator);\n\n score += termScore;\n }\n\n return score;\n }\n\n /**\n * Get the k1 parameter value.\n */\n getK1(): number {\n return this.k1;\n }\n\n /**\n * Get the b parameter value.\n */\n getB(): number {\n return this.b;\n }\n}\n","import { BM25InvertedIndex } from './BM25InvertedIndex';\nimport type { SerializedIndex, TermInfo } from './types';\n\n/**\n * Serializer for BM25InvertedIndex\n *\n * Handles serialization/deserialization of the inverted index for persistence.\n * Matches the structure defined in PHASE_11_IMPLEMENTATION_NOTES.\n */\nexport class IndexSerializer {\n /**\n * Serialize inverted index to a JSON-serializable object.\n * Note: In a real app, you might want to encoding this to binary (msgpack) later.\n */\n serialize(index: BM25InvertedIndex): SerializedIndex {\n const data: SerializedIndex = {\n version: 1,\n metadata: {\n totalDocs: index.getTotalDocs(),\n avgDocLength: index.getAvgDocLength(),\n createdAt: Date.now(),\n lastModified: Date.now(),\n },\n terms: this.serializeTerms(index),\n docLengths: this.serializeDocLengths(index),\n };\n\n return data;\n }\n\n /**\n * Deserialize from object into a new BM25InvertedIndex.\n */\n deserialize(data: SerializedIndex): BM25InvertedIndex {\n // Validate version\n if (data.version !== 1) {\n throw new Error(`Unsupported index version: ${data.version}`);\n }\n\n const index = new BM25InvertedIndex();\n this.loadIntoIndex(index, data);\n\n return index;\n }\n\n private serializeTerms(index: BM25InvertedIndex): SerializedIndex['terms'] {\n const terms: SerializedIndex['terms'] = [];\n const indexMap = (index as any).index as Map<string, TermInfo[]>; // Access private map\n\n // We need access to internal map.\n // Since we can't easily access private 'index' property without 'any' cast or getter,\n // we rely on iteration if available, or 'any' cast for this system component.\n // The public API getTerms() only returns keys.\n\n for (const term of index.getTerms()) {\n const termInfos = index.getDocumentsForTerm(term);\n terms.push({\n term,\n idf: index.getIDF(term),\n postings: termInfos.map((info) => ({\n docId: info.docId,\n termFrequency: info.termFrequency,\n positions: info.fieldPositions,\n })),\n });\n }\n\n return terms;\n }\n\n private serializeDocLengths(index: BM25InvertedIndex): Record<string, number> {\n const lengths: Record<string, number> = {};\n for (const [docId, length] of index.getDocLengths()) {\n lengths[docId] = length;\n }\n return lengths;\n }\n\n private loadIntoIndex(index: BM25InvertedIndex, data: SerializedIndex): void {\n // Restore metadata\n // We need to set private properties. \n // We'll use a helper method on Index or 'any' cast for this serializer friend class.\n const idx = index as any;\n \n idx.totalDocs = data.metadata.totalDocs;\n idx.avgDocLength = data.metadata.avgDocLength;\n \n // Restore doc lengths\n idx.docLengths = new Map(Object.entries(data.docLengths));\n \n // Restore terms\n for (const { term, idf, postings } of data.terms) {\n const termInfos: TermInfo[] = postings.map((p) => ({\n docId: p.docId,\n termFrequency: p.termFrequency,\n fieldPositions: p.positions,\n }));\n \n idx.index.set(term, termInfos);\n idx.idfCache.set(term, idf);\n \n // We also need to restore docTerms for efficient removal\n // This is expensive to rebuild from inverted index (O(Terms * Docs)).\n // But essential for updates.\n for (const info of termInfos) {\n if (!idx.docTerms.has(info.docId)) {\n idx.docTerms.set(info.docId, new Set());\n }\n idx.docTerms.get(info.docId).add(term);\n }\n }\n }\n}\n\n","/**\n * Full-Text Index\n *\n * High-level integration class that combines Tokenizer, InvertedIndex,\n * and BM25Scorer for complete full-text search functionality.\n * Designed to integrate with TopGun's CRDT maps.\n *\n * @module fts/FullTextIndex\n */\n\nimport type {\n FullTextIndexConfig,\n SearchOptions,\n ScoredDocument,\n TokenizerOptions,\n BM25Options,\n SearchResult,\n SerializedIndex,\n} from './types';\nimport { BM25Tokenizer } from './Tokenizer';\nimport { BM25InvertedIndex } from './BM25InvertedIndex';\nimport { BM25Scorer } from './BM25Scorer';\nimport { IndexSerializer } from './IndexSerializer';\n\n/**\n * Full-Text Index for TopGun\n *\n * Provides BM25-based full-text search across document fields.\n * Supports incremental updates (add/update/remove) for real-time sync.\n *\n * @example\n * ```typescript\n * const index = new FullTextIndex({\n * fields: ['title', 'body'],\n * tokenizer: { minLength: 2 },\n * bm25: { k1: 1.2, b: 0.75 }\n * });\n *\n * index.onSet('doc1', { title: 'Hello World', body: 'Test content' });\n * const results = index.search('hello');\n * // [{ docId: 'doc1', score: 0.5, matchedTerms: ['hello'] }]\n * ```\n */\nexport class FullTextIndex {\n /** Fields to index from documents */\n private readonly fields: string[];\n\n /** Tokenizer for text processing */\n private readonly tokenizer: BM25Tokenizer;\n\n /** BM25 scorer for relevance ranking */\n private readonly scorer: BM25Scorer;\n\n /** Per-field inverted indexes for field boosting */\n private readonly fieldIndexes: Map<string, BM25InvertedIndex>;\n\n /** Combined index for all fields */\n private combinedIndex: BM25InvertedIndex;\n\n /** Track indexed documents */\n private readonly indexedDocs: Set<string>;\n\n /** Serializer for persistence */\n private readonly serializer: IndexSerializer;\n\n /**\n * Cache of document tokens for fast single-document scoring.\n * Maps docId → tokenized terms from all indexed fields.\n */\n private readonly documentTokensCache: Map<string, string[]>;\n\n /**\n * Create a new FullTextIndex.\n *\n * @param config - Index configuration\n */\n constructor(config: FullTextIndexConfig) {\n this.fields = config.fields;\n this.tokenizer = new BM25Tokenizer(config.tokenizer);\n this.scorer = new BM25Scorer(config.bm25);\n this.fieldIndexes = new Map();\n this.combinedIndex = new BM25InvertedIndex();\n this.indexedDocs = new Set();\n this.serializer = new IndexSerializer();\n this.documentTokensCache = new Map();\n\n // Create per-field indexes\n for (const field of this.fields) {\n this.fieldIndexes.set(field, new BM25InvertedIndex());\n }\n }\n\n /**\n * Index a document (add or update).\n * Called when a document is set in the CRDT map.\n *\n * @param docId - Document identifier\n * @param document - Document data containing fields to index\n */\n onSet(docId: string, document: Record<string, unknown> | null | undefined): void {\n // Handle null/undefined documents\n if (!document || typeof document !== 'object') {\n // Clear cache for null/undefined document\n this.documentTokensCache.delete(docId);\n return;\n }\n\n // If document already exists, remove it first\n if (this.indexedDocs.has(docId)) {\n this.removeFromIndexes(docId);\n }\n\n // Collect all tokens for combined index\n const allTokens: string[] = [];\n\n // Index each field\n for (const field of this.fields) {\n const value = document[field];\n\n // Only index string values\n if (typeof value !== 'string') {\n continue;\n }\n\n const tokens = this.tokenizer.tokenize(value);\n\n if (tokens.length > 0) {\n // Add to field-specific index\n const fieldIndex = this.fieldIndexes.get(field)!;\n fieldIndex.addDocument(docId, tokens);\n\n // Collect for combined index\n allTokens.push(...tokens);\n }\n }\n\n // Add to combined index if any tokens were found\n if (allTokens.length > 0) {\n this.combinedIndex.addDocument(docId, allTokens);\n this.indexedDocs.add(docId);\n // Cache tokens for scoreSingleDocument\n this.documentTokensCache.set(docId, allTokens);\n } else {\n // No tokens - clear cache entry\n this.documentTokensCache.delete(docId);\n }\n }\n\n /**\n * Remove a document from the index.\n * Called when a document is deleted from the CRDT map.\n *\n * @param docId - Document identifier to remove\n */\n onRemove(docId: string): void {\n if (!this.indexedDocs.has(docId)) {\n return;\n }\n\n this.removeFromIndexes(docId);\n this.indexedDocs.delete(docId);\n // Clear cache entry\n this.documentTokensCache.delete(docId);\n }\n\n /**\n * Search the index with a query.\n *\n * @param query - Search query text\n * @param options - Search options (limit, minScore, boost)\n * @returns Array of search results, sorted by relevance\n */\n search(query: string, options?: SearchOptions): SearchResult[] {\n // Tokenize query\n const queryTerms = this.tokenizer.tokenize(query);\n\n if (queryTerms.length === 0) {\n return [];\n }\n\n // Check if field boosting is requested\n const boost = options?.boost;\n\n let results: ScoredDocument[];\n\n if (boost && Object.keys(boost).length > 0) {\n // Search with field boosting\n results = this.searchWithBoost(queryTerms, boost);\n } else {\n // Search combined index\n results = this.scorer.score(queryTerms, this.combinedIndex);\n }\n\n // Apply minScore filter\n if (options?.minScore !== undefined) {\n results = results.filter((r) => r.score >= options.minScore!);\n }\n\n // Apply limit\n if (options?.limit !== undefined && options.limit > 0) {\n results = results.slice(0, options.limit);\n }\n\n // Map to SearchResult\n return results.map((r) => ({\n docId: r.docId,\n score: r.score,\n matchedTerms: r.matchedTerms,\n source: 'fulltext' as const,\n }));\n }\n\n /**\n * Serialize the index state.\n *\n * @returns Serialized index data\n */\n serialize(): SerializedIndex {\n // We only serialize the combined index for now as it's the primary one.\n // If field boosting is required after restore, we'd need to serialize field indexes too.\n // For MVP/Phase 11, combined index serialization covers the main use case.\n return this.serializer.serialize(this.combinedIndex);\n }\n\n /**\n * Load index from serialized state.\n *\n * @param data - Serialized index data\n */\n load(data: SerializedIndex): void {\n this.combinedIndex = this.serializer.deserialize(data);\n\n // Rebuild indexedDocs set\n this.indexedDocs.clear();\n // Use private docLengths to rebuild indexedDocs set efficiently\n // This assumes we added getDocLengths to BM25InvertedIndex\n for (const [docId] of this.combinedIndex.getDocLengths()) {\n this.indexedDocs.add(docId);\n }\n\n // Note: Field indexes are NOT restored from combined index.\n // They would need to be rebuilt from source documents or serialized separately.\n // This is a tradeoff: fast load vs field boosting availability immediately without source docs.\n this.fieldIndexes.clear();\n for (const field of this.fields) {\n this.fieldIndexes.set(field, new BM25InvertedIndex());\n }\n\n // Clear document tokens cache - tokens must be rebuilt from source documents\n // This is intentional: serialized index doesn't include raw tokens\n this.documentTokensCache.clear();\n }\n\n /**\n * Build the index from an array of entries.\n * Useful for initial bulk loading.\n *\n * @param entries - Array of [docId, document] tuples\n */\n buildFromEntries(entries: Array<[string, Record<string, unknown> | null]>): void {\n for (const [docId, document] of entries) {\n this.onSet(docId, document);\n }\n }\n\n /**\n * Clear all data from the index.\n */\n clear(): void {\n this.combinedIndex.clear();\n for (const fieldIndex of this.fieldIndexes.values()) {\n fieldIndex.clear();\n }\n this.indexedDocs.clear();\n this.documentTokensCache.clear();\n }\n\n /**\n * Get the number of indexed documents.\n *\n * @returns Number of documents in the index\n */\n getSize(): number {\n return this.indexedDocs.size;\n }\n\n /**\n * Tokenize a query string using the index's tokenizer.\n * Public method for external use (e.g., SearchCoordinator).\n *\n * @param query - Query text to tokenize\n * @returns Array of tokenized terms\n */\n tokenizeQuery(query: string): string[] {\n return this.tokenizer.tokenize(query);\n }\n\n /**\n * Score a single document against query terms.\n * O(Q × D) complexity where Q = query terms, D = document tokens.\n *\n * This method is optimized for checking if a single document\n * matches a query, avoiding full index scan.\n *\n * @param docId - Document ID to score\n * @param queryTerms - Pre-tokenized query terms\n * @param document - Optional document data (used if not in cache)\n * @returns SearchResult with score and matched terms, or null if no match\n */\n scoreSingleDocument(\n docId: string,\n queryTerms: string[],\n document?: Record<string, unknown>\n ): SearchResult | null {\n if (queryTerms.length === 0) {\n return null;\n }\n\n // Get tokens from cache or compute from document\n let docTokens = this.documentTokensCache.get(docId);\n\n if (!docTokens && document) {\n // Document not in cache - tokenize on the fly\n docTokens = this.tokenizeDocument(document);\n }\n\n if (!docTokens || docTokens.length === 0) {\n return null;\n }\n\n // Quick check: any query term matches document?\n const docTokenSet = new Set(docTokens);\n const matchedTerms = queryTerms.filter(term => docTokenSet.has(term));\n\n if (matchedTerms.length === 0) {\n return null;\n }\n\n // Calculate BM25 score\n const score = this.scorer.scoreSingleDocument(\n queryTerms,\n docTokens,\n this.combinedIndex\n );\n\n if (score <= 0) {\n return null;\n }\n\n return {\n docId,\n score,\n matchedTerms,\n source: 'fulltext' as const,\n };\n }\n\n /**\n * Tokenize all indexed fields of a document.\n * Internal helper for scoreSingleDocument when document not in cache.\n *\n * @param document - Document data\n * @returns Array of all tokens from indexed fields\n */\n private tokenizeDocument(document: Record<string, unknown>): string[] {\n const allTokens: string[] = [];\n\n for (const field of this.fields) {\n const value = document[field];\n if (typeof value === 'string') {\n const tokens = this.tokenizer.tokenize(value);\n allTokens.push(...tokens);\n }\n }\n\n return allTokens;\n }\n\n /**\n * Get the index name (for debugging/display).\n *\n * @returns Descriptive name including indexed fields\n */\n get name(): string {\n return `FullTextIndex(${this.fields.join(', ')})`;\n }\n\n /**\n * Remove document from all indexes (internal).\n */\n private removeFromIndexes(docId: string): void {\n this.combinedIndex.removeDocument(docId);\n for (const fieldIndex of this.fieldIndexes.values()) {\n fieldIndex.removeDocument(docId);\n }\n }\n\n /**\n * Search with field boosting.\n * Scores are computed per-field and combined with boost weights.\n */\n private searchWithBoost(\n queryTerms: string[],\n boost: Record<string, number>\n ): ScoredDocument[] {\n // Accumulate scores per document\n const docScores = new Map<string, { score: number; terms: Set<string> }>();\n\n for (const field of this.fields) {\n const fieldIndex = this.fieldIndexes.get(field)!;\n const boostWeight = boost[field] ?? 1.0;\n\n // Score for this field\n const fieldResults = this.scorer.score(queryTerms, fieldIndex);\n\n for (const result of fieldResults) {\n const current = docScores.get(result.docId) || {\n score: 0,\n terms: new Set(),\n };\n\n // Apply boost to field score\n current.score += result.score * boostWeight;\n\n // Collect matched terms\n for (const term of result.matchedTerms) {\n current.terms.add(term);\n }\n\n docScores.set(result.docId, current);\n }\n }\n\n // Convert to array and sort\n const results: ScoredDocument[] = [];\n for (const [docId, { score, terms }] of docScores) {\n results.push({\n docId,\n score,\n matchedTerms: Array.from(terms),\n });\n }\n\n results.sort((a, b) => b.score - a.score);\n\n return results;\n }\n}\n","/**\n * IndexedORMap Implementation\n *\n * ORMap with index support for O(1) to O(log N) queries.\n * Wraps ORMap with indexing capabilities using the Wrapper Pattern.\n *\n * Note: ORMap stores multiple values per key (with tags).\n * Indexes track unique (key, tag) composite keys.\n *\n * Features:\n * - Hash and Navigable indexes for efficient queries\n * - Composite key indexing (key:tag)\n * - Automatic index updates on CRDT operations\n * - Lazy filtering for tombstones\n * - Adaptive indexing with query pattern tracking (Phase 8.02)\n *\n * @module IndexedORMap\n */\n\nimport { ORMap, ORMapRecord } from './ORMap';\nimport { HLC, Timestamp } from './HLC';\nimport { IndexRegistry, IndexRegistryStats } from './query/IndexRegistry';\nimport { QueryOptimizer } from './query/QueryOptimizer';\nimport type { Index, IndexStats, IndexQuery } from './query/indexes/types';\nimport { HashIndex } from './query/indexes/HashIndex';\nimport { NavigableIndex } from './query/indexes/NavigableIndex';\nimport { FallbackIndex } from './query/indexes/FallbackIndex';\nimport { InvertedIndex } from './query/indexes/InvertedIndex';\nimport { TokenizationPipeline } from './query/tokenization';\nimport { Attribute, simpleAttribute } from './query/Attribute';\nimport type { Query, QueryPlan, PlanStep, SimpleQueryNode } from './query/QueryTypes';\nimport { isSimpleQuery } from './query/QueryTypes';\nimport type { ResultSet } from './query/resultset/ResultSet';\nimport { SetResultSet } from './query/resultset/SetResultSet';\nimport { IntersectionResultSet } from './query/resultset/IntersectionResultSet';\nimport { UnionResultSet } from './query/resultset/UnionResultSet';\nimport { FilteringResultSet } from './query/resultset/FilteringResultSet';\nimport { evaluatePredicate, PredicateNode } from './predicate';\n\n// Full-Text Search imports (Phase 11)\nimport { FullTextIndex } from './fts/FullTextIndex';\nimport type { FullTextIndexConfig, SearchOptions as FTSSearchOptions, ScoredDocument } from './fts/types';\n\n// Adaptive indexing imports (Phase 8.02)\nimport {\n QueryPatternTracker,\n IndexAdvisor,\n AutoIndexManager,\n DefaultIndexingStrategy,\n} from './query/adaptive';\nimport type {\n IndexedMapOptions,\n IndexSuggestion,\n IndexSuggestionOptions,\n QueryStatistics,\n TrackedQueryType,\n RecommendedIndexType,\n} from './query/adaptive/types';\nimport { ADAPTIVE_INDEXING_DEFAULTS } from './query/adaptive/types';\n\n/**\n * Result of a query on IndexedORMap.\n */\nexport interface ORMapQueryResult<K, V> {\n key: K;\n tag: string;\n value: V;\n}\n\n/**\n * Result of a full-text search on IndexedORMap.\n * Includes BM25 relevance score for ranking.\n */\nexport interface ORMapSearchResult<K, V> extends ORMapQueryResult<K, V> {\n /** BM25 relevance score */\n score: number;\n /** Terms from the query that matched */\n matchedTerms: string[];\n}\n\n/**\n * ORMap with index support.\n *\n * Note: ORMap stores multiple values per key (with tags).\n * Indexes track unique (key, tag) pairs using composite keys.\n *\n * K = key type (extends string for compatibility)\n * V = value type\n */\nexport class IndexedORMap<K extends string, V> extends ORMap<K, V> {\n // Composite key = \"mapKey:tag\"\n private indexRegistry: IndexRegistry<string, V>;\n private queryOptimizer: QueryOptimizer<string, V>;\n\n // Adaptive indexing (Phase 8.02)\n private readonly queryTracker: QueryPatternTracker;\n private readonly indexAdvisor: IndexAdvisor;\n private readonly autoIndexManager: AutoIndexManager<string, V> | null;\n private readonly defaultIndexingStrategy: DefaultIndexingStrategy<V> | null;\n private readonly options: IndexedMapOptions;\n\n // Full-Text Search (Phase 11)\n private fullTextIndex: FullTextIndex | null = null;\n\n constructor(hlc: HLC, options: IndexedMapOptions = {}) {\n super(hlc);\n this.options = options;\n\n this.indexRegistry = new IndexRegistry();\n this.queryOptimizer = new QueryOptimizer({\n indexRegistry: this.indexRegistry,\n });\n\n // Set up fallback index for full scans\n this.indexRegistry.setFallbackIndex(\n new FallbackIndex<string, V>(\n () => this.getAllCompositeKeys(),\n (compositeKey) => this.getRecordByCompositeKey(compositeKey),\n (record, query) => this.matchesIndexQuery(record, query)\n )\n );\n\n // Initialize adaptive indexing (Phase 8.02)\n this.queryTracker = new QueryPatternTracker();\n this.indexAdvisor = new IndexAdvisor(this.queryTracker);\n\n // Initialize auto-index manager if enabled\n if (options.adaptiveIndexing?.autoIndex?.enabled) {\n this.autoIndexManager = new AutoIndexManager(\n this.queryTracker,\n this.indexAdvisor,\n options.adaptiveIndexing.autoIndex\n );\n this.autoIndexManager.setMap(this);\n } else {\n this.autoIndexManager = null;\n }\n\n // Initialize default indexing strategy\n if (options.defaultIndexing && options.defaultIndexing !== 'none') {\n this.defaultIndexingStrategy = new DefaultIndexingStrategy<V>(options.defaultIndexing);\n } else {\n this.defaultIndexingStrategy = null;\n }\n }\n\n // ==================== Index Management ====================\n\n /**\n * Add a hash index on an attribute.\n *\n * @param attribute - Attribute to index\n * @returns Created HashIndex\n */\n addHashIndex<A>(attribute: Attribute<V, A>): HashIndex<string, V, A> {\n const index = new HashIndex<string, V, A>(attribute);\n this.indexRegistry.addIndex(index);\n this.buildIndexFromExisting(index);\n return index;\n }\n\n /**\n * Add a navigable index on an attribute.\n * Navigable indexes support range queries (gt, gte, lt, lte, between).\n *\n * @param attribute - Attribute to index\n * @param comparator - Optional custom comparator\n * @returns Created NavigableIndex\n */\n addNavigableIndex<A extends string | number>(\n attribute: Attribute<V, A>,\n comparator?: (a: A, b: A) => number\n ): NavigableIndex<string, V, A> {\n const index = new NavigableIndex<string, V, A>(attribute, comparator);\n this.indexRegistry.addIndex(index);\n this.buildIndexFromExisting(index);\n return index;\n }\n\n /**\n * Add an inverted index for full-text search on an attribute.\n * Inverted indexes support text search queries (contains, containsAll, containsAny).\n *\n * @param attribute - Text attribute to index\n * @param pipeline - Optional custom tokenization pipeline\n * @returns Created InvertedIndex\n */\n addInvertedIndex<A extends string = string>(\n attribute: Attribute<V, A>,\n pipeline?: TokenizationPipeline\n ): InvertedIndex<string, V, A> {\n const index = new InvertedIndex<string, V, A>(attribute, pipeline);\n this.indexRegistry.addIndex(index);\n this.buildIndexFromExisting(index);\n return index;\n }\n\n /**\n * Add a custom index.\n *\n * @param index - Index to add\n */\n addIndex<A>(index: Index<string, V, A>): void {\n this.indexRegistry.addIndex(index);\n this.buildIndexFromExisting(index);\n }\n\n // ==================== Full-Text Search (Phase 11) ====================\n\n /**\n * Enable BM25-based full-text search on specified fields.\n * This creates a FullTextIndex for relevance-ranked search.\n *\n * Note: This is different from addInvertedIndex which provides\n * boolean matching (contains/containsAll/containsAny). This method\n * provides BM25 relevance scoring for true full-text search.\n *\n * @param config - Full-text index configuration\n * @returns The created FullTextIndex\n *\n * @example\n * ```typescript\n * const map = new IndexedORMap(hlc);\n * map.enableFullTextSearch({\n * fields: ['title', 'body'],\n * tokenizer: { minLength: 2 },\n * bm25: { k1: 1.2, b: 0.75 }\n * });\n *\n * map.add('doc1', { title: 'Hello World', body: 'Test content' });\n * const results = map.search('hello');\n * // [{ key: 'doc1', tag: '...', value: {...}, score: 0.5, matchedTerms: ['hello'] }]\n * ```\n */\n enableFullTextSearch(config: FullTextIndexConfig): FullTextIndex {\n // Create the full-text index\n this.fullTextIndex = new FullTextIndex(config);\n\n // Build from existing data\n const snapshot = this.getSnapshot();\n const entries: Array<[string, Record<string, unknown>]> = [];\n\n for (const [key, tagMap] of snapshot.items) {\n for (const [tag, record] of tagMap) {\n if (!snapshot.tombstones.has(tag)) {\n const compositeKey = this.createCompositeKey(key, tag);\n entries.push([compositeKey, record.value as Record<string, unknown>]);\n }\n }\n }\n\n this.fullTextIndex.buildFromEntries(entries);\n\n return this.fullTextIndex;\n }\n\n /**\n * Check if full-text search is enabled.\n *\n * @returns true if full-text search is enabled\n */\n isFullTextSearchEnabled(): boolean {\n return this.fullTextIndex !== null;\n }\n\n /**\n * Get the full-text index (if enabled).\n *\n * @returns The FullTextIndex or null\n */\n getFullTextIndex(): FullTextIndex | null {\n return this.fullTextIndex;\n }\n\n /**\n * Perform a BM25-ranked full-text search.\n * Results are sorted by relevance score (highest first).\n *\n * @param query - Search query text\n * @param options - Search options (limit, minScore, boost)\n * @returns Array of search results with scores, sorted by relevance\n *\n * @throws Error if full-text search is not enabled\n */\n search(query: string, options?: FTSSearchOptions): ORMapSearchResult<K, V>[] {\n if (!this.fullTextIndex) {\n throw new Error('Full-text search is not enabled. Call enableFullTextSearch() first.');\n }\n\n const scoredDocs = this.fullTextIndex.search(query, options);\n const results: ORMapSearchResult<K, V>[] = [];\n\n for (const { docId: compositeKey, score, matchedTerms } of scoredDocs) {\n const [key, tag] = this.parseCompositeKey(compositeKey);\n const records = this.getRecords(key as K);\n const record = records.find((r) => r.tag === tag);\n\n if (record) {\n results.push({\n key: key as K,\n tag,\n value: record.value,\n score,\n matchedTerms: matchedTerms ?? [],\n });\n }\n }\n\n return results;\n }\n\n /**\n * Disable full-text search and release the index.\n */\n disableFullTextSearch(): void {\n if (this.fullTextIndex) {\n this.fullTextIndex.clear();\n this.fullTextIndex = null;\n }\n }\n\n /**\n * Remove an index.\n *\n * @param index - Index to remove\n * @returns true if index was found and removed\n */\n removeIndex<A>(index: Index<string, V, A>): boolean {\n return this.indexRegistry.removeIndex(index);\n }\n\n /**\n * Get all indexes.\n *\n * @returns Array of all indexes\n */\n getIndexes(): Index<string, V, unknown>[] {\n return this.indexRegistry.getAllIndexes();\n }\n\n /**\n * Check if an attribute is indexed.\n *\n * @param attributeName - Attribute name\n * @returns true if attribute has indexes\n */\n hasIndexOn(attributeName: string): boolean {\n return this.indexRegistry.hasIndex(attributeName);\n }\n\n /**\n * Build index from existing data.\n */\n private buildIndexFromExisting<A>(index: Index<string, V, A>): void {\n const snapshot = this.getSnapshot();\n for (const [key, tagMap] of snapshot.items) {\n for (const [tag, record] of tagMap) {\n if (!snapshot.tombstones.has(tag)) {\n const compositeKey = this.createCompositeKey(key, tag);\n index.add(compositeKey, record.value);\n }\n }\n }\n }\n\n // ==================== Query Execution ====================\n\n /**\n * Execute a query across all records.\n * Returns array of matching results with key, tag, and value.\n *\n * Also tracks query patterns for adaptive indexing (Phase 8.02).\n *\n * @param query - Query to execute\n * @returns Array of query results\n */\n query(query: Query): ORMapQueryResult<K, V>[] {\n const start = performance.now();\n const plan = this.queryOptimizer.optimize(query);\n const resultSet = this.executePlan(plan.root);\n\n const results: ORMapQueryResult<K, V>[] = [];\n for (const compositeKey of resultSet) {\n const [key, tag] = this.parseCompositeKey(compositeKey);\n const records = this.getRecords(key as K);\n const record = records.find((r) => r.tag === tag);\n if (record) {\n results.push({ key: key as K, tag, value: record.value });\n }\n }\n\n // Track query pattern for adaptive indexing (Phase 8.02)\n const duration = performance.now() - start;\n this.trackQueryPattern(query, duration, results.length, plan.usesIndexes);\n\n return results;\n }\n\n /**\n * Execute a query and return matching values only.\n *\n * @param query - Query to execute\n * @returns Array of matching values\n */\n queryValues(query: Query): V[] {\n return this.query(query).map((r) => r.value);\n }\n\n /**\n * Count matching records without materializing results.\n *\n * @param query - Query to execute\n * @returns Number of matching records\n */\n count(query: Query): number {\n const plan = this.queryOptimizer.optimize(query);\n const resultSet = this.executePlan(plan.root);\n return resultSet.size();\n }\n\n /**\n * Execute plan and return result set.\n */\n private executePlan(step: PlanStep): ResultSet<string> {\n switch (step.type) {\n case 'index-scan':\n return step.index.retrieve(step.query) as ResultSet<string>;\n\n case 'full-scan': {\n const fallback = this.indexRegistry.getFallbackIndex();\n if (fallback) {\n // FallbackIndex uses predicate internally - cast through unknown for compatibility\n return fallback.retrieve(step.predicate as unknown as IndexQuery<unknown>) as ResultSet<string>;\n }\n return this.fullScan(step.predicate as Query);\n }\n\n case 'intersection':\n return new IntersectionResultSet(\n step.steps.map((s) => this.executePlan(s))\n );\n\n case 'union':\n return new UnionResultSet(step.steps.map((s) => this.executePlan(s)));\n\n case 'filter':\n return new FilteringResultSet(\n this.executePlan(step.source),\n (compositeKey) => this.getRecordByCompositeKey(compositeKey),\n (record) => {\n if (record === undefined) return false;\n return this.matchesPredicate(record, step.predicate as Query);\n }\n );\n\n case 'not': {\n const matching = new Set(this.executePlan(step.source).toArray());\n const allKeysSet = new Set(this.getAllCompositeKeys());\n for (const key of matching) {\n allKeysSet.delete(key);\n }\n return new SetResultSet(allKeysSet, 100);\n }\n\n default:\n throw new Error(`Unknown plan step type: ${(step as PlanStep).type}`);\n }\n }\n\n /**\n * Perform full scan with predicate evaluation.\n */\n private fullScan(query: Query): ResultSet<string> {\n const result = new Set<string>();\n const snapshot = this.getSnapshot();\n\n for (const [key, tagMap] of snapshot.items) {\n for (const [tag, record] of tagMap) {\n if (!snapshot.tombstones.has(tag)) {\n if (this.matchesPredicate(record.value, query)) {\n result.add(this.createCompositeKey(key, tag));\n }\n }\n }\n }\n\n return new SetResultSet(result, Number.MAX_SAFE_INTEGER);\n }\n\n // ==================== Override CRDT Operations ====================\n\n /**\n * Add a value (with index updates).\n */\n public add(key: K, value: V, ttlMs?: number): ORMapRecord<V> {\n const record = super.add(key, value, ttlMs);\n const compositeKey = this.createCompositeKey(key, record.tag);\n this.indexRegistry.onRecordAdded(compositeKey, value);\n\n // Update full-text index (Phase 11)\n if (this.fullTextIndex) {\n this.fullTextIndex.onSet(compositeKey, value as Record<string, unknown>);\n }\n\n return record;\n }\n\n /**\n * Remove a value (with index updates).\n */\n public remove(key: K, value: V): string[] {\n const records = this.getRecords(key);\n const matchingRecords = records.filter((r) => r.value === value);\n const result = super.remove(key, value);\n\n for (const record of matchingRecords) {\n const compositeKey = this.createCompositeKey(key, record.tag);\n this.indexRegistry.onRecordRemoved(compositeKey, record.value);\n\n // Update full-text index (Phase 11)\n if (this.fullTextIndex) {\n this.fullTextIndex.onRemove(compositeKey);\n }\n }\n\n return result;\n }\n\n /**\n * Apply a record from remote (with index updates).\n */\n public apply(key: K, record: ORMapRecord<V>): boolean {\n const applied = super.apply(key, record);\n if (applied) {\n const compositeKey = this.createCompositeKey(key, record.tag);\n this.indexRegistry.onRecordAdded(compositeKey, record.value);\n\n // Update full-text index (Phase 11)\n if (this.fullTextIndex) {\n this.fullTextIndex.onSet(compositeKey, record.value as Record<string, unknown>);\n }\n }\n return applied;\n }\n\n /**\n * Apply a tombstone (with index updates).\n */\n public applyTombstone(tag: string): void {\n // Find the record before tombstoning\n const snapshot = this.getSnapshot();\n let removedValue: V | undefined;\n let removedKey: K | undefined;\n\n for (const [key, tagMap] of snapshot.items) {\n const record = tagMap.get(tag);\n if (record) {\n removedValue = record.value;\n removedKey = key;\n break;\n }\n }\n\n super.applyTombstone(tag);\n\n if (removedValue !== undefined && removedKey !== undefined) {\n const compositeKey = this.createCompositeKey(removedKey, tag);\n this.indexRegistry.onRecordRemoved(compositeKey, removedValue);\n\n // Update full-text index (Phase 11)\n if (this.fullTextIndex) {\n this.fullTextIndex.onRemove(compositeKey);\n }\n }\n }\n\n /**\n * Clear all data (and indexes).\n */\n public clear(): void {\n super.clear();\n this.indexRegistry.clear();\n\n // Clear full-text index (Phase 11)\n if (this.fullTextIndex) {\n this.fullTextIndex.clear();\n }\n }\n\n // ==================== Helper Methods ====================\n\n /**\n * Create composite key from map key and tag.\n * Uses '||' as separator since HLC tags contain ':'\n */\n private createCompositeKey(key: K, tag: string): string {\n return `${key}||${tag}`;\n }\n\n /**\n * Parse composite key into [key, tag].\n * Expects '||' separator.\n */\n private parseCompositeKey(compositeKey: string): [string, string] {\n const separatorIndex = compositeKey.indexOf('||');\n if (separatorIndex === -1) {\n // Fallback for malformed keys\n return [compositeKey, ''];\n }\n return [\n compositeKey.substring(0, separatorIndex),\n compositeKey.substring(separatorIndex + 2),\n ];\n }\n\n /**\n * Get all composite keys from the map.\n */\n private getAllCompositeKeys(): Iterable<string> {\n const self = this;\n return {\n *[Symbol.iterator]() {\n const snapshot = self.getSnapshot();\n for (const [key, tagMap] of snapshot.items) {\n for (const [tag] of tagMap) {\n if (!snapshot.tombstones.has(tag)) {\n yield self.createCompositeKey(key, tag);\n }\n }\n }\n },\n };\n }\n\n /**\n * Get record by composite key.\n */\n private getRecordByCompositeKey(compositeKey: string): V | undefined {\n const [key, tag] = this.parseCompositeKey(compositeKey);\n const records = this.getRecords(key as K);\n const record = records.find((r) => r.tag === tag);\n return record?.value;\n }\n\n /**\n * Check if record matches predicate.\n */\n private matchesPredicate(record: V, query: Query): boolean {\n try {\n const predicate = this.queryToPredicate(query);\n return evaluatePredicate(predicate, record);\n } catch {\n return false;\n }\n }\n\n /**\n * Check if record matches IndexQuery (used by FallbackIndex).\n * This is a simplified matcher for full scan fallback.\n */\n private matchesIndexQuery(record: V, query: IndexQuery<unknown>): boolean {\n // Full scan matcher - evaluates the stored predicate\n // FallbackIndex passes the original query predicate\n if ('attribute' in (query as unknown as Record<string, unknown>)) {\n // This is a Query-like object passed through\n return this.matchesPredicate(record, query as unknown as Query);\n }\n // For simple IndexQuery without attribute context, always match\n return true;\n }\n\n /**\n * Convert Query to PredicateNode format.\n */\n private queryToPredicate(query: Query): PredicateNode {\n if ('type' in query) {\n switch (query.type) {\n case 'eq':\n return {\n op: 'eq',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'neq':\n return {\n op: 'neq',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'gt':\n return {\n op: 'gt',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'gte':\n return {\n op: 'gte',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'lt':\n return {\n op: 'lt',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'lte':\n return {\n op: 'lte',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'and':\n return {\n op: 'and',\n children: ((query as { children: Query[] }).children || []).map(\n (c) => this.queryToPredicate(c)\n ),\n };\n case 'or':\n return {\n op: 'or',\n children: ((query as { children: Query[] }).children || []).map(\n (c) => this.queryToPredicate(c)\n ),\n };\n case 'not':\n return {\n op: 'not',\n children: [\n this.queryToPredicate((query as { child: Query }).child),\n ],\n };\n case 'contains':\n return {\n op: 'contains',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'containsAll':\n return {\n op: 'containsAll',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { values: unknown[] }).values,\n };\n case 'containsAny':\n return {\n op: 'containsAny',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { values: unknown[] }).values,\n };\n default:\n return { op: 'eq', value: null };\n }\n }\n return { op: 'eq', value: null };\n }\n\n // ==================== Stats ====================\n\n /**\n * Get index statistics.\n */\n getIndexStats(): Map<string, IndexStats> {\n const stats = new Map<string, IndexStats>();\n for (const index of this.indexRegistry.getAllIndexes()) {\n stats.set(index.attribute.name, index.getStats());\n }\n return stats;\n }\n\n /**\n * Get index registry statistics.\n */\n getIndexRegistryStats(): IndexRegistryStats {\n return this.indexRegistry.getStats();\n }\n\n /**\n * Get query optimizer for plan inspection.\n */\n getQueryOptimizer(): QueryOptimizer<string, V> {\n return this.queryOptimizer;\n }\n\n /**\n * Explain query execution plan.\n *\n * @param query - Query to explain\n * @returns Query execution plan\n */\n explainQuery(query: Query): QueryPlan {\n return this.queryOptimizer.optimize(query);\n }\n\n // ==================== Adaptive Indexing (Phase 8.02) ====================\n\n /**\n * Register an attribute for auto-indexing.\n * Required before auto-index can create indexes on this attribute.\n *\n * @param attribute - The attribute to register\n * @param allowedIndexTypes - Optional list of allowed index types\n */\n registerAttribute<A>(\n attribute: Attribute<V, A>,\n allowedIndexTypes?: RecommendedIndexType[]\n ): void {\n if (this.autoIndexManager) {\n this.autoIndexManager.registerAttribute(attribute, allowedIndexTypes);\n }\n }\n\n /**\n * Unregister an attribute from auto-indexing.\n *\n * @param attributeName - Name of attribute to unregister\n */\n unregisterAttribute(attributeName: string): void {\n if (this.autoIndexManager) {\n this.autoIndexManager.unregisterAttribute(attributeName);\n }\n }\n\n /**\n * Get index suggestions based on query patterns.\n * Use this in production to get recommendations for manual index creation.\n *\n * @param options - Suggestion options\n * @returns Array of index suggestions sorted by priority\n */\n getIndexSuggestions(options?: IndexSuggestionOptions): IndexSuggestion[] {\n return this.indexAdvisor.getSuggestions(options);\n }\n\n /**\n * Get query pattern statistics.\n * Useful for debugging and understanding query patterns.\n *\n * @returns Array of query statistics\n */\n getQueryStatistics(): QueryStatistics[] {\n return this.queryTracker.getStatistics();\n }\n\n /**\n * Reset query statistics.\n * Call this to clear accumulated query patterns.\n */\n resetQueryStatistics(): void {\n this.queryTracker.clear();\n if (this.autoIndexManager) {\n this.autoIndexManager.resetCounts();\n }\n }\n\n /**\n * Get query pattern tracker for advanced usage.\n */\n getQueryTracker(): QueryPatternTracker {\n return this.queryTracker;\n }\n\n /**\n * Get index advisor for advanced usage.\n */\n getIndexAdvisor(): IndexAdvisor {\n return this.indexAdvisor;\n }\n\n /**\n * Get auto-index manager (if enabled).\n */\n getAutoIndexManager(): AutoIndexManager<string, V> | null {\n return this.autoIndexManager;\n }\n\n /**\n * Check if auto-indexing is enabled.\n */\n isAutoIndexingEnabled(): boolean {\n return this.autoIndexManager !== null;\n }\n\n /**\n * Track query pattern for adaptive indexing.\n */\n private trackQueryPattern(\n query: Query,\n duration: number,\n resultSize: number,\n usedIndex: boolean\n ): void {\n // Only track if advisor is enabled (default: true)\n const advisorEnabled = this.options.adaptiveIndexing?.advisor?.enabled ??\n ADAPTIVE_INDEXING_DEFAULTS.advisor.enabled;\n\n if (!advisorEnabled && !this.autoIndexManager) {\n return;\n }\n\n // Extract attribute from query\n const attribute = this.extractAttribute(query);\n if (!attribute) return;\n\n // Extract query type\n const queryType = this.extractQueryType(query);\n if (!queryType) return;\n\n // Check if this attribute has an index\n const hasIndex = this.indexRegistry.hasIndex(attribute);\n\n // Record query in tracker\n this.queryTracker.recordQuery(\n attribute,\n queryType,\n duration,\n resultSize,\n hasIndex\n );\n\n // Notify auto-index manager if enabled\n if (this.autoIndexManager) {\n this.autoIndexManager.onQueryExecuted(attribute, queryType);\n }\n }\n\n /**\n * Extract attribute name from query.\n */\n private extractAttribute(query: Query): string | null {\n if (isSimpleQuery(query)) {\n return (query as SimpleQueryNode).attribute;\n }\n\n // For compound queries, extract from first child\n if (query.type === 'and' || query.type === 'or') {\n const children = (query as { children?: Query[] }).children;\n if (children && children.length > 0) {\n return this.extractAttribute(children[0]);\n }\n }\n\n if (query.type === 'not') {\n const child = (query as { child?: Query }).child;\n if (child) {\n return this.extractAttribute(child);\n }\n }\n\n return null;\n }\n\n /**\n * Extract query type from query.\n */\n private extractQueryType(query: Query): TrackedQueryType | null {\n if (isSimpleQuery(query)) {\n const type = query.type;\n // Only track types that can be indexed\n const indexableTypes: TrackedQueryType[] = [\n 'eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'between', 'in', 'has',\n 'contains', 'containsAll', 'containsAny',\n ];\n if (indexableTypes.includes(type as TrackedQueryType)) {\n return type as TrackedQueryType;\n }\n }\n\n // For compound queries, extract from first child\n if (query.type === 'and' || query.type === 'or') {\n const children = (query as { children?: Query[] }).children;\n if (children && children.length > 0) {\n return this.extractQueryType(children[0]);\n }\n }\n\n if (query.type === 'not') {\n const child = (query as { child?: Query }).child;\n if (child) {\n return this.extractQueryType(child);\n }\n }\n\n return null;\n }\n}\n"],"mappings":"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","names":["h","h","import_zod","import_zod","WriteConcern","PartitionState","ConsistencyLevel","BTree","index"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/HLC.ts","../src/utils/hash.ts","../src/MerkleTree.ts","../src/LWWMap.ts","../src/ORMapMerkle.ts","../src/ORMapMerkleTree.ts","../src/ORMap.ts","../src/serializer.ts","../src/PNCounter.ts","../src/Ringbuffer.ts","../src/EventJournal.ts","../src/EntryProcessor.ts","../src/ConflictResolver.ts","../src/predicate.ts","../src/schemas.ts","../src/types/WriteConcern.ts","../src/types/cluster.ts","../src/query/ds/SortedMap.ts","../src/query/ds/types.ts","../src/query/Attribute.ts","../src/query/resultset/SetResultSet.ts","../src/query/indexes/HashIndex.ts","../src/query/resultset/LazyResultSet.ts","../src/query/indexes/NavigableIndex.ts","../src/query/indexes/FallbackIndex.ts","../src/query/QueryTypes.ts","../src/query/indexes/StandingQueryIndex.ts","../src/query/tokenization/Tokenizer.ts","../src/query/tokenization/TokenFilter.ts","../src/query/tokenization/TokenizationPipeline.ts","../src/query/indexes/InvertedIndex.ts","../src/query/indexes/CompoundIndex.ts","../src/query/indexes/lazy/LazyHashIndex.ts","../src/query/indexes/lazy/LazyNavigableIndex.ts","../src/query/indexes/lazy/LazyInvertedIndex.ts","../src/query/resultset/IntersectionResultSet.ts","../src/query/resultset/UnionResultSet.ts","../src/query/resultset/FilteringResultSet.ts","../src/query/resultset/SortedResultSet.ts","../src/query/resultset/LimitResultSet.ts","../src/query/IndexRegistry.ts","../src/query/QueryOptimizer.ts","../src/query/StandingQueryRegistry.ts","../src/query/LiveQueryManager.ts","../src/query/adaptive/types.ts","../src/query/adaptive/QueryPatternTracker.ts","../src/query/adaptive/IndexAdvisor.ts","../src/query/adaptive/AutoIndexManager.ts","../src/query/adaptive/DefaultIndexingStrategy.ts","../src/search/ReciprocalRankFusion.ts","../src/utils/base64url.ts","../src/utils/compare.ts","../src/query/QueryCursor.ts","../src/IndexedLWWMap.ts","../src/query/tokenization/stopwords.ts","../src/query/tokenization/porter-stemmer.ts","../src/fts/Tokenizer.ts","../src/fts/BM25InvertedIndex.ts","../src/fts/BM25Scorer.ts","../src/fts/IndexSerializer.ts","../src/fts/FullTextIndex.ts","../src/IndexedORMap.ts","../src/search/SearchCursor.ts"],"sourcesContent":["import { HLC, Timestamp } from './HLC';\nimport { LWWMap, LWWRecord } from './LWWMap';\nimport { ORMap, ORMapRecord, MergeKeyResult, ORMapSnapshot } from './ORMap';\nimport { MerkleTree } from './MerkleTree';\nimport { ORMapMerkleTree, ORMapMerkleNode } from './ORMapMerkleTree';\nimport { hashORMapEntry, hashORMapRecord, timestampToString, compareTimestamps } from './ORMapMerkle';\nimport { PNCounterImpl } from './PNCounter';\nimport type { PNCounter, PNCounterState, PNCounterStateObject, PNCounterConfig } from './PNCounter';\nimport { Ringbuffer } from './Ringbuffer';\nimport { EventJournalImpl, DEFAULT_EVENT_JOURNAL_CONFIG } from './EventJournal';\nimport type {\n EventJournal,\n EventJournalConfig,\n JournalEvent,\n JournalEventInput,\n JournalEventType,\n JournalEventListener,\n} from './EventJournal';\n\nexport { HLC, LWWMap, ORMap, MerkleTree, ORMapMerkleTree, PNCounterImpl };\nexport { hashORMapEntry, hashORMapRecord, timestampToString, compareTimestamps };\nexport type { PNCounter, PNCounterState, PNCounterStateObject, PNCounterConfig };\n\n// Event Journal exports (Phase 5.04)\nexport { Ringbuffer, EventJournalImpl, DEFAULT_EVENT_JOURNAL_CONFIG };\nexport type {\n EventJournal,\n EventJournalConfig,\n JournalEvent,\n JournalEventInput,\n JournalEventType,\n JournalEventListener,\n};\n\n// Entry Processor exports (Phase 5.03)\nexport {\n EntryProcessorDefSchema,\n validateProcessorCode,\n BuiltInProcessors,\n FORBIDDEN_PATTERNS,\n DEFAULT_PROCESSOR_RATE_LIMITS,\n} from './EntryProcessor';\nexport type {\n EntryProcessorFn,\n EntryProcessorDef,\n EntryProcessorResult,\n ProcessorRateLimitConfig,\n} from './EntryProcessor';\n\n// Conflict Resolver exports (Phase 5.05)\nexport {\n ConflictResolverDefSchema,\n validateResolverCode,\n BuiltInResolvers,\n RESOLVER_FORBIDDEN_PATTERNS,\n DEFAULT_RESOLVER_RATE_LIMITS,\n compareHLCTimestamps,\n deepMerge,\n} from './ConflictResolver';\nexport type {\n MergeContext,\n MergeResult,\n ConflictResolverFn,\n ConflictResolverDef,\n ResolverRateLimitConfig,\n MergeRejection,\n} from './ConflictResolver';\n\nexport * from './utils/hash';\nexport * from './serializer';\nexport * from './predicate';\nexport * from './security';\nexport * from './schemas';\nexport type { Timestamp, LWWRecord, ORMapRecord, MergeKeyResult, ORMapSnapshot, ORMapMerkleNode };\n\n// Re-export heartbeat types for convenience\nexport type { PingMessage, PongMessage } from './schemas';\n\n// Write Concern exports (Phase 5.01)\nexport {\n WriteConcern,\n WriteOptions,\n WriteResult,\n PendingWrite,\n WRITE_CONCERN_ORDER,\n DEFAULT_WRITE_CONCERN_TIMEOUT,\n isWriteConcernAchieved,\n getHighestWriteConcernLevel,\n} from './types/WriteConcern';\nexport type { WriteConcernValue } from './schemas';\n\n// Cluster types exports (Phase 4)\nexport type {\n NodeStatus,\n NodeInfo,\n PartitionInfo,\n PartitionMap,\n PartitionMapMessage,\n PartitionMapRequestMessage,\n PartitionChange,\n PartitionMapDeltaMessage,\n NotOwnerError,\n StaleMapError,\n RoutingError,\n ConnectionPoolConfig,\n PartitionRouterConfig,\n ClusterClientConfig,\n CircuitBreakerConfig,\n ConnectionState,\n NodeHealth,\n ClusterEvents,\n // Migration types (Task 03)\n PartitionMigration,\n MigrationConfig,\n MigrationStatus,\n MigrationMetrics,\n MigrationStartMessage,\n MigrationChunkMessage,\n MigrationChunkAckMessage,\n MigrationCompleteMessage,\n MigrationVerifyMessage,\n MigrationMessage,\n // Replication types (Task 04)\n WriteOptions as ClusterWriteOptions,\n ReadOptions as ClusterReadOptions,\n ReplicationConfig,\n ReplicationTask,\n ReplicationLag,\n ReplicationHealth,\n ReplicationResult,\n ReplicationMessage,\n ReplicationBatchMessage,\n ReplicationAckMessage,\n ReplicationBatchAckMessage,\n ReplicationProtocolMessage,\n} from './types/cluster';\nexport {\n DEFAULT_CONNECTION_POOL_CONFIG,\n DEFAULT_PARTITION_ROUTER_CONFIG,\n DEFAULT_CIRCUIT_BREAKER_CONFIG,\n PARTITION_COUNT,\n DEFAULT_BACKUP_COUNT,\n // Migration exports (Task 03)\n PartitionState,\n DEFAULT_MIGRATION_CONFIG,\n // Replication exports (Task 04)\n ConsistencyLevel,\n DEFAULT_REPLICATION_CONFIG,\n} from './types/cluster';\n\n// Query Engine exports (Phase 7 + Phase 8.01)\n// Note: Query from schemas conflicts with Query from query/QueryTypes\n// We rename query engine Query to QueryExpression to avoid conflict\nexport {\n // Data structures\n SortedMap,\n // Attribute system\n SimpleAttribute,\n MultiValueAttribute,\n simpleAttribute,\n multiAttribute,\n // Indexes\n HashIndex,\n NavigableIndex,\n StandingQueryIndex,\n FallbackIndex,\n createPredicateMatcher,\n InvertedIndex,\n // Tokenization (Phase 8.01)\n TokenizationPipeline,\n WhitespaceTokenizer,\n WordBoundaryTokenizer,\n NGramTokenizer,\n LowercaseFilter,\n StopWordFilter,\n MinLengthFilter,\n MaxLengthFilter,\n TrimFilter,\n UniqueFilter,\n DEFAULT_STOP_WORDS,\n // ResultSet\n SetResultSet,\n LazyResultSet,\n IntersectionResultSet,\n UnionResultSet,\n FilteringResultSet,\n SortedResultSet,\n createFieldComparator,\n LimitResultSet,\n // Type Guards\n isSimpleQuery,\n isLogicalQuery,\n // Index Registry\n IndexRegistry,\n // Query Optimizer\n QueryOptimizer,\n // Standing Query Registry\n StandingQueryRegistry,\n // Live Query Manager\n LiveQueryManager,\n // Query Cursor (Phase 14.1)\n QueryCursor,\n DEFAULT_QUERY_CURSOR_MAX_AGE_MS,\n} from './query';\n\n// Base64URL utilities (Phase 14.1)\nexport { encodeBase64Url, decodeBase64Url } from './utils/base64url';\n\n// Compare utilities (Phase 14.1)\nexport { compareValues } from './utils/compare';\n\nexport type {\n // Attribute system\n Attribute,\n // Indexes\n StandingQueryChange,\n StandingQueryIndexOptions,\n Index,\n IndexQuery,\n IndexStats,\n InvertedIndexStats,\n // Tokenization (Phase 8.01)\n Tokenizer,\n TokenFilter,\n TokenizationPipelineOptions,\n // ResultSet\n ResultSet,\n IteratorFactory,\n PredicateFn,\n CompareFn,\n // Query Types (renamed to avoid conflict with schemas.Query)\n QueryNode,\n SimpleQueryNode,\n LogicalQueryNode,\n QueryOptions,\n PlanStep,\n IndexScanStep,\n FullScanStep,\n IntersectionStep,\n UnionStep,\n FilterStep,\n NotStep,\n QueryPlan,\n // Index Registry\n IndexRegistryStats,\n // Query Optimizer\n QueryOptimizerOptions,\n // Standing Query Registry\n StandingQueryRegistryOptions,\n StandingQueryRegistryStats,\n // Live Query Manager\n LiveQueryManagerOptions,\n LiveQueryManagerStats,\n LiveQueryCallback,\n LiveQueryEvent,\n LiveQueryInitialEvent,\n LiveQueryDeltaEvent,\n // Query Cursor (Phase 14.1)\n QueryCursorData,\n CursorableQueryResult,\n QueryCursorOptions,\n QueryResultWithCursor,\n} from './query';\n\n// Re-export Query from query module as QueryExpression to avoid conflict\nexport type { Query as QueryExpression } from './query';\n\n// Indexed CRDT exports (Phase 7.07)\nexport { IndexedLWWMap } from './IndexedLWWMap';\nexport { IndexedORMap, type ORMapQueryResult, type ORMapSearchResult } from './IndexedORMap';\n\n// Full-Text Search exports (Phase 11)\nexport {\n // Tokenizer\n Tokenizer as FTSTokenizer,\n ENGLISH_STOPWORDS,\n porterStem,\n // Inverted Index\n InvertedIndex as FTSInvertedIndex,\n // BM25 Scorer\n BM25Scorer,\n // Full-Text Index (high-level integration)\n FullTextIndex,\n} from './fts';\nexport type {\n // Types\n TokenizerOptions as FTSTokenizerOptions,\n TermInfo,\n Posting,\n BM25Options,\n ScoredDocument,\n FullTextIndexConfig,\n SearchOptions as FTSSearchOptions,\n SearchResult as FTSSearchResult,\n SerializedIndex,\n} from './fts';\n\n// Search utilities exports (Phase 12 + Phase 14)\nexport {\n ReciprocalRankFusion,\n SearchCursor,\n DEFAULT_CURSOR_MAX_AGE_MS,\n} from './search';\nexport type {\n RankedResult,\n RRFConfig,\n MergedResult,\n SearchCursorData,\n CursorableResult,\n} from './search';\n","export interface Timestamp {\n millis: number;\n counter: number;\n nodeId: string;\n}\n\nexport class HLC {\n private lastMillis: number;\n private lastCounter: number;\n private readonly nodeId: string;\n\n // Max allowable drift in milliseconds (1 minute)\n private static readonly MAX_DRIFT = 60000;\n\n constructor(nodeId: string) {\n this.nodeId = nodeId;\n this.lastMillis = 0;\n this.lastCounter = 0;\n }\n\n public get getNodeId(): string {\n return this.nodeId;\n }\n\n /**\n * Generates a new unique timestamp for a local event.\n * Ensures monotonicity: always greater than any previously generated or received timestamp.\n */\n public now(): Timestamp {\n const systemTime = Date.now();\n \n // If local physical time catches up to logical time, reset counter\n if (systemTime > this.lastMillis) {\n this.lastMillis = systemTime;\n this.lastCounter = 0;\n } else {\n // Else, just increment the logical counter\n this.lastCounter++;\n }\n\n return {\n millis: this.lastMillis,\n counter: this.lastCounter,\n nodeId: this.nodeId\n };\n }\n\n /**\n * Updates the local clock based on a received remote timestamp.\n * Must be called whenever a message/event is received from another node.\n */\n public update(remote: Timestamp): void {\n const systemTime = Date.now();\n\n // Validate drift (optional but good practice)\n if (remote.millis > systemTime + HLC.MAX_DRIFT) {\n console.warn(`Clock drift detected: Remote time ${remote.millis} is far ahead of local ${systemTime}`);\n // In strict systems we might reject, but in AP systems we usually accept and fast-forward\n }\n\n const maxMillis = Math.max(this.lastMillis, systemTime, remote.millis);\n\n if (maxMillis === this.lastMillis && maxMillis === remote.millis) {\n // Both clocks are on the same millisecond, take max counter\n this.lastCounter = Math.max(this.lastCounter, remote.counter) + 1;\n } else if (maxMillis === this.lastMillis) {\n // Local logical clock is ahead in millis (or same as remote but remote millis < local)\n this.lastCounter++;\n } else if (maxMillis === remote.millis) {\n // Remote clock is ahead, fast-forward local\n this.lastCounter = remote.counter + 1;\n } else {\n // System time is ahead of both\n this.lastCounter = 0;\n }\n\n this.lastMillis = maxMillis;\n }\n\n /**\n * Compares two timestamps.\n * Returns -1 if a < b, 1 if a > b, 0 if equal.\n */\n public static compare(a: Timestamp, b: Timestamp): number {\n if (a.millis !== b.millis) {\n return a.millis - b.millis;\n }\n if (a.counter !== b.counter) {\n return a.counter - b.counter;\n }\n return a.nodeId.localeCompare(b.nodeId);\n }\n\n /**\n * Serializes timestamp to a string representation (e.g., for storage/network).\n * Format: \"<millis>:<counter>:<nodeId>\"\n */\n public static toString(ts: Timestamp): string {\n return `${ts.millis}:${ts.counter}:${ts.nodeId}`;\n }\n\n /**\n * Parses a string representation back to a Timestamp object.\n */\n public static parse(str: string): Timestamp {\n const parts = str.split(':');\n if (parts.length !== 3) {\n throw new Error(`Invalid timestamp format: ${str}`);\n }\n return {\n millis: parseInt(parts[0], 10),\n counter: parseInt(parts[1], 10),\n nodeId: parts[2]\n };\n }\n}\n","/**\n * Hash utilities for TopGun\n *\n * Uses native xxHash64 when available (via @topgunbuild/native),\n * falls back to FNV-1a for JS-only environments.\n *\n * Phase 3.05: Native Hash Integration\n */\n\n// Try to load native hash module\nlet nativeHash: {\n hashString: (str: string) => number;\n isNativeHashAvailable: () => boolean;\n} | null = null;\n\nlet nativeLoadAttempted = false;\n\nfunction tryLoadNative(): void {\n if (nativeLoadAttempted) return;\n nativeLoadAttempted = true;\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n nativeHash = require('@topgunbuild/native');\n } catch {\n // Native module not available, will use FNV-1a fallback\n }\n}\n\n/**\n * FNV-1a Hash implementation for strings.\n * Fast, non-cryptographic, synchronous.\n * Used as fallback when native module is unavailable.\n */\nfunction fnv1aHash(str: string): number {\n let hash = 0x811c9dc5;\n for (let i = 0; i < str.length; i++) {\n hash ^= str.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return hash >>> 0; // Ensure positive 32-bit integer\n}\n\n/**\n * Hash a string to a 32-bit unsigned integer.\n *\n * Uses native xxHash64 (truncated to 32 bits) when available,\n * otherwise falls back to FNV-1a.\n *\n * @param str - String to hash\n * @returns 32-bit unsigned integer hash\n */\nexport function hashString(str: string): number {\n tryLoadNative();\n\n if (nativeHash && nativeHash.isNativeHashAvailable()) {\n return nativeHash.hashString(str);\n }\n\n return fnv1aHash(str);\n}\n\n/**\n * Combines multiple hash numbers into one order-independent hash.\n * Used for combining bucket hashes in Merkle trees.\n *\n * Uses simple sum (with overflow handling) for order-independence.\n *\n * @param hashes - Array of hash values to combine\n * @returns Combined hash as 32-bit unsigned integer\n */\nexport function combineHashes(hashes: number[]): number {\n let result = 0;\n for (const h of hashes) {\n result = (result + h) | 0; // Simple sum with overflow\n }\n return result >>> 0;\n}\n\n/**\n * Check if native hash module is being used.\n * Useful for diagnostics and testing.\n */\nexport function isUsingNativeHash(): boolean {\n tryLoadNative();\n return nativeHash?.isNativeHashAvailable() === true;\n}\n\n/**\n * Force use of FNV-1a hash (for testing/compatibility).\n * After calling this, hashString will always use FNV-1a.\n */\nexport function disableNativeHash(): void {\n nativeHash = null;\n nativeLoadAttempted = true;\n}\n\n/**\n * Re-enable native hash loading (for testing).\n * Resets the load state so native module can be loaded again.\n */\nexport function resetNativeHash(): void {\n nativeHash = null;\n nativeLoadAttempted = false;\n}\n\n/**\n * Hash an object to a 32-bit unsigned integer.\n * Uses deterministic JSON serialization + hashString.\n *\n * @param obj - Object to hash (must be JSON-serializable)\n * @returns 32-bit unsigned integer hash\n */\nexport function hashObject(obj: unknown): number {\n // Deterministic serialization: sort object keys recursively\n const json = JSON.stringify(obj, (_, value) => {\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n return Object.keys(value)\n .sort()\n .reduce((sorted: Record<string, unknown>, key) => {\n sorted[key] = value[key];\n return sorted;\n }, {});\n }\n return value;\n });\n\n return hashString(json);\n}\n","import { LWWRecord } from './LWWMap';\nimport { hashString } from './utils/hash';\n\nexport interface MerkleNode {\n hash: number;\n children?: { [key: string]: MerkleNode }; // Keyed by bucket index (hex char)\n entries?: Map<string, number>; // Leaf node: Key -> ContentHash\n}\n\n/**\n * A specific implementation of Merkle Tree for syncing LWW-Maps.\n * It uses a Prefix Trie structure based on the hash of the Record Key.\n * \n * Structure:\n * - Level 0: Root\n * - Level 1..N: Buckets based on hex digits of Key Hash.\n * \n * This allows us to quickly identify which \"bucket\" of keys is out of sync.\n */\nexport class MerkleTree {\n private root: MerkleNode;\n private readonly depth: number;\n\n constructor(records: Map<string, LWWRecord<any>> = new Map(), depth: number = 3) {\n this.depth = depth;\n this.root = { hash: 0, children: {} };\n // Build initial tree\n for (const [key, record] of records) {\n this.update(key, record);\n }\n }\n\n /**\n * Incrementally updates the Merkle Tree with a single record.\n * @param key The key of the record\n * @param record The record (value + timestamp)\n */\n public update(key: string, record: LWWRecord<any>) {\n const itemHash = hashString(`${key}:${record.timestamp.millis}:${record.timestamp.counter}:${record.timestamp.nodeId}`);\n // We use the hash of the KEY for routing, so the record stays in the same bucket\n // regardless of timestamp changes.\n const pathHash = hashString(key).toString(16).padStart(8, '0'); \n \n this.updateNode(this.root, key, itemHash, pathHash, 0);\n }\n\n /**\n * Removes a key from the Merkle Tree.\n * Necessary for Garbage Collection of tombstones.\n */\n public remove(key: string) {\n const pathHash = hashString(key).toString(16).padStart(8, '0');\n this.removeNode(this.root, key, pathHash, 0);\n }\n\n private removeNode(node: MerkleNode, key: string, pathHash: string, level: number): number {\n // Leaf Node Logic\n if (level >= this.depth) {\n if (node.entries) {\n node.entries.delete(key);\n \n // Recalculate leaf hash\n let h = 0;\n for (const val of node.entries.values()) {\n h = (h + val) | 0;\n }\n node.hash = h >>> 0;\n }\n return node.hash;\n }\n\n // Intermediate Node Logic\n const bucketChar = pathHash[level];\n if (node.children && node.children[bucketChar]) {\n const childHash = this.removeNode(node.children[bucketChar], key, pathHash, level + 1);\n \n // Optimization: if child is empty/zero, we might want to remove it, but for now just recalc.\n }\n \n // Recalculate this node's hash from children\n let h = 0;\n if (node.children) {\n for (const child of Object.values(node.children)) {\n h = (h + child.hash) | 0;\n }\n }\n node.hash = h >>> 0;\n return node.hash;\n }\n\n private updateNode(node: MerkleNode, key: string, itemHash: number, pathHash: string, level: number): number {\n // Leaf Node Logic\n if (level >= this.depth) {\n if (!node.entries) node.entries = new Map();\n node.entries.set(key, itemHash);\n \n // Recalculate leaf hash (Sum of item hashes)\n let h = 0;\n for (const val of node.entries.values()) {\n h = (h + val) | 0;\n }\n node.hash = h >>> 0;\n return node.hash;\n }\n\n // Intermediate Node Logic\n const bucketChar = pathHash[level];\n if (!node.children) node.children = {};\n \n if (!node.children[bucketChar]) {\n node.children[bucketChar] = { hash: 0 };\n }\n \n this.updateNode(node.children[bucketChar], key, itemHash, pathHash, level + 1);\n \n // Recalculate this node's hash from children\n let h = 0;\n for (const child of Object.values(node.children)) {\n h = (h + child.hash) | 0;\n }\n node.hash = h >>> 0;\n return node.hash;\n }\n\n public getRootHash(): number {\n return this.root.hash;\n }\n\n public getNode(path: string): MerkleNode | undefined {\n let current = this.root;\n for (const char of path) {\n if (!current.children || !current.children[char]) {\n return undefined;\n }\n current = current.children[char];\n }\n return current;\n }\n\n /**\n * Returns the hashes of the children at the given path.\n * Used by the client/server to compare buckets.\n */\n public getBuckets(path: string): Record<string, number> {\n const node = this.getNode(path);\n if (!node || !node.children) return {};\n \n const result: Record<string, number> = {};\n for (const [key, child] of Object.entries(node.children)) {\n result[key] = child.hash;\n }\n return result;\n }\n\n /**\n * For a leaf node (bucket), returns the actual keys it contains.\n * Used to request specific keys when a bucket differs.\n */\n public getKeysInBucket(path: string): string[] {\n const node = this.getNode(path);\n if (!node || !node.entries) return [];\n return Array.from(node.entries.keys());\n }\n}\n","import { HLC, Timestamp } from './HLC';\nimport { MerkleTree } from './MerkleTree';\n\n/**\n * A record in the LWW-Map.\n * Can represent a value or a deletion (tombstone).\n */\nexport interface LWWRecord<V> {\n value: V | null;\n timestamp: Timestamp;\n ttlMs?: number;\n}\n\n/**\n * Last-Write-Wins Map Implementation.\n * This structure guarantees convergence by always keeping the entry with the highest timestamp.\n */\nexport class LWWMap<K, V> {\n private data: Map<K, LWWRecord<V>>;\n private readonly hlc: HLC;\n private listeners: Array<() => void> = [];\n private merkleTree: MerkleTree;\n\n constructor(hlc: HLC) {\n this.hlc = hlc;\n this.data = new Map();\n this.merkleTree = new MerkleTree();\n }\n\n public onChange(callback: () => void): () => void {\n this.listeners.push(callback);\n return () => {\n this.listeners = this.listeners.filter(cb => cb !== callback);\n };\n }\n\n private notify(): void {\n this.listeners.forEach(cb => cb());\n }\n\n public getMerkleTree(): MerkleTree {\n return this.merkleTree;\n }\n\n public get size(): number {\n return this.data.size;\n }\n\n /**\n * Sets a value for a key.\n * Generates a new timestamp using the local HLC.\n */\n public set(key: K, value: V, ttlMs?: number): LWWRecord<V> {\n const timestamp = this.hlc.now();\n const record: LWWRecord<V> = { value, timestamp };\n \n if (ttlMs !== undefined) {\n if (typeof ttlMs !== 'number' || ttlMs <= 0 || !Number.isFinite(ttlMs)) {\n // We could throw, but to be resilient we might just ignore invalid TTL or log warning.\n // Given this is core lib, throwing is safer to alert dev.\n throw new Error('TTL must be a positive finite number');\n }\n record.ttlMs = ttlMs;\n }\n \n // We assume K is string for MerkleTree compatibility in this system\n // If K is not string, we might need to stringify it.\n // The project seems to use string keys for maps.\n this.data.set(key, record);\n this.merkleTree.update(String(key), record);\n \n this.notify();\n return record;\n }\n\n /**\n * Retrieves the value for a key.\n * Returns undefined if key doesn't exist, is a tombstone, or is expired.\n */\n public get(key: K): V | undefined {\n const record = this.data.get(key);\n if (!record || record.value === null) {\n return undefined;\n }\n\n // Check for expiration\n if (record.ttlMs) {\n const now = Date.now();\n if (record.timestamp.millis + record.ttlMs < now) {\n return undefined;\n }\n }\n\n return record.value;\n }\n\n /**\n * Returns the full record (including timestamp).\n * Useful for synchronization.\n */\n public getRecord(key: K): LWWRecord<V> | undefined {\n return this.data.get(key);\n }\n\n /**\n * Removes a key (creates a tombstone).\n */\n public remove(key: K): LWWRecord<V> {\n const timestamp = this.hlc.now();\n const tombstone: LWWRecord<V> = { value: null, timestamp };\n \n this.data.set(key, tombstone);\n this.merkleTree.update(String(key), tombstone);\n \n this.notify();\n return tombstone;\n }\n\n /**\n * Merges a record from a remote source.\n * Returns true if the local state was updated.\n */\n public merge(key: K, remoteRecord: LWWRecord<V>): boolean {\n // Update our clock to ensure causality for future events\n this.hlc.update(remoteRecord.timestamp);\n\n const localRecord = this.data.get(key);\n\n // LWW Logic:\n // 1. If no local record, accept remote.\n // 2. If remote is strictly greater than local, accept remote.\n // 3. If equal, we can arbitrarily choose (e.g. by NodeID) to ensure convergence, \n // but HLC.compare handles nodeId tie-breaking already.\n \n if (!localRecord || HLC.compare(remoteRecord.timestamp, localRecord.timestamp) > 0) {\n this.data.set(key, remoteRecord);\n this.merkleTree.update(String(key), remoteRecord);\n \n this.notify();\n return true;\n }\n\n return false;\n }\n\n /**\n * Garbage Collection: Prunes tombstones older than the specified timestamp.\n * Only removes records that are tombstones (deleted) AND older than the threshold.\n * \n * @param olderThan The timestamp threshold. Tombstones older than this will be removed.\n * @returns The number of tombstones removed.\n */\n public prune(olderThan: Timestamp): K[] {\n const removedKeys: K[] = [];\n \n for (const [key, record] of this.data.entries()) {\n // Only prune tombstones (value === null)\n if (record.value === null) {\n // Check if timestamp is strictly older than the threshold\n // HLC.compare(a, b) returns < 0 if a < b\n if (HLC.compare(record.timestamp, olderThan) < 0) {\n this.data.delete(key);\n this.merkleTree.remove(String(key));\n removedKeys.push(key);\n }\n }\n }\n\n if (removedKeys.length > 0) {\n this.notify();\n }\n\n return removedKeys;\n }\n\n /**\n * Clears all data and tombstones.\n * Resets the MerkleTree.\n */\n public clear(): void {\n this.data.clear();\n this.merkleTree = new MerkleTree();\n this.notify();\n }\n\n /**\n * Returns an iterator over all non-deleted entries.\n */\n public entries(): IterableIterator<[K, V]> {\n const iterator = this.data.entries();\n const now = Date.now();\n \n return {\n [Symbol.iterator]() { return this; },\n next: () => {\n let result = iterator.next();\n while (!result.done) {\n const [key, record] = result.value;\n if (record.value !== null) {\n // Check TTL\n if (record.ttlMs && record.timestamp.millis + record.ttlMs < now) {\n result = iterator.next();\n continue;\n }\n return { value: [key, record.value], done: false };\n }\n result = iterator.next();\n }\n return { value: undefined, done: true };\n }\n };\n }\n\n /**\n * Returns all keys (including tombstones).\n */\n public allKeys(): IterableIterator<K> {\n return this.data.keys();\n }\n}\n","import { ORMapRecord } from './ORMap';\nimport { Timestamp } from './HLC';\nimport { hashString } from './utils/hash';\n\n/**\n * Convert Timestamp to deterministic string for hashing.\n * Format: millis:counter:nodeId\n */\nexport function timestampToString(ts: Timestamp): string {\n return `${ts.millis}:${ts.counter}:${ts.nodeId}`;\n}\n\n/**\n * Stringify a value in a deterministic way for hashing.\n */\nfunction stringifyValue(value: unknown): string {\n if (value === null || value === undefined) {\n return String(value);\n }\n if (typeof value === 'object') {\n // Sort object keys for deterministic JSON\n return JSON.stringify(value, Object.keys(value as Record<string, unknown>).sort());\n }\n return String(value);\n}\n\n/**\n * Hash an ORMap entry (key + all its records).\n * Must be deterministic regardless of insertion order.\n *\n * @param key The key of the entry\n * @param records Map of tag -> record for this key\n * @returns Hash as a number (FNV-1a hash)\n */\nexport function hashORMapEntry<V>(\n key: string,\n records: Map<string, ORMapRecord<V>>\n): number {\n // Sort records by tag for deterministic ordering\n const sortedTags = Array.from(records.keys()).sort();\n\n // Build deterministic string representation\n const parts: string[] = [`key:${key}`];\n\n for (const tag of sortedTags) {\n const record = records.get(tag)!;\n // Include tag, value (JSON-stringified), timestamp, and ttl if present\n const valuePart = stringifyValue(record.value);\n\n let recordStr = `${tag}:${valuePart}:${timestampToString(record.timestamp)}`;\n if (record.ttlMs !== undefined) {\n recordStr += `:ttl=${record.ttlMs}`;\n }\n parts.push(recordStr);\n }\n\n return hashString(parts.join('|'));\n}\n\n/**\n * Hash a single ORMapRecord for comparison.\n * Used when comparing individual records during merge.\n */\nexport function hashORMapRecord<V>(record: ORMapRecord<V>): number {\n const valuePart = stringifyValue(record.value);\n\n let str = `${record.tag}:${valuePart}:${timestampToString(record.timestamp)}`;\n if (record.ttlMs !== undefined) {\n str += `:ttl=${record.ttlMs}`;\n }\n\n return hashString(str);\n}\n\n/**\n * Compare two timestamps.\n * Returns:\n * < 0 if a < b\n * > 0 if a > b\n * = 0 if a == b\n */\nexport function compareTimestamps(a: Timestamp, b: Timestamp): number {\n if (a.millis !== b.millis) {\n return a.millis - b.millis;\n }\n if (a.counter !== b.counter) {\n return a.counter - b.counter;\n }\n return a.nodeId.localeCompare(b.nodeId);\n}\n","import { ORMap, ORMapRecord } from './ORMap';\nimport { hashString, combineHashes } from './utils/hash';\nimport { hashORMapEntry } from './ORMapMerkle';\n\n/**\n * Merkle Node for ORMap.\n * Uses a prefix trie structure based on key hash (similar to LWWMap MerkleTree).\n */\nexport interface ORMapMerkleNode {\n hash: number;\n children?: { [key: string]: ORMapMerkleNode }; // Keyed by bucket index (hex char)\n entries?: Map<string, number>; // Leaf node: Key -> ContentHash\n}\n\n/**\n * A Merkle Tree implementation specifically for ORMap synchronization.\n * Uses a Prefix Trie structure based on the hash of the Record Key.\n *\n * Structure:\n * - Level 0: Root\n * - Level 1..N: Buckets based on hex digits of Key Hash.\n *\n * Key difference from LWWMap MerkleTree:\n * - Each key can have multiple records (tags), so the entry hash includes all records for that key.\n */\nexport class ORMapMerkleTree {\n private root: ORMapMerkleNode;\n private readonly depth: number;\n\n constructor(depth: number = 3) {\n this.depth = depth;\n this.root = { hash: 0, children: {} };\n }\n\n /**\n * Update tree from ORMap data.\n * Rebuilds hashes for all entries in the map.\n */\n updateFromORMap<K, V>(map: ORMap<K, V>): void {\n // Clear and rebuild\n this.root = { hash: 0, children: {} };\n\n // Access internal items through available methods\n // We need to iterate over all keys and get their records\n const snapshot = map.getSnapshot();\n\n for (const [key, records] of snapshot.items) {\n if (records.size > 0) {\n const keyStr = String(key);\n const entryHash = hashORMapEntry(keyStr, records);\n const pathHash = hashString(keyStr).toString(16).padStart(8, '0');\n this.updateNode(this.root, keyStr, entryHash, pathHash, 0);\n }\n }\n }\n\n /**\n * Incrementally update a single key's hash.\n * Call this when records for a key change.\n */\n update<V>(key: string, records: Map<string, ORMapRecord<V>>): void {\n const pathHash = hashString(key).toString(16).padStart(8, '0');\n\n if (records.size === 0) {\n // Key has no records, remove from tree\n this.removeNode(this.root, key, pathHash, 0);\n } else {\n const entryHash = hashORMapEntry(key, records);\n this.updateNode(this.root, key, entryHash, pathHash, 0);\n }\n }\n\n /**\n * Remove a key from the tree.\n * Called when all records for a key are removed.\n */\n remove(key: string): void {\n const pathHash = hashString(key).toString(16).padStart(8, '0');\n this.removeNode(this.root, key, pathHash, 0);\n }\n\n private updateNode(\n node: ORMapMerkleNode,\n key: string,\n entryHash: number,\n pathHash: string,\n level: number\n ): number {\n // Leaf Node Logic\n if (level >= this.depth) {\n if (!node.entries) node.entries = new Map();\n node.entries.set(key, entryHash);\n\n // Recalculate leaf hash (Sum of entry hashes)\n let h = 0;\n for (const val of node.entries.values()) {\n h = (h + val) | 0;\n }\n node.hash = h >>> 0;\n return node.hash;\n }\n\n // Intermediate Node Logic\n const bucketChar = pathHash[level];\n if (!node.children) node.children = {};\n\n if (!node.children[bucketChar]) {\n node.children[bucketChar] = { hash: 0 };\n }\n\n this.updateNode(node.children[bucketChar], key, entryHash, pathHash, level + 1);\n\n // Recalculate this node's hash from children\n let h = 0;\n for (const child of Object.values(node.children)) {\n h = (h + child.hash) | 0;\n }\n node.hash = h >>> 0;\n return node.hash;\n }\n\n private removeNode(\n node: ORMapMerkleNode,\n key: string,\n pathHash: string,\n level: number\n ): number {\n // Leaf Node Logic\n if (level >= this.depth) {\n if (node.entries) {\n node.entries.delete(key);\n\n // Recalculate leaf hash\n let h = 0;\n for (const val of node.entries.values()) {\n h = (h + val) | 0;\n }\n node.hash = h >>> 0;\n }\n return node.hash;\n }\n\n // Intermediate Node Logic\n const bucketChar = pathHash[level];\n if (node.children && node.children[bucketChar]) {\n this.removeNode(node.children[bucketChar], key, pathHash, level + 1);\n }\n\n // Recalculate this node's hash from children\n let h = 0;\n if (node.children) {\n for (const child of Object.values(node.children)) {\n h = (h + child.hash) | 0;\n }\n }\n node.hash = h >>> 0;\n return node.hash;\n }\n\n /**\n * Get the root hash for quick comparison.\n */\n getRootHash(): number {\n return this.root.hash;\n }\n\n /**\n * Get node at a specific path.\n */\n getNode(path: string): ORMapMerkleNode | undefined {\n let current = this.root;\n for (const char of path) {\n if (!current.children || !current.children[char]) {\n return undefined;\n }\n current = current.children[char];\n }\n return current;\n }\n\n /**\n * Returns the hashes of the children at the given path.\n * Used by the client/server to compare buckets.\n */\n getBuckets(path: string): Record<string, number> {\n const node = this.getNode(path);\n if (!node || !node.children) return {};\n\n const result: Record<string, number> = {};\n for (const [key, child] of Object.entries(node.children)) {\n result[key] = child.hash;\n }\n return result;\n }\n\n /**\n * For a leaf node (bucket), returns the actual keys it contains.\n * Used to request specific keys when a bucket differs.\n */\n getKeysInBucket(path: string): string[] {\n const node = this.getNode(path);\n if (!node || !node.entries) return [];\n return Array.from(node.entries.keys());\n }\n\n /**\n * Find keys that differ between this tree and bucket info from remote.\n * Returns keys that:\n * - Exist locally but have different hash on remote\n * - Exist on remote but not locally\n * - Exist locally but not on remote\n */\n findDiffKeys(path: string, remoteEntries: Map<string, number>): Set<string> {\n const diffKeys = new Set<string>();\n const node = this.getNode(path);\n const localEntries = node?.entries || new Map();\n\n // Keys in local but not remote, or different hash\n for (const [key, hash] of localEntries) {\n const remoteHash = remoteEntries.get(key);\n if (remoteHash === undefined || remoteHash !== hash) {\n diffKeys.add(key);\n }\n }\n\n // Keys in remote but not local\n for (const key of remoteEntries.keys()) {\n if (!localEntries.has(key)) {\n diffKeys.add(key);\n }\n }\n\n return diffKeys;\n }\n\n /**\n * Get all entry hashes at a leaf path.\n * Used when sending bucket details to remote.\n */\n getEntryHashes(path: string): Map<string, number> {\n const node = this.getNode(path);\n return node?.entries || new Map();\n }\n\n /**\n * Check if a path leads to a leaf node.\n */\n isLeaf(path: string): boolean {\n const node = this.getNode(path);\n return node !== undefined && node.entries !== undefined && node.entries.size > 0;\n }\n}\n","import { HLC, Timestamp } from './HLC';\nimport { ORMapMerkleTree } from './ORMapMerkleTree';\nimport { compareTimestamps } from './ORMapMerkle';\n\n/**\n * A record in the OR-Map (Observed-Remove Map).\n * Represents a single value instance with a unique tag.\n */\nexport interface ORMapRecord<V> {\n value: V;\n timestamp: Timestamp;\n tag: string; // Unique identifier (UUID + Timestamp)\n ttlMs?: number;\n}\n\n/**\n * Result of merging records for a key.\n */\nexport interface MergeKeyResult {\n added: number;\n updated: number;\n}\n\n/**\n * Snapshot of ORMap internal state for Merkle Tree synchronization.\n */\nexport interface ORMapSnapshot<K, V> {\n items: Map<K, Map<string, ORMapRecord<V>>>;\n tombstones: Set<string>;\n}\n\n/**\n * OR-Map (Observed-Remove Map) Implementation.\n * \n * Acts as a Multimap where each Key holds a Set of Values.\n * Supports concurrent additions to the same key without data loss.\n * \n * Logic:\n * - Add(K, V): Generates a unique tag. Stores (V, tag) under K.\n * - Remove(K, V): Finds all *currently observed* tags for V under K, and moves them to a Remove Set (Tombstones).\n * - Merge: Union of items minus Union of tombstones.\n */\nexport class ORMap<K, V> {\n // Key -> Map<Tag, Record>\n // Stores active records.\n private items: Map<K, Map<string, ORMapRecord<V>>>;\n\n // Set of removed tags (Tombstones).\n private tombstones: Set<string>;\n\n // Set of expired tags (Local only cache for fast filtering)\n // Note: We don't persist this directly, but rely on filtering.\n // For now, we will just filter on get()\n\n private readonly hlc: HLC;\n\n // Merkle Tree for efficient sync\n private merkleTree: ORMapMerkleTree;\n\n constructor(hlc: HLC) {\n this.hlc = hlc;\n this.items = new Map();\n this.tombstones = new Set();\n this.merkleTree = new ORMapMerkleTree();\n }\n\n private listeners: Array<() => void> = [];\n\n public onChange(callback: () => void): () => void {\n this.listeners.push(callback);\n return () => {\n this.listeners = this.listeners.filter(cb => cb !== callback);\n };\n }\n\n private notify(): void {\n this.listeners.forEach(cb => cb());\n }\n\n public get size(): number {\n return this.items.size;\n }\n\n public get totalRecords(): number {\n let count = 0;\n for (const keyMap of this.items.values()) {\n count += keyMap.size;\n }\n return count;\n }\n\n /**\n * Adds a value to the set associated with the key.\n * Generates a unique tag for this specific addition.\n */\n public add(key: K, value: V, ttlMs?: number): ORMapRecord<V> {\n const timestamp = this.hlc.now();\n // Tag must be unique globally. HLC.toString() provides unique string per node+time.\n const tag = HLC.toString(timestamp);\n\n const record: ORMapRecord<V> = {\n value,\n timestamp,\n tag\n };\n\n if (ttlMs !== undefined) {\n if (typeof ttlMs !== 'number' || ttlMs <= 0 || !Number.isFinite(ttlMs)) {\n throw new Error('TTL must be a positive finite number');\n }\n record.ttlMs = ttlMs;\n }\n\n let keyMap = this.items.get(key);\n if (!keyMap) {\n keyMap = new Map();\n this.items.set(key, keyMap);\n }\n\n keyMap.set(tag, record);\n this.updateMerkleTree(key);\n this.notify();\n return record;\n }\n\n /**\n * Removes a specific value from the set associated with the key.\n * Marks all *currently observed* instances of this value as removed (tombstones).\n * Returns the list of tags that were removed (useful for sync).\n */\n public remove(key: K, value: V): string[] {\n const keyMap = this.items.get(key);\n if (!keyMap) return [];\n\n // Find all tags for this value\n const tagsToRemove: string[] = [];\n\n for (const [tag, record] of keyMap.entries()) {\n // Using strict equality. For objects, this requires the exact instance.\n if (record.value === value) {\n tagsToRemove.push(tag);\n }\n }\n\n for (const tag of tagsToRemove) {\n this.tombstones.add(tag);\n keyMap.delete(tag);\n }\n\n if (keyMap.size === 0) {\n this.items.delete(key);\n }\n\n this.updateMerkleTree(key);\n this.notify();\n return tagsToRemove;\n }\n\n /**\n * Clears all data and tombstones.\n */\n public clear(): void {\n this.items.clear();\n this.tombstones.clear();\n this.merkleTree = new ORMapMerkleTree();\n this.notify();\n }\n\n /**\n * Returns all active values for a key.\n * Filters out expired records.\n */\n public get(key: K): V[] {\n const keyMap = this.items.get(key);\n if (!keyMap) return [];\n\n const values: V[] = [];\n const now = Date.now();\n\n for (const [tag, record] of keyMap.entries()) {\n if (!this.tombstones.has(tag)) {\n // Check expiration\n if (record.ttlMs && record.timestamp.millis + record.ttlMs < now) {\n continue;\n }\n values.push(record.value);\n }\n }\n return values;\n }\n\n /**\n * Returns all active records for a key.\n * Useful for persistence and sync.\n * Filters out expired records.\n */\n public getRecords(key: K): ORMapRecord<V>[] {\n const keyMap = this.items.get(key);\n if (!keyMap) return [];\n\n const records: ORMapRecord<V>[] = [];\n const now = Date.now();\n\n for (const [tag, record] of keyMap.entries()) {\n if (!this.tombstones.has(tag)) {\n // Check expiration\n if (record.ttlMs && record.timestamp.millis + record.ttlMs < now) {\n continue;\n }\n records.push(record);\n }\n }\n return records;\n }\n\n /**\n * Returns all tombstone tags.\n */\n public getTombstones(): string[] {\n return Array.from(this.tombstones);\n }\n\n /**\n * Applies a record from a remote source (Sync).\n * Returns true if the record was applied (not tombstoned).\n */\n public apply(key: K, record: ORMapRecord<V>): boolean {\n if (this.tombstones.has(record.tag)) return false;\n\n let keyMap = this.items.get(key);\n if (!keyMap) {\n keyMap = new Map();\n this.items.set(key, keyMap);\n }\n keyMap.set(record.tag, record);\n this.hlc.update(record.timestamp);\n this.updateMerkleTree(key);\n this.notify();\n return true;\n }\n\n /**\n * Applies a tombstone (deletion) from a remote source.\n */\n public applyTombstone(tag: string): void {\n this.tombstones.add(tag);\n // Cleanup active items if present\n for (const [key, keyMap] of this.items) {\n if (keyMap.has(tag)) {\n keyMap.delete(tag);\n if (keyMap.size === 0) this.items.delete(key);\n this.updateMerkleTree(key);\n // We found it, so we can stop searching (tag is unique globally)\n break;\n }\n }\n this.notify();\n }\n\n /**\n * Merges state from another ORMap.\n * - Adds all new tombstones from 'other'.\n * - Adds all new items from 'other' that are not in tombstones.\n * - Updates HLC with observed timestamps.\n */\n public merge(other: ORMap<K, V>): void {\n const changedKeys = new Set<K>();\n\n // 1. Merge tombstones\n for (const tag of other.tombstones) {\n this.tombstones.add(tag);\n }\n\n // 2. Merge items\n for (const [key, otherKeyMap] of other.items) {\n let localKeyMap = this.items.get(key);\n if (!localKeyMap) {\n localKeyMap = new Map();\n this.items.set(key, localKeyMap);\n }\n\n for (const [tag, record] of otherKeyMap) {\n // Only accept if not deleted\n if (!this.tombstones.has(tag)) {\n if (!localKeyMap.has(tag)) {\n localKeyMap.set(tag, record);\n changedKeys.add(key);\n }\n // Always update causality\n this.hlc.update(record.timestamp);\n }\n }\n }\n\n // 3. Cleanup: Remove any local items that are now in the merged tombstones\n for (const [key, localKeyMap] of this.items) {\n for (const tag of localKeyMap.keys()) {\n if (this.tombstones.has(tag)) {\n localKeyMap.delete(tag);\n changedKeys.add(key);\n }\n }\n if (localKeyMap.size === 0) {\n this.items.delete(key);\n }\n }\n\n // Update Merkle Tree for changed keys\n for (const key of changedKeys) {\n this.updateMerkleTree(key);\n }\n\n this.notify();\n }\n\n /**\n * Garbage Collection: Prunes tombstones older than the specified timestamp.\n */\n public prune(olderThan: Timestamp): string[] {\n const removedTags: string[] = [];\n\n for (const tag of this.tombstones) {\n try {\n const timestamp = HLC.parse(tag);\n if (HLC.compare(timestamp, olderThan) < 0) {\n this.tombstones.delete(tag);\n removedTags.push(tag);\n }\n } catch (e) {\n // Ignore invalid tags\n }\n }\n\n return removedTags;\n }\n\n // ============ Merkle Sync Methods ============\n\n /**\n * Get the Merkle Tree for this ORMap.\n * Used for efficient synchronization.\n */\n public getMerkleTree(): ORMapMerkleTree {\n return this.merkleTree;\n }\n\n /**\n * Get a snapshot of internal state for Merkle Tree synchronization.\n * Returns references to internal structures - do not modify!\n */\n public getSnapshot(): ORMapSnapshot<K, V> {\n return {\n items: this.items,\n tombstones: this.tombstones\n };\n }\n\n /**\n * Get all keys in this ORMap.\n */\n public allKeys(): K[] {\n return Array.from(this.items.keys());\n }\n\n /**\n * Get the internal records map for a key.\n * Returns Map<tag, record> or undefined if key doesn't exist.\n * Used for Merkle sync.\n */\n public getRecordsMap(key: K): Map<string, ORMapRecord<V>> | undefined {\n return this.items.get(key);\n }\n\n /**\n * Merge remote records for a specific key into local state.\n * Implements Observed-Remove CRDT semantics.\n * Used during Merkle Tree synchronization.\n *\n * @param key The key to merge\n * @param remoteRecords Array of records from remote\n * @param remoteTombstones Array of tombstone tags from remote\n * @returns Result with count of added and updated records\n */\n public mergeKey(\n key: K,\n remoteRecords: ORMapRecord<V>[],\n remoteTombstones: string[] = []\n ): MergeKeyResult {\n let added = 0;\n let updated = 0;\n\n // First apply remote tombstones\n for (const tag of remoteTombstones) {\n if (!this.tombstones.has(tag)) {\n this.tombstones.add(tag);\n }\n }\n\n // Get or create local key map\n let localKeyMap = this.items.get(key);\n if (!localKeyMap) {\n localKeyMap = new Map();\n this.items.set(key, localKeyMap);\n }\n\n // Remove any local records that are now tombstoned\n for (const tag of localKeyMap.keys()) {\n if (this.tombstones.has(tag)) {\n localKeyMap.delete(tag);\n }\n }\n\n // Merge remote records\n for (const remoteRecord of remoteRecords) {\n // Skip if tombstoned\n if (this.tombstones.has(remoteRecord.tag)) {\n continue;\n }\n\n const localRecord = localKeyMap.get(remoteRecord.tag);\n\n if (!localRecord) {\n // New record - add it\n localKeyMap.set(remoteRecord.tag, remoteRecord);\n added++;\n } else if (compareTimestamps(remoteRecord.timestamp, localRecord.timestamp) > 0) {\n // Remote is newer - update\n localKeyMap.set(remoteRecord.tag, remoteRecord);\n updated++;\n }\n // Else: local is newer or equal, keep local\n\n // Always update causality\n this.hlc.update(remoteRecord.timestamp);\n }\n\n // Cleanup empty key map\n if (localKeyMap.size === 0) {\n this.items.delete(key);\n }\n\n // Update Merkle Tree\n this.updateMerkleTree(key);\n\n if (added > 0 || updated > 0) {\n this.notify();\n }\n\n return { added, updated };\n }\n\n /**\n * Check if a tag is tombstoned.\n */\n public isTombstoned(tag: string): boolean {\n return this.tombstones.has(tag);\n }\n\n /**\n * Update the Merkle Tree for a specific key.\n * Called internally after any modification.\n */\n private updateMerkleTree(key: K): void {\n const keyStr = String(key);\n const keyMap = this.items.get(key);\n\n if (!keyMap || keyMap.size === 0) {\n this.merkleTree.remove(keyStr);\n } else {\n this.merkleTree.update(keyStr, keyMap);\n }\n }\n}\n","import { pack, unpack } from 'msgpackr';\n\n/**\n * Serializes a JavaScript object to MessagePack binary format.\n * Uses msgpackr for 2-5x faster serialization compared to @msgpack/msgpack.\n * @param data The data to serialize.\n * @returns A Uint8Array containing the serialized data.\n */\nexport function serialize(data: unknown): Uint8Array {\n return pack(data);\n}\n\n/**\n * Deserializes MessagePack binary data to a JavaScript object.\n * Uses msgpackr for 2-5x faster deserialization compared to @msgpack/msgpack.\n * @param data The binary data to deserialize (Uint8Array or ArrayBuffer).\n * @returns The deserialized object.\n */\nexport function deserialize<T = unknown>(data: Uint8Array | ArrayBuffer): T {\n // msgpackr unpack accepts Uint8Array, Buffer, ArrayBuffer\n const buffer = data instanceof ArrayBuffer ? new Uint8Array(data) : data;\n return unpack(buffer) as T;\n}\n\n","import { serialize, deserialize } from './serializer';\n\n/**\n * State of a PN Counter CRDT.\n * Tracks positive and negative increments per node for convergence.\n */\nexport interface PNCounterState {\n /** Positive increments per node */\n positive: Map<string, number>;\n /** Negative increments per node */\n negative: Map<string, number>;\n}\n\n/**\n * Serializable form of PNCounterState for network/storage.\n */\nexport interface PNCounterStateObject {\n /** Positive increments per node as object */\n p: Record<string, number>;\n /** Negative increments per node as object */\n n: Record<string, number>;\n}\n\n/**\n * Configuration for creating a PN Counter.\n */\nexport interface PNCounterConfig {\n /** Unique node identifier for this counter instance */\n nodeId: string;\n /** Initial state to restore from */\n initialState?: PNCounterState;\n}\n\n/**\n * Interface for PN Counter CRDT.\n */\nexport interface PNCounter {\n /** Get current value */\n get(): number;\n\n /** Increment by 1, return new value */\n increment(): number;\n\n /** Decrement by 1, return new value */\n decrement(): number;\n\n /** Add delta (positive or negative), return new value */\n addAndGet(delta: number): number;\n\n /** Get state for sync */\n getState(): PNCounterState;\n\n /** Merge remote state */\n merge(remote: PNCounterState): void;\n\n /** Subscribe to value changes */\n subscribe(listener: (value: number) => void): () => void;\n}\n\n/**\n * Positive-Negative Counter CRDT implementation.\n *\n * A PN Counter is a CRDT that supports increment and decrement operations\n * on any node, works offline, and guarantees convergence without coordination.\n *\n * How it works:\n * - Tracks positive increments per node in a G-Counter\n * - Tracks negative increments per node in another G-Counter\n * - Value = sum(positive) - sum(negative)\n * - Merge takes max for each node in both counters\n *\n * @example\n * ```typescript\n * const counter = new PNCounterImpl({ nodeId: 'node-1' });\n * counter.increment(); // 1\n * counter.increment(); // 2\n * counter.decrement(); // 1\n * counter.addAndGet(5); // 6\n * ```\n */\nexport class PNCounterImpl implements PNCounter {\n private readonly nodeId: string;\n private state: PNCounterState;\n private listeners: Set<(value: number) => void> = new Set();\n\n constructor(config: PNCounterConfig) {\n this.nodeId = config.nodeId;\n this.state = config.initialState ?? {\n positive: new Map(),\n negative: new Map(),\n };\n }\n\n /**\n * Get the current counter value.\n * Value = sum(positive) - sum(negative)\n */\n get(): number {\n let sum = 0;\n for (const v of this.state.positive.values()) sum += v;\n for (const v of this.state.negative.values()) sum -= v;\n return sum;\n }\n\n /**\n * Increment by 1 and return the new value.\n */\n increment(): number {\n return this.addAndGet(1);\n }\n\n /**\n * Decrement by 1 and return the new value.\n */\n decrement(): number {\n return this.addAndGet(-1);\n }\n\n /**\n * Add a delta (positive or negative) and return the new value.\n * @param delta The amount to add (can be negative)\n */\n addAndGet(delta: number): number {\n if (delta === 0) return this.get();\n\n if (delta > 0) {\n const current = this.state.positive.get(this.nodeId) ?? 0;\n this.state.positive.set(this.nodeId, current + delta);\n } else {\n const current = this.state.negative.get(this.nodeId) ?? 0;\n this.state.negative.set(this.nodeId, current + Math.abs(delta));\n }\n\n const newValue = this.get();\n this.notifyListeners(newValue);\n return newValue;\n }\n\n /**\n * Get a copy of the current state for synchronization.\n */\n getState(): PNCounterState {\n return {\n positive: new Map(this.state.positive),\n negative: new Map(this.state.negative),\n };\n }\n\n /**\n * Merge remote state into this counter.\n * Takes the maximum value for each node in both positive and negative counters.\n * This operation is commutative, associative, and idempotent (CRDT properties).\n *\n * @param remote The remote state to merge\n */\n merge(remote: PNCounterState): void {\n let changed = false;\n\n // Merge positive: take max for each node\n for (const [nodeId, value] of remote.positive) {\n const current = this.state.positive.get(nodeId) ?? 0;\n if (value > current) {\n this.state.positive.set(nodeId, value);\n changed = true;\n }\n }\n\n // Merge negative: take max for each node\n for (const [nodeId, value] of remote.negative) {\n const current = this.state.negative.get(nodeId) ?? 0;\n if (value > current) {\n this.state.negative.set(nodeId, value);\n changed = true;\n }\n }\n\n if (changed) {\n this.notifyListeners(this.get());\n }\n }\n\n /**\n * Subscribe to value changes.\n * The listener is immediately called with the current value.\n *\n * @param listener Callback function receiving the new value\n * @returns Unsubscribe function\n */\n subscribe(listener: (value: number) => void): () => void {\n this.listeners.add(listener);\n // Immediately notify with current value\n listener(this.get());\n return () => this.listeners.delete(listener);\n }\n\n private notifyListeners(value: number): void {\n for (const listener of this.listeners) {\n try {\n listener(value);\n } catch (e) {\n // Silently catch listener errors to prevent breaking other listeners\n }\n }\n }\n\n /**\n * Get the node ID of this counter instance.\n */\n getNodeId(): string {\n return this.nodeId;\n }\n\n // ============================================\n // Serialization\n // ============================================\n\n /**\n * Serialize state to binary format (msgpack).\n */\n static serialize(state: PNCounterState): Uint8Array {\n const obj: PNCounterStateObject = {\n p: Object.fromEntries(state.positive),\n n: Object.fromEntries(state.negative),\n };\n return serialize(obj);\n }\n\n /**\n * Deserialize binary data to state.\n */\n static deserialize(data: Uint8Array): PNCounterState {\n const obj = deserialize<PNCounterStateObject>(data);\n return {\n positive: new Map(Object.entries(obj.p)),\n negative: new Map(Object.entries(obj.n)),\n };\n }\n\n /**\n * Convert state to plain object (for JSON/network).\n */\n static stateToObject(state: PNCounterState): PNCounterStateObject {\n return {\n p: Object.fromEntries(state.positive),\n n: Object.fromEntries(state.negative),\n };\n }\n\n /**\n * Convert plain object to state.\n */\n static objectToState(obj: PNCounterStateObject): PNCounterState {\n return {\n positive: new Map(Object.entries(obj.p)),\n negative: new Map(Object.entries(obj.n)),\n };\n }\n}\n","/**\n * Fixed-size circular buffer with sequence numbers.\n * Older entries are overwritten when capacity is reached.\n *\n * @template T - Type of items stored in the buffer\n */\nexport class Ringbuffer<T> {\n private buffer: (T | undefined)[];\n private readonly _capacity: number;\n private headSequence: bigint = 0n; // Oldest available sequence\n private tailSequence: bigint = 0n; // Next sequence to write\n\n constructor(capacity: number) {\n if (capacity < 1) {\n throw new Error('Capacity must be >= 1');\n }\n this._capacity = capacity;\n this.buffer = new Array(capacity);\n }\n\n /**\n * Add item to buffer, returns sequence number.\n */\n add(item: T): bigint {\n const sequence = this.tailSequence;\n const index = Number(sequence % BigInt(this._capacity));\n\n this.buffer[index] = item;\n this.tailSequence++;\n\n // Advance head if we overwrote oldest\n if (this.tailSequence - this.headSequence > this._capacity) {\n this.headSequence = this.tailSequence - BigInt(this._capacity);\n }\n\n return sequence;\n }\n\n /**\n * Read item at sequence.\n * Returns undefined if sequence is out of range.\n */\n read(sequence: bigint): T | undefined {\n if (sequence < this.headSequence || sequence >= this.tailSequence) {\n return undefined;\n }\n const index = Number(sequence % BigInt(this._capacity));\n return this.buffer[index];\n }\n\n /**\n * Read range of items (inclusive).\n * Automatically clamps to available range.\n */\n readRange(startSeq: bigint, endSeq: bigint): T[] {\n const items: T[] = [];\n const actualStart = startSeq < this.headSequence ? this.headSequence : startSeq;\n const actualEnd = endSeq >= this.tailSequence ? this.tailSequence - 1n : endSeq;\n\n for (let seq = actualStart; seq <= actualEnd; seq++) {\n const item = this.read(seq);\n if (item !== undefined) {\n items.push(item);\n }\n }\n\n return items;\n }\n\n /**\n * Read from sequence with limit.\n */\n readFrom(startSeq: bigint, limit: number = 100): T[] {\n const endSeq = startSeq + BigInt(limit) - 1n;\n return this.readRange(startSeq, endSeq);\n }\n\n /**\n * Get the oldest available sequence number.\n */\n getHeadSequence(): bigint {\n return this.headSequence;\n }\n\n /**\n * Get the next sequence number to be written.\n */\n getTailSequence(): bigint {\n return this.tailSequence;\n }\n\n /**\n * Get the number of items currently in the buffer.\n */\n size(): number {\n return Number(this.tailSequence - this.headSequence);\n }\n\n /**\n * Get the maximum capacity of the buffer.\n */\n getCapacity(): number {\n return this._capacity;\n }\n\n /**\n * Clear all items from the buffer.\n */\n clear(): void {\n this.buffer = new Array(this._capacity);\n this.headSequence = 0n;\n this.tailSequence = 0n;\n }\n\n /**\n * Check if a sequence is available in the buffer.\n */\n isAvailable(sequence: bigint): boolean {\n return sequence >= this.headSequence && sequence < this.tailSequence;\n }\n\n /**\n * Get remaining capacity before oldest entries are overwritten.\n */\n remainingCapacity(): number {\n return this._capacity - this.size();\n }\n}\n","import { Ringbuffer } from './Ringbuffer';\nimport type { Timestamp } from './HLC';\n\n/**\n * Type of journal event.\n */\nexport type JournalEventType = 'PUT' | 'UPDATE' | 'DELETE';\n\n/**\n * Single event in the journal.\n */\nexport interface JournalEvent<V = unknown> {\n /** Monotonically increasing sequence number */\n sequence: bigint;\n\n /** Event type */\n type: JournalEventType;\n\n /** Map name */\n mapName: string;\n\n /** Entry key */\n key: string;\n\n /** New value (undefined for DELETE) */\n value?: V;\n\n /** Previous value (for UPDATE and DELETE) */\n previousValue?: V;\n\n /** HLC timestamp */\n timestamp: Timestamp;\n\n /** Node that made the change */\n nodeId: string;\n\n /** Optional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Input for appending events (without sequence).\n */\nexport type JournalEventInput<V = unknown> = Omit<JournalEvent<V>, 'sequence'>;\n\n/**\n * Event Journal configuration.\n */\nexport interface EventJournalConfig {\n /** Maximum number of events to keep in memory */\n capacity: number;\n\n /** Time-to-live for events (ms), 0 = infinite */\n ttlMs: number;\n\n /** Persist to storage adapter */\n persistent: boolean;\n\n /** Maps to include (empty = all) */\n includeMaps?: string[];\n\n /** Maps to exclude */\n excludeMaps?: string[];\n}\n\n/**\n * Default configuration for Event Journal.\n */\nexport const DEFAULT_EVENT_JOURNAL_CONFIG: EventJournalConfig = {\n capacity: 10000,\n ttlMs: 0, // Infinite\n persistent: true,\n includeMaps: [],\n excludeMaps: [],\n};\n\n/**\n * Event Journal interface.\n */\nexport interface EventJournal {\n /** Append event to journal */\n append<V>(event: JournalEventInput<V>): JournalEvent<V>;\n\n /** Read events from sequence (inclusive) */\n readFrom(sequence: bigint, limit?: number): JournalEvent[];\n\n /** Read events in range */\n readRange(startSeq: bigint, endSeq: bigint): JournalEvent[];\n\n /** Get latest sequence number */\n getLatestSequence(): bigint;\n\n /** Get oldest sequence number (after compaction) */\n getOldestSequence(): bigint;\n\n /** Subscribe to new events */\n subscribe(\n listener: (event: JournalEvent) => void,\n fromSequence?: bigint\n ): () => void;\n\n /** Get capacity info */\n getCapacity(): { used: number; total: number };\n\n /** Force compaction */\n compact(): Promise<void>;\n\n /** Dispose resources */\n dispose(): void;\n}\n\n/**\n * Journal event listener type.\n */\nexport type JournalEventListener = (event: JournalEvent) => void;\n\n/**\n * Event Journal implementation using Ringbuffer.\n * Records all Map changes as an append-only log.\n */\nexport class EventJournalImpl implements EventJournal {\n private readonly config: EventJournalConfig;\n private readonly buffer: Ringbuffer<JournalEvent>;\n private readonly listeners: Set<JournalEventListener> = new Set();\n private ttlTimer?: ReturnType<typeof setInterval>;\n\n constructor(config: Partial<EventJournalConfig> = {}) {\n this.config = { ...DEFAULT_EVENT_JOURNAL_CONFIG, ...config };\n this.buffer = new Ringbuffer(this.config.capacity);\n\n if (this.config.ttlMs > 0) {\n this.startTTLCleanup();\n }\n }\n\n /**\n * Append event to journal.\n * Returns the event with assigned sequence number.\n * Returns event with sequence -1n if map is filtered out.\n */\n append<V>(eventData: JournalEventInput<V>): JournalEvent<V> {\n // Check map filters\n if (!this.shouldCapture(eventData.mapName)) {\n return { ...eventData, sequence: -1n } as JournalEvent<V>;\n }\n\n const event: JournalEvent<V> = {\n ...eventData,\n sequence: 0n, // Will be set by buffer\n };\n\n const sequence = this.buffer.add(event);\n event.sequence = sequence;\n\n // Notify listeners\n for (const listener of this.listeners) {\n try {\n listener(event);\n } catch (e) {\n console.error('EventJournal listener error:', e);\n }\n }\n\n return event;\n }\n\n /**\n * Read events from sequence with optional limit.\n */\n readFrom(sequence: bigint, limit: number = 100): JournalEvent[] {\n return this.buffer.readFrom(sequence, limit);\n }\n\n /**\n * Read events in range (inclusive).\n */\n readRange(startSeq: bigint, endSeq: bigint): JournalEvent[] {\n return this.buffer.readRange(startSeq, endSeq);\n }\n\n /**\n * Get latest sequence number.\n * Returns 0n if no events have been added.\n */\n getLatestSequence(): bigint {\n const tail = this.buffer.getTailSequence();\n return tail > 0n ? tail - 1n : 0n;\n }\n\n /**\n * Get oldest available sequence number.\n */\n getOldestSequence(): bigint {\n return this.buffer.getHeadSequence();\n }\n\n /**\n * Subscribe to new events.\n * Optionally replay events from a specific sequence.\n *\n * @param listener Callback for each event\n * @param fromSequence Optional sequence to start replay from\n * @returns Unsubscribe function\n */\n subscribe(\n listener: JournalEventListener,\n fromSequence?: bigint\n ): () => void {\n // Replay events if fromSequence is specified\n if (fromSequence !== undefined) {\n const events = this.readFrom(fromSequence, this.config.capacity);\n for (const event of events) {\n try {\n listener(event);\n } catch (e) {\n console.error('EventJournal replay error:', e);\n }\n }\n }\n\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /**\n * Get capacity information.\n */\n getCapacity(): { used: number; total: number } {\n return {\n used: this.buffer.size(),\n total: this.buffer.getCapacity(),\n };\n }\n\n /**\n * Force compaction.\n * Note: The ringbuffer handles eviction automatically.\n * This method is provided for explicit cleanup of old events.\n */\n async compact(): Promise<void> {\n // The ringbuffer automatically evicts old entries when full.\n // TTL-based cleanup is handled by the timer.\n // This method can be extended for additional cleanup logic.\n }\n\n /**\n * Check if a map should be captured.\n */\n private shouldCapture(mapName: string): boolean {\n const { includeMaps, excludeMaps } = this.config;\n\n if (excludeMaps && excludeMaps.includes(mapName)) {\n return false;\n }\n\n if (includeMaps && includeMaps.length > 0) {\n return includeMaps.includes(mapName);\n }\n\n return true;\n }\n\n /**\n * Start TTL cleanup timer.\n */\n private startTTLCleanup(): void {\n const interval = Math.min(this.config.ttlMs, 60000); // At least every minute\n this.ttlTimer = setInterval(() => {\n this.compact();\n }, interval);\n }\n\n /**\n * Dispose resources.\n */\n dispose(): void {\n if (this.ttlTimer) {\n clearInterval(this.ttlTimer);\n this.ttlTimer = undefined;\n }\n this.listeners.clear();\n }\n\n /**\n * Get all current listeners count (for testing).\n */\n getListenerCount(): number {\n return this.listeners.size;\n }\n\n /**\n * Get configuration (for testing).\n */\n getConfig(): EventJournalConfig {\n return { ...this.config };\n }\n}\n","import { z } from 'zod';\n\n// --- Entry Processor Types ---\n\n/**\n * Function executed on the server against a single entry.\n * Receives the current value (or undefined if key doesn't exist).\n * Returns the new value (or undefined to delete the entry).\n */\nexport type EntryProcessorFn<V, R = V> = (\n value: V | undefined,\n key: string,\n args?: unknown,\n) => { value: V | undefined; result?: R };\n\n/**\n * Zod schema for entry processor definition validation.\n */\nexport const EntryProcessorDefSchema = z.object({\n name: z.string().min(1).max(100),\n code: z.string().min(1).max(10000), // Max 10KB code\n args: z.unknown().optional(),\n});\n\n/**\n * Serializable entry processor definition.\n * Code is sent as string and executed in isolated sandbox.\n */\nexport interface EntryProcessorDef<V = unknown, R = V> {\n /** Unique processor name for caching compiled code */\n name: string;\n\n /** JavaScript function body as string */\n code: string;\n\n /** Optional arguments passed to the processor */\n args?: unknown;\n\n /** Type markers (not serialized) */\n __valueType?: V;\n __resultType?: R;\n}\n\n/**\n * Result of entry processor execution.\n */\nexport interface EntryProcessorResult<R = unknown> {\n /** Whether the operation succeeded */\n success: boolean;\n\n /** Custom result returned by processor */\n result?: R;\n\n /** Error message if failed */\n error?: string;\n\n /** New value after processing (for client cache update) */\n newValue?: unknown;\n}\n\n// --- Security: Forbidden Patterns ---\n\n/**\n * Patterns that are denied in processor code for security reasons.\n */\nexport const FORBIDDEN_PATTERNS = [\n /\\beval\\b/,\n /\\bFunction\\b/,\n /\\bprocess\\b/,\n /\\bglobal\\b/,\n /\\brequire\\b/,\n /\\bimport\\b/,\n /\\bfetch\\b/,\n /\\bXMLHttpRequest\\b/,\n /\\bsetTimeout\\b/,\n /\\bsetInterval\\b/,\n /\\bsetImmediate\\b/,\n];\n\n/**\n * Validates processor code against forbidden patterns.\n * Returns true if code is safe, false otherwise.\n */\nexport function validateProcessorCode(code: string): {\n valid: boolean;\n error?: string;\n} {\n for (const pattern of FORBIDDEN_PATTERNS) {\n if (pattern.test(code)) {\n return {\n valid: false,\n error: `Forbidden pattern detected: ${pattern.source}`,\n };\n }\n }\n return { valid: true };\n}\n\n// --- Built-in Processors ---\n\n/**\n * Built-in processors for common operations.\n * These are type-safe and pre-validated.\n */\nexport const BuiltInProcessors = {\n /**\n * Increment numeric value by delta.\n * If value doesn't exist, starts from 0.\n */\n INCREMENT: (delta: number = 1): EntryProcessorDef<number, number> => ({\n name: 'builtin:increment',\n code: `\n const current = value ?? 0;\n const newValue = current + args;\n return { value: newValue, result: newValue };\n `,\n args: delta,\n }),\n\n /**\n * Decrement numeric value by delta.\n * If value doesn't exist, starts from 0.\n */\n DECREMENT: (delta: number = 1): EntryProcessorDef<number, number> => ({\n name: 'builtin:decrement',\n code: `\n const current = value ?? 0;\n const newValue = current - args;\n return { value: newValue, result: newValue };\n `,\n args: delta,\n }),\n\n /**\n * Decrement with floor (won't go below 0).\n * Returns both the new value and whether it was floored.\n */\n DECREMENT_FLOOR: (\n delta: number = 1,\n ): EntryProcessorDef<number, { newValue: number; wasFloored: boolean }> => ({\n name: 'builtin:decrement_floor',\n code: `\n const current = value ?? 0;\n const target = current - args;\n const newValue = Math.max(0, target);\n return {\n value: newValue,\n result: { newValue, wasFloored: target < 0 }\n };\n `,\n args: delta,\n }),\n\n /**\n * Multiply numeric value by factor.\n * If value doesn't exist, starts from 1.\n */\n MULTIPLY: (factor: number): EntryProcessorDef<number, number> => ({\n name: 'builtin:multiply',\n code: `\n const current = value ?? 1;\n const newValue = current * args;\n return { value: newValue, result: newValue };\n `,\n args: factor,\n }),\n\n /**\n * Set value only if key doesn't exist.\n * Returns true if value was set, false if key already existed.\n */\n PUT_IF_ABSENT: <V>(newValue: V): EntryProcessorDef<V, boolean> => ({\n name: 'builtin:put_if_absent',\n code: `\n if (value !== undefined) {\n return { value, result: false };\n }\n return { value: args, result: true };\n `,\n args: newValue,\n }),\n\n /**\n * Replace value only if key exists.\n * Returns the old value if replaced, undefined otherwise.\n */\n REPLACE: <V>(newValue: V): EntryProcessorDef<V, V | undefined> => ({\n name: 'builtin:replace',\n code: `\n if (value === undefined) {\n return { value: undefined, result: undefined };\n }\n return { value: args, result: value };\n `,\n args: newValue,\n }),\n\n /**\n * Replace value only if it matches expected value.\n * Returns true if replaced, false otherwise.\n */\n REPLACE_IF_EQUALS: <V>(\n expectedValue: V,\n newValue: V,\n ): EntryProcessorDef<V, boolean> => ({\n name: 'builtin:replace_if_equals',\n code: `\n if (JSON.stringify(value) === JSON.stringify(args.expected)) {\n return { value: args.newValue, result: true };\n }\n return { value, result: false };\n `,\n args: { expected: expectedValue, newValue },\n }),\n\n /**\n * Delete entry only if value matches.\n * Returns true if deleted, false otherwise.\n */\n DELETE_IF_EQUALS: <V>(expectedValue: V): EntryProcessorDef<V, boolean> => ({\n name: 'builtin:delete_if_equals',\n code: `\n if (JSON.stringify(value) === JSON.stringify(args)) {\n return { value: undefined, result: true };\n }\n return { value, result: false };\n `,\n args: expectedValue,\n }),\n\n /**\n * Append item to array.\n * Creates array if it doesn't exist.\n * Returns new array length.\n */\n ARRAY_PUSH: <T>(item: T): EntryProcessorDef<T[], number> => ({\n name: 'builtin:array_push',\n code: `\n const arr = value ?? [];\n arr.push(args);\n return { value: arr, result: arr.length };\n `,\n args: item,\n }),\n\n /**\n * Remove last item from array.\n * Returns the removed item or undefined.\n */\n ARRAY_POP: <T>(): EntryProcessorDef<T[], T | undefined> => ({\n name: 'builtin:array_pop',\n code: `\n if (!value || value.length === 0) {\n return { value: value ?? [], result: undefined };\n }\n const removed = value.pop();\n return { value, result: removed };\n `,\n }),\n\n /**\n * Remove item from array by value (first occurrence).\n * Returns true if item was found and removed.\n */\n ARRAY_REMOVE: <T>(item: T): EntryProcessorDef<T[], boolean> => ({\n name: 'builtin:array_remove',\n code: `\n if (!value) {\n return { value: [], result: false };\n }\n const idx = value.findIndex(v => JSON.stringify(v) === JSON.stringify(args));\n if (idx === -1) {\n return { value, result: false };\n }\n value.splice(idx, 1);\n return { value, result: true };\n `,\n args: item,\n }),\n\n /**\n * Update nested property using dot notation path.\n * Creates intermediate objects if they don't exist.\n */\n SET_PROPERTY: <V>(\n path: string,\n propValue: unknown,\n ): EntryProcessorDef<V, V> => ({\n name: 'builtin:set_property',\n code: `\n const obj = value ?? {};\n const parts = args.path.split('.');\n let current = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n current[parts[i]] = current[parts[i]] ?? {};\n current = current[parts[i]];\n }\n current[parts[parts.length - 1]] = args.value;\n return { value: obj, result: obj };\n `,\n args: { path, value: propValue },\n }),\n\n /**\n * Delete nested property using dot notation path.\n * Returns the deleted value or undefined.\n */\n DELETE_PROPERTY: <V>(path: string): EntryProcessorDef<V, unknown> => ({\n name: 'builtin:delete_property',\n code: `\n if (!value) {\n return { value, result: undefined };\n }\n const parts = args.split('.');\n let current = value;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) {\n return { value, result: undefined };\n }\n current = current[parts[i]];\n }\n const lastKey = parts[parts.length - 1];\n const deleted = current[lastKey];\n delete current[lastKey];\n return { value, result: deleted };\n `,\n args: path,\n }),\n\n /**\n * Get current value without modifying it.\n * Useful for conditional reads.\n */\n GET: <V>(): EntryProcessorDef<V, V | undefined> => ({\n name: 'builtin:get',\n code: `\n return { value, result: value };\n `,\n }),\n\n /**\n * Conditional update based on version/timestamp.\n * Only updates if current version matches expected.\n * Useful for optimistic locking.\n */\n CONDITIONAL_UPDATE: <V extends { version?: number }>(\n expectedVersion: number,\n newData: Partial<V>,\n ): EntryProcessorDef<V, { updated: boolean; conflict: boolean }> => ({\n name: 'builtin:conditional_update',\n code: `\n if (!value || value.version !== args.expectedVersion) {\n return {\n value,\n result: { updated: false, conflict: true }\n };\n }\n const updated = {\n ...value,\n ...args.newData,\n version: (value.version ?? 0) + 1,\n };\n return {\n value: updated,\n result: { updated: true, conflict: false }\n };\n `,\n args: { expectedVersion, newData },\n }),\n\n /**\n * Merge object properties into existing value.\n * Shallow merge only.\n */\n MERGE: <V extends Record<string, unknown>>(\n properties: Partial<V>,\n ): EntryProcessorDef<V, V> => ({\n name: 'builtin:merge',\n code: `\n const merged = { ...(value ?? {}), ...args };\n return { value: merged, result: merged };\n `,\n args: properties,\n }),\n};\n\n// --- Rate Limiting Configuration ---\n\n/**\n * Rate limiting configuration for processor execution.\n */\nexport interface ProcessorRateLimitConfig {\n /** Max processor executions per second per client */\n maxExecutionsPerSecond: number;\n\n /** Max processor code size in bytes */\n maxCodeSizeBytes: number;\n\n /** Max args size in bytes (JSON stringified) */\n maxArgsSizeBytes: number;\n}\n\n/**\n * Default rate limit configuration.\n */\nexport const DEFAULT_PROCESSOR_RATE_LIMITS: ProcessorRateLimitConfig = {\n maxExecutionsPerSecond: 100,\n maxCodeSizeBytes: 10240, // 10KB\n maxArgsSizeBytes: 1048576, // 1MB\n};\n","import { z } from 'zod';\nimport { Timestamp, HLC } from './HLC';\n\n// --- Merge Context ---\n\n/**\n * Context provided to a conflict resolver during merge operations.\n */\nexport interface MergeContext<V = unknown> {\n /** Map name being modified */\n mapName: string;\n\n /** Entry key being modified */\n key: string;\n\n /** Current server/local value (undefined if key doesn't exist) */\n localValue: V | undefined;\n\n /** Incoming client/remote value */\n remoteValue: V;\n\n /** Local HLC timestamp (undefined if key doesn't exist) */\n localTimestamp?: Timestamp;\n\n /** Remote HLC timestamp */\n remoteTimestamp: Timestamp;\n\n /** Client/node ID that sent the update */\n remoteNodeId: string;\n\n /** Authentication context (optional) */\n auth?: {\n userId?: string;\n roles?: string[];\n metadata?: Record<string, unknown>;\n };\n\n /** Read other entries for cross-key validation */\n readEntry: (key: string) => V | undefined;\n}\n\n// --- Merge Result ---\n\n/**\n * Result of conflict resolution.\n */\nexport type MergeResult<V = unknown> =\n | { action: 'accept'; value: V } // Accept remote value\n | { action: 'reject'; reason: string } // Reject with error\n | { action: 'merge'; value: V } // Custom merged value\n | { action: 'local' }; // Keep local value\n\n// --- Conflict Resolver Function ---\n\n/**\n * Conflict resolver function signature.\n */\nexport type ConflictResolverFn<V = unknown> = (\n context: MergeContext<V>,\n) => MergeResult<V> | Promise<MergeResult<V>>;\n\n// --- Conflict Resolver Definition ---\n\n/**\n * Conflict resolver definition (can be native function or sandboxed code).\n */\nexport interface ConflictResolverDef<V = unknown> {\n /** Unique resolver name */\n name: string;\n\n /** JavaScript function body as string (for sandboxed execution) */\n code?: string;\n\n /** Native function (for trusted server-side resolvers) */\n fn?: ConflictResolverFn<V>;\n\n /** Priority (higher = runs first, default 50) */\n priority?: number;\n\n /** Apply only to specific keys (glob pattern) */\n keyPattern?: string;\n}\n\n// --- Zod Schema for Wire Format ---\n\n/**\n * Zod schema for validating conflict resolver definitions from network.\n */\nexport const ConflictResolverDefSchema = z.object({\n name: z.string().min(1).max(100),\n code: z.string().max(50000).optional(),\n priority: z.number().int().min(0).max(100).default(50),\n keyPattern: z.string().optional(),\n});\n\n// --- Security: Forbidden Patterns ---\n\n/**\n * Patterns that are denied in resolver code for security reasons.\n * Same patterns as EntryProcessor for consistency.\n */\nexport const RESOLVER_FORBIDDEN_PATTERNS = [\n /\\beval\\b/,\n /\\bFunction\\b/,\n /\\bprocess\\b/,\n /\\bglobal\\b/,\n /\\brequire\\b/,\n /\\bimport\\b/,\n /\\bfetch\\b/,\n /\\bXMLHttpRequest\\b/,\n /\\bsetTimeout\\b/,\n /\\bsetInterval\\b/,\n /\\bsetImmediate\\b/,\n];\n\n/**\n * Validates resolver code against forbidden patterns.\n */\nexport function validateResolverCode(code: string): {\n valid: boolean;\n error?: string;\n} {\n for (const pattern of RESOLVER_FORBIDDEN_PATTERNS) {\n if (pattern.test(code)) {\n return {\n valid: false,\n error: `Forbidden pattern detected: ${pattern.source}`,\n };\n }\n }\n return { valid: true };\n}\n\n// --- Rate Limiting Configuration ---\n\n/**\n * Rate limiting configuration for resolver registration.\n */\nexport interface ResolverRateLimitConfig {\n /** Max resolver registrations per client */\n maxResolversPerClient: number;\n\n /** Max resolver code size in bytes */\n maxCodeSizeBytes: number;\n}\n\n/**\n * Default rate limit configuration.\n */\nexport const DEFAULT_RESOLVER_RATE_LIMITS: ResolverRateLimitConfig = {\n maxResolversPerClient: 50,\n maxCodeSizeBytes: 50000, // 50KB\n};\n\n// --- Helper Functions ---\n\n/**\n * Compares two HLC timestamps.\n * Returns negative if a < b, positive if a > b, 0 if equal.\n */\nexport function compareHLCTimestamps(a: Timestamp, b: Timestamp): number {\n return HLC.compare(a, b);\n}\n\n/**\n * Deep merges two objects.\n * Remote values take precedence at each level.\n */\nexport function deepMerge<T extends object>(target: T, source: T): T {\n const result = { ...target };\n\n for (const key of Object.keys(source) as (keyof T)[]) {\n const sourceVal = source[key];\n const targetVal = target[key];\n\n if (\n typeof sourceVal === 'object' &&\n sourceVal !== null &&\n typeof targetVal === 'object' &&\n targetVal !== null &&\n !Array.isArray(sourceVal)\n ) {\n (result as Record<string, unknown>)[key as string] = deepMerge(\n targetVal as object,\n sourceVal as object,\n );\n } else {\n (result as Record<string, unknown>)[key as string] = sourceVal;\n }\n }\n\n return result;\n}\n\n// --- Built-in Resolvers ---\n\n/**\n * Built-in conflict resolvers for common patterns.\n * These are type-safe and pre-validated.\n */\nexport const BuiltInResolvers = {\n /**\n * Standard Last-Write-Wins - accept if remote timestamp is newer.\n */\n LWW: <V>(): ConflictResolverDef<V> => ({\n name: 'builtin:lww',\n fn: (ctx) => {\n if (!ctx.localTimestamp) {\n return { action: 'accept', value: ctx.remoteValue };\n }\n\n const cmp = compareHLCTimestamps(ctx.remoteTimestamp, ctx.localTimestamp);\n if (cmp > 0) {\n return { action: 'accept', value: ctx.remoteValue };\n }\n return { action: 'local' };\n },\n priority: 0, // Lowest priority - fallback\n }),\n\n /**\n * First-Write-Wins - reject if local value exists.\n * Useful for booking systems, unique constraints.\n */\n FIRST_WRITE_WINS: <V>(): ConflictResolverDef<V> => ({\n name: 'builtin:first_write_wins',\n fn: (ctx) => {\n if (ctx.localValue !== undefined) {\n return { action: 'reject', reason: 'Entry already exists' };\n }\n return { action: 'accept', value: ctx.remoteValue };\n },\n priority: 100,\n }),\n\n /**\n * Numeric minimum - keep lowest value.\n * Useful for auction systems (lowest bid wins).\n */\n NUMERIC_MIN: (): ConflictResolverDef<number> => ({\n name: 'builtin:numeric_min',\n fn: (ctx) => {\n const local = ctx.localValue ?? Infinity;\n const remote = ctx.remoteValue;\n return { action: 'merge', value: Math.min(local, remote) };\n },\n priority: 50,\n }),\n\n /**\n * Numeric maximum - keep highest value.\n * Useful for high score tracking.\n */\n NUMERIC_MAX: (): ConflictResolverDef<number> => ({\n name: 'builtin:numeric_max',\n fn: (ctx) => {\n const local = ctx.localValue ?? -Infinity;\n const remote = ctx.remoteValue;\n return { action: 'merge', value: Math.max(local, remote) };\n },\n priority: 50,\n }),\n\n /**\n * Non-negative - reject if value would be negative.\n * Useful for inventory systems.\n */\n NON_NEGATIVE: (): ConflictResolverDef<number> => ({\n name: 'builtin:non_negative',\n fn: (ctx) => {\n if (typeof ctx.remoteValue !== 'number' || ctx.remoteValue < 0) {\n return { action: 'reject', reason: 'Value cannot be negative' };\n }\n return { action: 'accept', value: ctx.remoteValue };\n },\n priority: 90,\n }),\n\n /**\n * Array union - merge arrays by taking union of elements.\n * Useful for tags, categories.\n */\n ARRAY_UNION: <T>(): ConflictResolverDef<T[]> => ({\n name: 'builtin:array_union',\n fn: (ctx) => {\n const local = ctx.localValue ?? [];\n const remote = ctx.remoteValue ?? [];\n const merged = [...new Set([...local, ...remote])];\n return { action: 'merge', value: merged };\n },\n priority: 50,\n }),\n\n /**\n * Deep merge - recursively merge objects.\n * Remote values take precedence at leaf level.\n */\n DEEP_MERGE: <V extends object>(): ConflictResolverDef<V> => ({\n name: 'builtin:deep_merge',\n fn: (ctx) => {\n const local = (ctx.localValue ?? {}) as V;\n const remote = ctx.remoteValue;\n const merged = deepMerge(local, remote);\n return { action: 'merge', value: merged };\n },\n priority: 50,\n }),\n\n /**\n * Server-only - reject all client writes.\n * Useful for server-controlled state.\n */\n SERVER_ONLY: <V>(): ConflictResolverDef<V> => ({\n name: 'builtin:server_only',\n fn: (ctx) => {\n // Server writes have a special node ID or auth role\n if (ctx.auth?.roles?.includes('server') || ctx.remoteNodeId.startsWith('server:')) {\n return { action: 'accept', value: ctx.remoteValue };\n }\n return { action: 'reject', reason: 'Only server can write to this entry' };\n },\n priority: 100,\n }),\n\n /**\n * Owner-only - only the original creator can modify.\n * Requires value to have an `ownerId` property.\n */\n OWNER_ONLY: <V extends { ownerId?: string }>(): ConflictResolverDef<V> => ({\n name: 'builtin:owner_only',\n fn: (ctx) => {\n // If no local value, accept (first write sets owner)\n if (!ctx.localValue) {\n return { action: 'accept', value: ctx.remoteValue };\n }\n\n // Check if remote is from owner\n const ownerId = ctx.localValue.ownerId;\n if (ownerId && ctx.auth?.userId !== ownerId) {\n return { action: 'reject', reason: 'Only owner can modify this entry' };\n }\n\n return { action: 'accept', value: ctx.remoteValue };\n },\n priority: 95,\n }),\n\n /**\n * Immutable - reject any modifications after initial write.\n */\n IMMUTABLE: <V>(): ConflictResolverDef<V> => ({\n name: 'builtin:immutable',\n fn: (ctx) => {\n if (ctx.localValue !== undefined) {\n return { action: 'reject', reason: 'Entry is immutable' };\n }\n return { action: 'accept', value: ctx.remoteValue };\n },\n priority: 100,\n }),\n\n /**\n * Version check - only accept if version increments by 1.\n * Useful for optimistic locking.\n */\n VERSION_INCREMENT: <V extends { version?: number }>(): ConflictResolverDef<V> => ({\n name: 'builtin:version_increment',\n fn: (ctx) => {\n const localVersion = ctx.localValue?.version ?? 0;\n const remoteVersion = ctx.remoteValue?.version ?? 0;\n\n if (remoteVersion !== localVersion + 1) {\n return {\n action: 'reject',\n reason: `Version conflict: expected ${localVersion + 1}, got ${remoteVersion}`,\n };\n }\n return { action: 'accept', value: ctx.remoteValue };\n },\n priority: 90,\n }),\n};\n\n// --- Merge Rejection Event ---\n\n/**\n * Event emitted when a merge is rejected.\n */\nexport interface MergeRejection {\n mapName: string;\n key: string;\n attemptedValue: unknown;\n reason: string;\n timestamp: Timestamp;\n nodeId: string;\n}\n","\nexport type PredicateOp =\n | 'eq' | 'neq'\n | 'gt' | 'gte'\n | 'lt' | 'lte'\n | 'like' | 'regex'\n | 'contains' | 'containsAll' | 'containsAny'\n | 'and' | 'or' | 'not'\n // Full-Text Search predicates (Phase 12)\n | 'match' | 'matchPhrase' | 'matchPrefix';\n\n/**\n * Options for full-text search match predicate.\n */\nexport interface MatchOptions {\n /** Minimum BM25 score threshold */\n minScore?: number;\n /** Boost factor for this field */\n boost?: number;\n /** Operator for multi-term queries: 'and' requires all terms, 'or' requires any */\n operator?: 'and' | 'or';\n /** Fuzziness level for typo tolerance (0 = exact, 1 = 1 edit, 2 = 2 edits) */\n fuzziness?: number;\n}\n\nexport interface PredicateNode {\n op: PredicateOp;\n attribute?: string;\n value?: any;\n children?: PredicateNode[];\n /** FTS-specific: search query string */\n query?: string;\n /** FTS-specific: match options */\n matchOptions?: MatchOptions;\n /** FTS-specific: phrase slop (word distance tolerance) */\n slop?: number;\n /** FTS-specific: prefix for matchPrefix */\n prefix?: string;\n /** FTS-specific: max prefix expansions */\n maxExpansions?: number;\n}\n\nexport class Predicates {\n static equal(attribute: string, value: any): PredicateNode { \n return { op: 'eq', attribute, value }; \n }\n \n static notEqual(attribute: string, value: any): PredicateNode { \n return { op: 'neq', attribute, value }; \n }\n \n static greaterThan(attribute: string, value: any): PredicateNode { \n return { op: 'gt', attribute, value }; \n }\n \n static greaterThanOrEqual(attribute: string, value: any): PredicateNode { \n return { op: 'gte', attribute, value }; \n }\n \n static lessThan(attribute: string, value: any): PredicateNode { \n return { op: 'lt', attribute, value }; \n }\n \n static lessThanOrEqual(attribute: string, value: any): PredicateNode { \n return { op: 'lte', attribute, value }; \n }\n \n static like(attribute: string, pattern: string): PredicateNode { \n return { op: 'like', attribute, value: pattern }; \n }\n \n static regex(attribute: string, pattern: string): PredicateNode { \n return { op: 'regex', attribute, value: pattern }; \n }\n\n static between(attribute: string, from: any, to: any): PredicateNode {\n return {\n op: 'and',\n children: [\n { op: 'gte', attribute, value: from },\n { op: 'lte', attribute, value: to }\n ]\n };\n }\n\n static and(...predicates: PredicateNode[]): PredicateNode { \n return { op: 'and', children: predicates }; \n }\n \n static or(...predicates: PredicateNode[]): PredicateNode { \n return { op: 'or', children: predicates }; \n }\n \n static not(predicate: PredicateNode): PredicateNode {\n return { op: 'not', children: [predicate] };\n }\n\n /**\n * Create a 'contains' predicate for text search.\n * Matches if attribute value contains the search text.\n *\n * @param attribute - Attribute name\n * @param value - Text to search for\n */\n static contains(attribute: string, value: string): PredicateNode {\n return { op: 'contains', attribute, value };\n }\n\n /**\n * Create a 'containsAll' predicate for text search.\n * Matches if attribute value contains ALL search values.\n *\n * @param attribute - Attribute name\n * @param values - Text values that must all be present\n */\n static containsAll(attribute: string, values: string[]): PredicateNode {\n return { op: 'containsAll', attribute, value: values };\n }\n\n /**\n * Create a 'containsAny' predicate for text search.\n * Matches if attribute value contains ANY search value.\n *\n * @param attribute - Attribute name\n * @param values - Text values, any of which can match\n */\n static containsAny(attribute: string, values: string[]): PredicateNode {\n return { op: 'containsAny', attribute, value: values };\n }\n\n // ============== Full-Text Search Predicates (Phase 12) ==============\n\n /**\n * Create a 'match' predicate for full-text search.\n * Uses BM25 scoring to find relevant documents.\n *\n * @param attribute - Field to search in\n * @param query - Search query string\n * @param options - Match options (minScore, boost, operator, fuzziness)\n *\n * @example\n * ```typescript\n * // Simple match\n * Predicates.match('title', 'machine learning')\n *\n * // With options\n * Predicates.match('body', 'neural networks', { minScore: 1.0, boost: 2.0 })\n * ```\n */\n static match(attribute: string, query: string, options?: MatchOptions): PredicateNode {\n return { op: 'match', attribute, query, matchOptions: options };\n }\n\n /**\n * Create a 'matchPhrase' predicate for exact phrase matching.\n * Matches documents containing the exact phrase (words in order).\n *\n * @param attribute - Field to search in\n * @param query - Phrase to match\n * @param slop - Word distance tolerance (0 = exact, 1 = allow 1 word between)\n *\n * @example\n * ```typescript\n * // Exact phrase\n * Predicates.matchPhrase('body', 'machine learning')\n *\n * // With slop (allows \"machine deep learning\")\n * Predicates.matchPhrase('body', 'machine learning', 1)\n * ```\n */\n static matchPhrase(attribute: string, query: string, slop?: number): PredicateNode {\n return { op: 'matchPhrase', attribute, query, slop };\n }\n\n /**\n * Create a 'matchPrefix' predicate for prefix matching.\n * Matches documents where field starts with the given prefix.\n *\n * @param attribute - Field to search in\n * @param prefix - Prefix to match\n * @param maxExpansions - Maximum number of term expansions\n *\n * @example\n * ```typescript\n * // Match titles starting with \"mach\"\n * Predicates.matchPrefix('title', 'mach')\n *\n * // Limit expansions for performance\n * Predicates.matchPrefix('title', 'mach', 50)\n * ```\n */\n static matchPrefix(attribute: string, prefix: string, maxExpansions?: number): PredicateNode {\n return { op: 'matchPrefix', attribute, prefix, maxExpansions };\n }\n\n /**\n * Create a multi-field match predicate.\n * Searches across multiple fields with optional per-field boosting.\n *\n * @param attributes - Fields to search in\n * @param query - Search query string\n * @param options - Options including per-field boost factors\n *\n * @example\n * ```typescript\n * // Search title and body\n * Predicates.multiMatch(['title', 'body'], 'machine learning')\n *\n * // With boosting (title 2x more important)\n * Predicates.multiMatch(['title', 'body'], 'machine learning', {\n * boost: { title: 2.0, body: 1.0 }\n * })\n * ```\n */\n static multiMatch(\n attributes: string[],\n query: string,\n options?: { boost?: Record<string, number> }\n ): PredicateNode {\n const children = attributes.map((attr) => ({\n op: 'match' as const,\n attribute: attr,\n query,\n matchOptions: options?.boost?.[attr] ? { boost: options.boost[attr] } : undefined,\n }));\n return { op: 'or', children };\n }\n}\n\nexport function evaluatePredicate(predicate: PredicateNode, data: any): boolean {\n if (!data) return false;\n \n switch (predicate.op) {\n case 'and':\n return (predicate.children || []).every(p => evaluatePredicate(p, data));\n case 'or':\n return (predicate.children || []).some(p => evaluatePredicate(p, data));\n case 'not': {\n const child = (predicate.children || [])[0];\n if (!child) return true; // NOT of nothing is true (vacuous)\n return !evaluatePredicate(child, data);\n }\n }\n\n // Leaf nodes require an attribute\n if (!predicate.attribute) return false;\n \n const value = data[predicate.attribute];\n const target = predicate.value;\n\n switch (predicate.op) {\n case 'eq':\n return value === target;\n case 'neq':\n return value !== target;\n case 'gt':\n return value > target;\n case 'gte':\n return value >= target;\n case 'lt':\n return value < target;\n case 'lte':\n return value <= target;\n case 'like':\n if (typeof value !== 'string' || typeof target !== 'string') return false;\n const pattern = target\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n .replace(/%/g, '.*')\n .replace(/_/g, '.');\n return new RegExp(`^${pattern}$`, 'i').test(value);\n case 'regex':\n if (typeof value !== 'string' || typeof target !== 'string') return false;\n return new RegExp(target).test(value);\n case 'contains':\n if (typeof value !== 'string' || typeof target !== 'string') return false;\n return value.toLowerCase().includes(target.toLowerCase());\n case 'containsAll':\n if (typeof value !== 'string' || !Array.isArray(target)) return false;\n return target.every(\n (t) => typeof t === 'string' && value.toLowerCase().includes(t.toLowerCase())\n );\n case 'containsAny':\n if (typeof value !== 'string' || !Array.isArray(target)) return false;\n return target.some(\n (t) => typeof t === 'string' && value.toLowerCase().includes(t.toLowerCase())\n );\n default:\n return false;\n }\n}\n","import { z } from 'zod';\n\n// --- Write Concern Types ---\n\n/**\n * Write Concern schema - defines when an operation is considered acknowledged.\n */\nexport const WriteConcernSchema = z.enum([\n 'FIRE_AND_FORGET',\n 'MEMORY',\n 'APPLIED',\n 'REPLICATED',\n 'PERSISTED',\n]);\n\nexport type WriteConcernValue = z.infer<typeof WriteConcernSchema>;\n\n// --- Basic Types ---\n\nexport const TimestampSchema = z.object({\n millis: z.union([z.number(), z.bigint()]).transform(Number),\n counter: z.union([z.number(), z.bigint()]).transform(Number),\n nodeId: z.string(),\n});\n\nexport const LWWRecordSchema = z.object({\n value: z.any().nullable(),\n timestamp: TimestampSchema,\n ttlMs: z.number().optional(),\n});\n\nexport const ORMapRecordSchema = z.object({\n value: z.any(),\n timestamp: TimestampSchema,\n tag: z.string(),\n ttlMs: z.number().optional(),\n});\n\n// --- Predicate Types ---\n\nexport const PredicateOpSchema = z.enum([\n 'eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'like', 'regex', 'and', 'or', 'not'\n]);\n\n// Recursive schema for PredicateNode\nexport const PredicateNodeSchema: z.ZodType<any> = z.lazy(() => z.object({\n op: PredicateOpSchema,\n attribute: z.string().optional(),\n value: z.any().optional(),\n children: z.array(PredicateNodeSchema).optional(),\n}));\n\n// --- Query Types ---\n\nexport const QuerySchema = z.object({\n where: z.record(z.string(), z.any()).optional(),\n predicate: PredicateNodeSchema.optional(),\n sort: z.record(z.string(), z.enum(['asc', 'desc'])).optional(),\n limit: z.number().optional(),\n cursor: z.string().optional(), // Phase 14.1: replaces offset\n});\n\n// --- Query Response Types (Phase 14.1) ---\n\n/**\n * Cursor status for debugging.\n * - valid: Cursor was valid and applied\n * - expired: Cursor was expired (fell back to first page)\n * - invalid: Cursor was malformed or hash mismatch (fell back to first page)\n * - none: No cursor was provided\n */\nexport const CursorStatusSchema = z.enum(['valid', 'expired', 'invalid', 'none']);\n\nexport const QueryRespPayloadSchema = z.object({\n queryId: z.string(),\n results: z.array(z.object({\n key: z.string(),\n value: z.unknown(),\n })),\n nextCursor: z.string().optional(),\n hasMore: z.boolean().optional(),\n /** Debug info: status of input cursor processing */\n cursorStatus: CursorStatusSchema.optional(),\n});\n\nexport const QueryRespMessageSchema = z.object({\n type: z.literal('QUERY_RESP'),\n payload: QueryRespPayloadSchema,\n});\n\n// --- Client Operation Types ---\n\nexport const ClientOpSchema = z.object({\n id: z.string().optional(),\n mapName: z.string(),\n key: z.string(),\n // Permissive opType to match ServerCoordinator behavior logic\n // It can be 'REMOVE', 'OR_ADD', 'OR_REMOVE' or undefined/other (implies PUT/LWW)\n opType: z.string().optional(),\n record: LWWRecordSchema.nullable().optional(),\n orRecord: ORMapRecordSchema.nullable().optional(),\n orTag: z.string().nullable().optional(),\n // Write Concern fields (Phase 5.01)\n writeConcern: WriteConcernSchema.optional(),\n timeout: z.number().optional(),\n});\n\n// --- Message Schemas ---\n\nexport const AuthMessageSchema = z.object({\n type: z.literal('AUTH'),\n token: z.string(),\n});\n\nexport const QuerySubMessageSchema = z.object({\n type: z.literal('QUERY_SUB'),\n payload: z.object({\n queryId: z.string(),\n mapName: z.string(),\n query: QuerySchema,\n }),\n});\n\nexport const QueryUnsubMessageSchema = z.object({\n type: z.literal('QUERY_UNSUB'),\n payload: z.object({\n queryId: z.string(),\n }),\n});\n\nexport const ClientOpMessageSchema = z.object({\n type: z.literal('CLIENT_OP'),\n payload: ClientOpSchema,\n});\n\nexport const OpBatchMessageSchema = z.object({\n type: z.literal('OP_BATCH'),\n payload: z.object({\n ops: z.array(ClientOpSchema),\n // Batch-level Write Concern (can be overridden per-op)\n writeConcern: WriteConcernSchema.optional(),\n timeout: z.number().optional(),\n }),\n});\n\nexport const SyncInitMessageSchema = z.object({\n type: z.literal('SYNC_INIT'),\n mapName: z.string(),\n lastSyncTimestamp: z.number().optional(),\n});\n\nexport const SyncRespRootMessageSchema = z.object({\n type: z.literal('SYNC_RESP_ROOT'),\n payload: z.object({\n mapName: z.string(),\n rootHash: z.number(),\n timestamp: TimestampSchema,\n }),\n});\n\nexport const SyncRespBucketsMessageSchema = z.object({\n type: z.literal('SYNC_RESP_BUCKETS'),\n payload: z.object({\n mapName: z.string(),\n path: z.string(),\n buckets: z.record(z.string(), z.number()),\n }),\n});\n\nexport const SyncRespLeafMessageSchema = z.object({\n type: z.literal('SYNC_RESP_LEAF'),\n payload: z.object({\n mapName: z.string(),\n path: z.string(),\n records: z.array(z.object({\n key: z.string(),\n record: LWWRecordSchema,\n })),\n }),\n});\n\nexport const MerkleReqBucketMessageSchema = z.object({\n type: z.literal('MERKLE_REQ_BUCKET'),\n payload: z.object({\n mapName: z.string(),\n path: z.string(),\n }),\n});\n\nexport const LockRequestSchema = z.object({\n type: z.literal('LOCK_REQUEST'),\n payload: z.object({\n requestId: z.string(),\n name: z.string(),\n ttl: z.number().optional(),\n }),\n});\n\nexport const LockReleaseSchema = z.object({\n type: z.literal('LOCK_RELEASE'),\n payload: z.object({\n requestId: z.string().optional(),\n name: z.string(),\n fencingToken: z.number(),\n }),\n});\n\n// --- Topic Messages ---\n\nexport const TopicSubSchema = z.object({\n type: z.literal('TOPIC_SUB'),\n payload: z.object({\n topic: z.string(),\n }),\n});\n\nexport const TopicUnsubSchema = z.object({\n type: z.literal('TOPIC_UNSUB'),\n payload: z.object({\n topic: z.string(),\n }),\n});\n\nexport const TopicPubSchema = z.object({\n type: z.literal('TOPIC_PUB'),\n payload: z.object({\n topic: z.string(),\n data: z.any(),\n }),\n});\n\nexport const TopicMessageEventSchema = z.object({\n type: z.literal('TOPIC_MESSAGE'),\n payload: z.object({\n topic: z.string(),\n data: z.any(),\n publisherId: z.string().optional(),\n timestamp: z.number(),\n }),\n});\n\n// --- PN Counter Messages (Phase 5.2) ---\n\nexport const PNCounterStateObjectSchema = z.object({\n p: z.record(z.string(), z.number()), // positive counts per node\n n: z.record(z.string(), z.number()), // negative counts per node\n});\n\nexport const CounterRequestSchema = z.object({\n type: z.literal('COUNTER_REQUEST'),\n payload: z.object({\n name: z.string(),\n }),\n});\n\nexport const CounterSyncSchema = z.object({\n type: z.literal('COUNTER_SYNC'),\n payload: z.object({\n name: z.string(),\n state: PNCounterStateObjectSchema,\n }),\n});\n\nexport const CounterResponseSchema = z.object({\n type: z.literal('COUNTER_RESPONSE'),\n payload: z.object({\n name: z.string(),\n state: PNCounterStateObjectSchema,\n }),\n});\n\nexport const CounterUpdateSchema = z.object({\n type: z.literal('COUNTER_UPDATE'),\n payload: z.object({\n name: z.string(),\n state: PNCounterStateObjectSchema,\n }),\n});\n\n// --- Heartbeat Messages ---\n\nexport const PingMessageSchema = z.object({\n type: z.literal('PING'),\n timestamp: z.number(), // Client's Date.now()\n});\n\nexport const PongMessageSchema = z.object({\n type: z.literal('PONG'),\n timestamp: z.number(), // Echo back client's timestamp\n serverTime: z.number(), // Server's Date.now() (for clock skew detection)\n});\n\n// --- Batched Messages ---\n\n/**\n * BATCH: Server sends multiple messages batched together.\n * Uses length-prefixed binary format for efficiency.\n * Format: [4 bytes: count][4 bytes: len1][msg1][4 bytes: len2][msg2]...\n */\nexport const BatchMessageSchema = z.object({\n type: z.literal('BATCH'),\n count: z.number(),\n data: z.instanceof(Uint8Array),\n});\n\n// --- ORMap Sync Messages ---\n\n/**\n * ORMAP_SYNC_INIT: Client initiates ORMap sync\n * Sends root hash and bucket hashes to server\n */\nexport const ORMapSyncInitSchema = z.object({\n type: z.literal('ORMAP_SYNC_INIT'),\n mapName: z.string(),\n rootHash: z.number(),\n bucketHashes: z.record(z.string(), z.number()), // path -> hash\n lastSyncTimestamp: z.number().optional(),\n});\n\n/**\n * ORMAP_SYNC_RESP_ROOT: Server responds with its root hash\n */\nexport const ORMapSyncRespRootSchema = z.object({\n type: z.literal('ORMAP_SYNC_RESP_ROOT'),\n payload: z.object({\n mapName: z.string(),\n rootHash: z.number(),\n timestamp: TimestampSchema,\n }),\n});\n\n/**\n * ORMAP_SYNC_RESP_BUCKETS: Server sends bucket hashes for comparison\n */\nexport const ORMapSyncRespBucketsSchema = z.object({\n type: z.literal('ORMAP_SYNC_RESP_BUCKETS'),\n payload: z.object({\n mapName: z.string(),\n path: z.string(),\n buckets: z.record(z.string(), z.number()),\n }),\n});\n\n/**\n * ORMAP_MERKLE_REQ_BUCKET: Client requests bucket details\n */\nexport const ORMapMerkleReqBucketSchema = z.object({\n type: z.literal('ORMAP_MERKLE_REQ_BUCKET'),\n payload: z.object({\n mapName: z.string(),\n path: z.string(),\n }),\n});\n\n/**\n * ORMAP_SYNC_RESP_LEAF: Server sends actual records for differing keys\n */\nexport const ORMapSyncRespLeafSchema = z.object({\n type: z.literal('ORMAP_SYNC_RESP_LEAF'),\n payload: z.object({\n mapName: z.string(),\n path: z.string(),\n entries: z.array(z.object({\n key: z.string(),\n records: z.array(ORMapRecordSchema),\n tombstones: z.array(z.string()), // Tombstone tags for this key's records\n })),\n }),\n});\n\n/**\n * ORMAP_DIFF_REQUEST: Client requests data for specific keys\n */\nexport const ORMapDiffRequestSchema = z.object({\n type: z.literal('ORMAP_DIFF_REQUEST'),\n payload: z.object({\n mapName: z.string(),\n keys: z.array(z.string()),\n }),\n});\n\n/**\n * ORMAP_DIFF_RESPONSE: Server responds with data for requested keys\n */\nexport const ORMapDiffResponseSchema = z.object({\n type: z.literal('ORMAP_DIFF_RESPONSE'),\n payload: z.object({\n mapName: z.string(),\n entries: z.array(z.object({\n key: z.string(),\n records: z.array(ORMapRecordSchema),\n tombstones: z.array(z.string()),\n })),\n }),\n});\n\n/**\n * ORMAP_PUSH_DIFF: Client pushes local diffs to server\n */\nexport const ORMapPushDiffSchema = z.object({\n type: z.literal('ORMAP_PUSH_DIFF'),\n payload: z.object({\n mapName: z.string(),\n entries: z.array(z.object({\n key: z.string(),\n records: z.array(ORMapRecordSchema),\n tombstones: z.array(z.string()),\n })),\n }),\n});\n\n// --- Phase 4: Partition Map Schemas ---\n\n/**\n * PARTITION_MAP_REQUEST: Client requests current partition map\n */\nexport const PartitionMapRequestSchema = z.object({\n type: z.literal('PARTITION_MAP_REQUEST'),\n payload: z.object({\n currentVersion: z.number().optional(),\n }).optional(),\n});\n\n// --- Entry Processor Messages (Phase 5.03) ---\n\n/**\n * Entry processor definition schema.\n */\nexport const EntryProcessorSchema = z.object({\n name: z.string().min(1).max(100),\n code: z.string().min(1).max(10000),\n args: z.unknown().optional(),\n});\n\n/**\n * ENTRY_PROCESS: Client requests atomic operation on single key.\n */\nexport const EntryProcessRequestSchema = z.object({\n type: z.literal('ENTRY_PROCESS'),\n requestId: z.string(),\n mapName: z.string(),\n key: z.string(),\n processor: EntryProcessorSchema,\n});\n\n/**\n * ENTRY_PROCESS_BATCH: Client requests atomic operation on multiple keys.\n */\nexport const EntryProcessBatchRequestSchema = z.object({\n type: z.literal('ENTRY_PROCESS_BATCH'),\n requestId: z.string(),\n mapName: z.string(),\n keys: z.array(z.string()),\n processor: EntryProcessorSchema,\n});\n\n/**\n * ENTRY_PROCESS_RESPONSE: Server responds to single-key processor request.\n */\nexport const EntryProcessResponseSchema = z.object({\n type: z.literal('ENTRY_PROCESS_RESPONSE'),\n requestId: z.string(),\n success: z.boolean(),\n result: z.unknown().optional(),\n newValue: z.unknown().optional(),\n error: z.string().optional(),\n});\n\n/**\n * Individual key result in batch response.\n */\nexport const EntryProcessKeyResultSchema = z.object({\n success: z.boolean(),\n result: z.unknown().optional(),\n newValue: z.unknown().optional(),\n error: z.string().optional(),\n});\n\n/**\n * ENTRY_PROCESS_BATCH_RESPONSE: Server responds to multi-key processor request.\n */\nexport const EntryProcessBatchResponseSchema = z.object({\n type: z.literal('ENTRY_PROCESS_BATCH_RESPONSE'),\n requestId: z.string(),\n results: z.record(z.string(), EntryProcessKeyResultSchema),\n});\n\n// --- Event Journal Messages (Phase 5.04) ---\n\n/**\n * Journal event type schema.\n */\nexport const JournalEventTypeSchema = z.enum(['PUT', 'UPDATE', 'DELETE']);\n\n/**\n * Journal event data (serialized for network).\n */\nexport const JournalEventDataSchema = z.object({\n sequence: z.string(), // bigint as string\n type: JournalEventTypeSchema,\n mapName: z.string(),\n key: z.string(),\n value: z.unknown().optional(),\n previousValue: z.unknown().optional(),\n timestamp: TimestampSchema,\n nodeId: z.string(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * JOURNAL_SUBSCRIBE: Client subscribes to journal events.\n */\nexport const JournalSubscribeRequestSchema = z.object({\n type: z.literal('JOURNAL_SUBSCRIBE'),\n requestId: z.string(),\n fromSequence: z.string().optional(), // bigint as string\n mapName: z.string().optional(),\n types: z.array(JournalEventTypeSchema).optional(),\n});\n\n/**\n * JOURNAL_UNSUBSCRIBE: Client unsubscribes from journal events.\n */\nexport const JournalUnsubscribeRequestSchema = z.object({\n type: z.literal('JOURNAL_UNSUBSCRIBE'),\n subscriptionId: z.string(),\n});\n\n/**\n * JOURNAL_EVENT: Server sends journal event to client.\n */\nexport const JournalEventMessageSchema = z.object({\n type: z.literal('JOURNAL_EVENT'),\n event: JournalEventDataSchema,\n});\n\n/**\n * JOURNAL_READ: Client requests events from journal.\n */\nexport const JournalReadRequestSchema = z.object({\n type: z.literal('JOURNAL_READ'),\n requestId: z.string(),\n fromSequence: z.string(),\n limit: z.number().optional(),\n mapName: z.string().optional(),\n});\n\n/**\n * JOURNAL_READ_RESPONSE: Server responds with journal events.\n */\nexport const JournalReadResponseSchema = z.object({\n type: z.literal('JOURNAL_READ_RESPONSE'),\n requestId: z.string(),\n events: z.array(JournalEventDataSchema),\n hasMore: z.boolean(),\n});\n\n// --- Full-Text Search Messages (Phase 11.1) ---\n\n/**\n * Search options schema for FTS queries.\n */\nexport const SearchOptionsSchema = z.object({\n limit: z.number().optional(),\n minScore: z.number().optional(),\n boost: z.record(z.string(), z.number()).optional(),\n});\n\n/**\n * SEARCH: Client requests one-shot BM25 search.\n */\nexport const SearchPayloadSchema = z.object({\n requestId: z.string(),\n mapName: z.string(),\n query: z.string(),\n options: SearchOptionsSchema.optional(),\n});\n\nexport const SearchMessageSchema = z.object({\n type: z.literal('SEARCH'),\n payload: SearchPayloadSchema,\n});\n\n/**\n * SEARCH_RESP: Server responds with search results.\n */\nexport const SearchRespPayloadSchema = z.object({\n requestId: z.string(),\n results: z.array(z.object({\n key: z.string(),\n value: z.unknown(),\n score: z.number(),\n matchedTerms: z.array(z.string()),\n })),\n totalCount: z.number(),\n error: z.string().optional(),\n});\n\nexport const SearchRespMessageSchema = z.object({\n type: z.literal('SEARCH_RESP'),\n payload: SearchRespPayloadSchema,\n});\n\n// --- Live Search Subscription Messages (Phase 11.1b) ---\n\n/**\n * Search delta update type.\n * - ENTER: Document entered the result set (new or score exceeded minScore)\n * - UPDATE: Document score changed while remaining in result set\n * - LEAVE: Document left the result set (removed or score dropped below minScore)\n */\nexport const SearchUpdateTypeSchema = z.enum(['ENTER', 'UPDATE', 'LEAVE']);\n\n/**\n * SEARCH_SUB: Client subscribes to live search results.\n */\nexport const SearchSubPayloadSchema = z.object({\n subscriptionId: z.string(),\n mapName: z.string(),\n query: z.string(),\n options: SearchOptionsSchema.optional(),\n});\n\nexport const SearchSubMessageSchema = z.object({\n type: z.literal('SEARCH_SUB'),\n payload: SearchSubPayloadSchema,\n});\n\n/**\n * SEARCH_UPDATE: Server sends delta update for a subscribed search.\n */\nexport const SearchUpdatePayloadSchema = z.object({\n subscriptionId: z.string(),\n key: z.string(),\n value: z.unknown(),\n score: z.number(),\n matchedTerms: z.array(z.string()),\n type: SearchUpdateTypeSchema,\n});\n\nexport const SearchUpdateMessageSchema = z.object({\n type: z.literal('SEARCH_UPDATE'),\n payload: SearchUpdatePayloadSchema,\n});\n\n/**\n * SEARCH_UNSUB: Client unsubscribes from live search.\n */\nexport const SearchUnsubPayloadSchema = z.object({\n subscriptionId: z.string(),\n});\n\nexport const SearchUnsubMessageSchema = z.object({\n type: z.literal('SEARCH_UNSUB'),\n payload: SearchUnsubPayloadSchema,\n});\n\n// --- Conflict Resolver Messages (Phase 5.05) ---\n\n/**\n * Conflict resolver definition schema (wire format).\n */\nexport const ConflictResolverSchema = z.object({\n name: z.string().min(1).max(100),\n code: z.string().max(50000),\n priority: z.number().int().min(0).max(100).optional(),\n keyPattern: z.string().optional(),\n});\n\n/**\n * REGISTER_RESOLVER: Client registers a conflict resolver on server.\n */\nexport const RegisterResolverRequestSchema = z.object({\n type: z.literal('REGISTER_RESOLVER'),\n requestId: z.string(),\n mapName: z.string(),\n resolver: ConflictResolverSchema,\n});\n\n/**\n * REGISTER_RESOLVER_RESPONSE: Server acknowledges resolver registration.\n */\nexport const RegisterResolverResponseSchema = z.object({\n type: z.literal('REGISTER_RESOLVER_RESPONSE'),\n requestId: z.string(),\n success: z.boolean(),\n error: z.string().optional(),\n});\n\n/**\n * UNREGISTER_RESOLVER: Client unregisters a conflict resolver.\n */\nexport const UnregisterResolverRequestSchema = z.object({\n type: z.literal('UNREGISTER_RESOLVER'),\n requestId: z.string(),\n mapName: z.string(),\n resolverName: z.string(),\n});\n\n/**\n * UNREGISTER_RESOLVER_RESPONSE: Server acknowledges resolver unregistration.\n */\nexport const UnregisterResolverResponseSchema = z.object({\n type: z.literal('UNREGISTER_RESOLVER_RESPONSE'),\n requestId: z.string(),\n success: z.boolean(),\n error: z.string().optional(),\n});\n\n/**\n * MERGE_REJECTED: Server notifies client that a merge was rejected.\n */\nexport const MergeRejectedMessageSchema = z.object({\n type: z.literal('MERGE_REJECTED'),\n mapName: z.string(),\n key: z.string(),\n attemptedValue: z.unknown(),\n reason: z.string(),\n timestamp: TimestampSchema,\n});\n\n/**\n * LIST_RESOLVERS: Client requests list of registered resolvers.\n */\nexport const ListResolversRequestSchema = z.object({\n type: z.literal('LIST_RESOLVERS'),\n requestId: z.string(),\n mapName: z.string().optional(),\n});\n\n/**\n * LIST_RESOLVERS_RESPONSE: Server responds with registered resolvers.\n */\nexport const ListResolversResponseSchema = z.object({\n type: z.literal('LIST_RESOLVERS_RESPONSE'),\n requestId: z.string(),\n resolvers: z.array(z.object({\n mapName: z.string(),\n name: z.string(),\n priority: z.number().optional(),\n keyPattern: z.string().optional(),\n })),\n});\n\n// --- Write Concern Response Schemas (Phase 5.01) ---\n\n/**\n * Individual operation result within a batch ACK\n */\nexport const OpResultSchema = z.object({\n opId: z.string(),\n success: z.boolean(),\n achievedLevel: WriteConcernSchema,\n error: z.string().optional(),\n});\n\n/**\n * OP_ACK: Server acknowledges write operations\n * Extended to support Write Concern levels\n */\nexport const OpAckMessageSchema = z.object({\n type: z.literal('OP_ACK'),\n payload: z.object({\n /** ID of the last operation in the batch (for backwards compatibility) */\n lastId: z.string(),\n /** Write Concern level achieved (for simple ACKs) */\n achievedLevel: WriteConcernSchema.optional(),\n /** Per-operation results (for batch operations with mixed Write Concern) */\n results: z.array(OpResultSchema).optional(),\n }),\n});\n\n/**\n * OP_REJECTED: Server rejects a write operation\n */\nexport const OpRejectedMessageSchema = z.object({\n type: z.literal('OP_REJECTED'),\n payload: z.object({\n /** Operation ID that was rejected */\n opId: z.string(),\n /** Reason for rejection */\n reason: z.string(),\n /** Error code */\n code: z.number().optional(),\n }),\n});\n\n// --- Distributed Live Subscriptions Messages (Phase 14.2) ---\n\n/**\n * CLUSTER_SUB_REGISTER - Register a distributed subscription on a node.\n * Sent from coordinator to data-owning nodes for both FTS and Query subscriptions.\n */\nexport const ClusterSubRegisterPayloadSchema = z.object({\n /** Unique subscription ID */\n subscriptionId: z.string(),\n /** Node ID of the coordinator (receives updates) */\n coordinatorNodeId: z.string(),\n /** Map name to subscribe to */\n mapName: z.string(),\n /** Subscription type */\n type: z.enum(['SEARCH', 'QUERY']),\n\n // For FTS subscriptions\n /** Search query string (for SEARCH type) */\n searchQuery: z.string().optional(),\n /** Search options (for SEARCH type) */\n searchOptions: z.object({\n limit: z.number().int().positive().optional(),\n minScore: z.number().optional(),\n boost: z.record(z.string(), z.number()).optional(),\n }).optional(),\n\n // For Query subscriptions\n /** Query predicate (for QUERY type) */\n queryPredicate: z.any().optional(),\n /** Query sort order (for QUERY type) */\n querySort: z.record(z.string(), z.enum(['asc', 'desc'])).optional(),\n});\n\nexport const ClusterSubRegisterMessageSchema = z.object({\n type: z.literal('CLUSTER_SUB_REGISTER'),\n payload: ClusterSubRegisterPayloadSchema,\n});\n\n/**\n * CLUSTER_SUB_ACK - Acknowledgment of subscription registration with initial results.\n * Sent from data node back to coordinator.\n */\nexport const ClusterSubAckPayloadSchema = z.object({\n /** Correlates to subscriptionId */\n subscriptionId: z.string(),\n /** Node that registered this subscription */\n nodeId: z.string(),\n /** Registration success status */\n success: z.boolean(),\n /** Error message if failed */\n error: z.string().optional(),\n /** Initial results from this node */\n initialResults: z.array(z.object({\n key: z.string(),\n value: z.unknown(),\n score: z.number().optional(),\n matchedTerms: z.array(z.string()).optional(),\n })).optional(),\n /** Total matching documents on this node */\n totalHits: z.number().int().nonnegative().optional(),\n});\n\nexport const ClusterSubAckMessageSchema = z.object({\n type: z.literal('CLUSTER_SUB_ACK'),\n payload: ClusterSubAckPayloadSchema,\n});\n\n/**\n * CLUSTER_SUB_UPDATE - Delta update from a data node to coordinator.\n * Sent when a document enters/updates/leaves the subscription result set.\n */\nexport const ClusterSubUpdatePayloadSchema = z.object({\n /** Subscription ID this update belongs to */\n subscriptionId: z.string(),\n /** Node that produced this update */\n sourceNodeId: z.string(),\n /** Document key */\n key: z.string(),\n /** Document value (null for LEAVE) */\n value: z.unknown(),\n /** Search score (for SEARCH type) */\n score: z.number().optional(),\n /** Matched terms (for SEARCH type) */\n matchedTerms: z.array(z.string()).optional(),\n /** Change type: ENTER (new match), UPDATE (still matches), LEAVE (no longer matches) */\n changeType: z.enum(['ENTER', 'UPDATE', 'LEAVE']),\n /** Timestamp for ordering */\n timestamp: z.number(),\n});\n\nexport const ClusterSubUpdateMessageSchema = z.object({\n type: z.literal('CLUSTER_SUB_UPDATE'),\n payload: ClusterSubUpdatePayloadSchema,\n});\n\n/**\n * CLUSTER_SUB_UNREGISTER - Remove a subscription from a node.\n * Sent from coordinator to data-owning nodes when client unsubscribes.\n */\nexport const ClusterSubUnregisterPayloadSchema = z.object({\n /** Subscription ID to remove */\n subscriptionId: z.string(),\n});\n\nexport const ClusterSubUnregisterMessageSchema = z.object({\n type: z.literal('CLUSTER_SUB_UNREGISTER'),\n payload: ClusterSubUnregisterPayloadSchema,\n});\n\n// --- Union Schema ---\n\nexport const MessageSchema = z.discriminatedUnion('type', [\n AuthMessageSchema,\n QuerySubMessageSchema,\n QueryUnsubMessageSchema,\n ClientOpMessageSchema,\n OpBatchMessageSchema,\n SyncInitMessageSchema,\n SyncRespRootMessageSchema,\n SyncRespBucketsMessageSchema,\n SyncRespLeafMessageSchema,\n MerkleReqBucketMessageSchema,\n LockRequestSchema,\n LockReleaseSchema,\n TopicSubSchema,\n TopicUnsubSchema,\n TopicPubSchema,\n PingMessageSchema,\n PongMessageSchema,\n // ORMap Sync Messages\n ORMapSyncInitSchema,\n ORMapSyncRespRootSchema,\n ORMapSyncRespBucketsSchema,\n ORMapMerkleReqBucketSchema,\n ORMapSyncRespLeafSchema,\n ORMapDiffRequestSchema,\n ORMapDiffResponseSchema,\n ORMapPushDiffSchema,\n // Phase 4: Partition Map\n PartitionMapRequestSchema,\n // Phase 5.2: PN Counter\n CounterRequestSchema,\n CounterSyncSchema,\n // Phase 5.03: Entry Processor\n EntryProcessRequestSchema,\n EntryProcessBatchRequestSchema,\n EntryProcessResponseSchema,\n EntryProcessBatchResponseSchema,\n // Phase 5.04: Event Journal\n JournalSubscribeRequestSchema,\n JournalUnsubscribeRequestSchema,\n JournalEventMessageSchema,\n JournalReadRequestSchema,\n JournalReadResponseSchema,\n // Phase 5.05: Conflict Resolver\n RegisterResolverRequestSchema,\n RegisterResolverResponseSchema,\n UnregisterResolverRequestSchema,\n UnregisterResolverResponseSchema,\n MergeRejectedMessageSchema,\n ListResolversRequestSchema,\n ListResolversResponseSchema,\n // Phase 11.1: Full-Text Search\n SearchMessageSchema,\n SearchRespMessageSchema,\n // Phase 11.1b: Live Search Subscriptions\n SearchSubMessageSchema,\n SearchUpdateMessageSchema,\n SearchUnsubMessageSchema,\n // Phase 14.2: Distributed Live Subscriptions (cluster-internal)\n ClusterSubRegisterMessageSchema,\n ClusterSubAckMessageSchema,\n ClusterSubUpdateMessageSchema,\n ClusterSubUnregisterMessageSchema,\n]);\n\n// --- Type Inference ---\n\nexport type Timestamp = z.infer<typeof TimestampSchema>;\nexport type LWWRecord<V = any> = z.infer<typeof LWWRecordSchema>; // Generic placeholder\nexport type ORMapRecord<V = any> = z.infer<typeof ORMapRecordSchema>; // Generic placeholder\n// export type PredicateNode = z.infer<typeof PredicateNodeSchema>; // Conflict with predicate.ts\nexport type Query = z.infer<typeof QuerySchema>;\nexport type ClientOp = z.infer<typeof ClientOpSchema>;\nexport type Message = z.infer<typeof MessageSchema>;\nexport type PingMessage = z.infer<typeof PingMessageSchema>;\nexport type PongMessage = z.infer<typeof PongMessageSchema>;\nexport type BatchMessage = z.infer<typeof BatchMessageSchema>;\n\n// Write Concern types (Phase 5.01)\nexport type OpAckMessage = z.infer<typeof OpAckMessageSchema>;\nexport type OpRejectedMessage = z.infer<typeof OpRejectedMessageSchema>;\nexport type OpResult = z.infer<typeof OpResultSchema>;\n\n// Entry Processor types (Phase 5.03)\nexport type EntryProcessRequest = z.infer<typeof EntryProcessRequestSchema>;\nexport type EntryProcessBatchRequest = z.infer<typeof EntryProcessBatchRequestSchema>;\nexport type EntryProcessResponse = z.infer<typeof EntryProcessResponseSchema>;\nexport type EntryProcessBatchResponse = z.infer<typeof EntryProcessBatchResponseSchema>;\nexport type EntryProcessKeyResult = z.infer<typeof EntryProcessKeyResultSchema>;\n\n// Event Journal types (Phase 5.04)\nexport type JournalEventType = z.infer<typeof JournalEventTypeSchema>;\nexport type JournalEventData = z.infer<typeof JournalEventDataSchema>;\nexport type JournalSubscribeRequest = z.infer<typeof JournalSubscribeRequestSchema>;\nexport type JournalUnsubscribeRequest = z.infer<typeof JournalUnsubscribeRequestSchema>;\nexport type JournalEventMessage = z.infer<typeof JournalEventMessageSchema>;\nexport type JournalReadRequest = z.infer<typeof JournalReadRequestSchema>;\nexport type JournalReadResponse = z.infer<typeof JournalReadResponseSchema>;\n\n// Conflict Resolver types (Phase 5.05)\nexport type ConflictResolver = z.infer<typeof ConflictResolverSchema>;\nexport type RegisterResolverRequest = z.infer<typeof RegisterResolverRequestSchema>;\nexport type RegisterResolverResponse = z.infer<typeof RegisterResolverResponseSchema>;\nexport type UnregisterResolverRequest = z.infer<typeof UnregisterResolverRequestSchema>;\nexport type UnregisterResolverResponse = z.infer<typeof UnregisterResolverResponseSchema>;\nexport type MergeRejectedMessage = z.infer<typeof MergeRejectedMessageSchema>;\nexport type ListResolversRequest = z.infer<typeof ListResolversRequestSchema>;\nexport type ListResolversResponse = z.infer<typeof ListResolversResponseSchema>;\n\n// Full-Text Search types (Phase 11.1)\nexport type SearchOptions = z.infer<typeof SearchOptionsSchema>;\nexport type SearchPayload = z.infer<typeof SearchPayloadSchema>;\nexport type SearchMessage = z.infer<typeof SearchMessageSchema>;\nexport type SearchRespPayload = z.infer<typeof SearchRespPayloadSchema>;\nexport type SearchRespMessage = z.infer<typeof SearchRespMessageSchema>;\n\n// Live Search Subscription types (Phase 11.1b)\nexport type SearchUpdateType = z.infer<typeof SearchUpdateTypeSchema>;\nexport type SearchSubPayload = z.infer<typeof SearchSubPayloadSchema>;\nexport type SearchSubMessage = z.infer<typeof SearchSubMessageSchema>;\nexport type SearchUpdatePayload = z.infer<typeof SearchUpdatePayloadSchema>;\nexport type SearchUpdateMessage = z.infer<typeof SearchUpdateMessageSchema>;\nexport type SearchUnsubPayload = z.infer<typeof SearchUnsubPayloadSchema>;\nexport type SearchUnsubMessage = z.infer<typeof SearchUnsubMessageSchema>;\n\n// --- Distributed Search Messages (Phase 14) ---\n\n/**\n * CLUSTER_SEARCH_REQ: Broadcast search request to cluster nodes.\n * Sent from coordinator to data-owning nodes.\n */\nexport const ClusterSearchReqPayloadSchema = z.object({\n /** Unique request ID for correlation */\n requestId: z.string(),\n /** Map name to search */\n mapName: z.string(),\n /** Search query text */\n query: z.string(),\n /** Search options */\n options: z.object({\n /** Maximum results per node (for Top-K) */\n limit: z.number().int().positive().max(1000),\n /** Minimum score threshold */\n minScore: z.number().optional(),\n /** Fields to boost */\n boost: z.record(z.string(), z.number()).optional(),\n /** Include matched terms in response */\n includeMatchedTerms: z.boolean().optional(),\n /** For cursor-based pagination: return results after this score */\n afterScore: z.number().optional(),\n /** For cursor-based pagination: return results after this key (tie-breaking) */\n afterKey: z.string().optional(),\n }),\n /** Timeout in milliseconds */\n timeoutMs: z.number().int().positive().optional(),\n});\n\nexport const ClusterSearchReqMessageSchema = z.object({\n type: z.literal('CLUSTER_SEARCH_REQ'),\n payload: ClusterSearchReqPayloadSchema,\n});\n\n/**\n * CLUSTER_SEARCH_RESP: Response from a node with local search results.\n */\nexport const ClusterSearchRespPayloadSchema = z.object({\n /** Correlates to requestId */\n requestId: z.string(),\n /** Node that produced these results */\n nodeId: z.string(),\n /** Search results with scores */\n results: z.array(z.object({\n key: z.string(),\n value: z.unknown(),\n score: z.number(),\n matchedTerms: z.array(z.string()).optional(),\n })),\n /** Total matching documents on this node (for pagination) */\n totalHits: z.number().int().nonnegative(),\n /** Execution time on this node in ms (for monitoring) */\n executionTimeMs: z.number().nonnegative(),\n /** Error if search failed on this node */\n error: z.string().optional(),\n});\n\nexport const ClusterSearchRespMessageSchema = z.object({\n type: z.literal('CLUSTER_SEARCH_RESP'),\n payload: ClusterSearchRespPayloadSchema,\n});\n\n/**\n * CLUSTER_SEARCH_SUBSCRIBE: Live distributed search subscription.\n */\nexport const ClusterSearchSubscribePayloadSchema = z.object({\n subscriptionId: z.string(),\n mapName: z.string(),\n query: z.string(),\n options: SearchOptionsSchema.optional(),\n});\n\nexport const ClusterSearchSubscribeMessageSchema = z.object({\n type: z.literal('CLUSTER_SEARCH_SUBSCRIBE'),\n payload: ClusterSearchSubscribePayloadSchema,\n});\n\n/**\n * CLUSTER_SEARCH_UNSUBSCRIBE: Unsubscribe from distributed search.\n */\nexport const ClusterSearchUnsubscribePayloadSchema = z.object({\n subscriptionId: z.string(),\n});\n\nexport const ClusterSearchUnsubscribeMessageSchema = z.object({\n type: z.literal('CLUSTER_SEARCH_UNSUBSCRIBE'),\n payload: ClusterSearchUnsubscribePayloadSchema,\n});\n\n/**\n * CLUSTER_SEARCH_UPDATE: Delta update for live distributed search.\n */\nexport const ClusterSearchUpdatePayloadSchema = z.object({\n subscriptionId: z.string(),\n nodeId: z.string(),\n key: z.string(),\n value: z.unknown(),\n score: z.number(),\n matchedTerms: z.array(z.string()).optional(),\n type: SearchUpdateTypeSchema,\n});\n\nexport const ClusterSearchUpdateMessageSchema = z.object({\n type: z.literal('CLUSTER_SEARCH_UPDATE'),\n payload: ClusterSearchUpdatePayloadSchema,\n});\n\n// Distributed Search types (Phase 14)\nexport type ClusterSearchReqPayload = z.infer<typeof ClusterSearchReqPayloadSchema>;\nexport type ClusterSearchReqMessage = z.infer<typeof ClusterSearchReqMessageSchema>;\nexport type ClusterSearchRespPayload = z.infer<typeof ClusterSearchRespPayloadSchema>;\nexport type ClusterSearchRespMessage = z.infer<typeof ClusterSearchRespMessageSchema>;\nexport type ClusterSearchSubscribePayload = z.infer<typeof ClusterSearchSubscribePayloadSchema>;\nexport type ClusterSearchSubscribeMessage = z.infer<typeof ClusterSearchSubscribeMessageSchema>;\nexport type ClusterSearchUnsubscribePayload = z.infer<typeof ClusterSearchUnsubscribePayloadSchema>;\nexport type ClusterSearchUnsubscribeMessage = z.infer<typeof ClusterSearchUnsubscribeMessageSchema>;\nexport type ClusterSearchUpdatePayload = z.infer<typeof ClusterSearchUpdatePayloadSchema>;\nexport type ClusterSearchUpdateMessage = z.infer<typeof ClusterSearchUpdateMessageSchema>;\n\n// Distributed Live Subscriptions types (Phase 14.2)\nexport type ClusterSubRegisterPayload = z.infer<typeof ClusterSubRegisterPayloadSchema>;\nexport type ClusterSubRegisterMessage = z.infer<typeof ClusterSubRegisterMessageSchema>;\nexport type ClusterSubAckPayload = z.infer<typeof ClusterSubAckPayloadSchema>;\nexport type ClusterSubAckMessage = z.infer<typeof ClusterSubAckMessageSchema>;\nexport type ClusterSubUpdatePayload = z.infer<typeof ClusterSubUpdatePayloadSchema>;\nexport type ClusterSubUpdateMessage = z.infer<typeof ClusterSubUpdateMessageSchema>;\nexport type ClusterSubUnregisterPayload = z.infer<typeof ClusterSubUnregisterPayloadSchema>;\nexport type ClusterSubUnregisterMessage = z.infer<typeof ClusterSubUnregisterMessageSchema>;\n\n// Query Response types (Phase 14.1)\nexport type CursorStatus = z.infer<typeof CursorStatusSchema>;\nexport type QueryRespPayload = z.infer<typeof QueryRespPayloadSchema>;\nexport type QueryRespMessage = z.infer<typeof QueryRespMessageSchema>;\n","/**\n * Write Concern - Configurable Acknowledgment Levels\n *\n * Write Concern defines when a write operation is considered successful.\n * Similar to MongoDB's writeConcern, Kafka's acks, and Cassandra's consistency levels.\n */\n\n/**\n * Write Concern levels - determines when an operation is acknowledged.\n *\n * Levels are ordered by durability guarantee (lowest to highest):\n * FIRE_AND_FORGET < MEMORY < APPLIED < REPLICATED < PERSISTED\n */\nexport enum WriteConcern {\n /**\n * FIRE_AND_FORGET (acks=0)\n * - ACK sent immediately after server receives the message\n * - Operation may be lost if server crashes before processing\n * - Maximum throughput, minimum latency\n * - Use case: metrics, logs, non-critical data\n */\n FIRE_AND_FORGET = 'FIRE_AND_FORGET',\n\n /**\n * MEMORY (acks=1, default) - current Early ACK behavior\n * - ACK sent after validation and queuing for processing\n * - Operation is in memory but not yet applied to CRDT\n * - Use case: most operations, real-time updates\n */\n MEMORY = 'MEMORY',\n\n /**\n * APPLIED\n * - ACK sent after operation is applied to CRDT in memory\n * - Data is readable on this node immediately after ACK\n * - Use case: operations requiring immediate consistency on the node\n */\n APPLIED = 'APPLIED',\n\n /**\n * REPLICATED\n * - ACK sent after operation is broadcast to cluster (CLUSTER_EVENT sent)\n * - Data survives primary node failure\n * - Use case: important data requiring cluster durability\n */\n REPLICATED = 'REPLICATED',\n\n /**\n * PERSISTED\n * - ACK sent after operation is written to storage on primary node\n * - Data survives node restart\n * - Use case: critical data (financial transactions, audit logs)\n */\n PERSISTED = 'PERSISTED',\n}\n\n/**\n * Default timeout for Write Concern acknowledgments (ms)\n */\nexport const DEFAULT_WRITE_CONCERN_TIMEOUT = 5000;\n\n/**\n * Write options for PUT/REMOVE operations\n */\nexport interface WriteOptions {\n /**\n * Write acknowledgment level.\n * @default WriteConcern.MEMORY\n */\n writeConcern?: WriteConcern;\n\n /**\n * Timeout for waiting for acknowledgment (ms).\n * Applies to APPLIED, REPLICATED, PERSISTED levels.\n * @default 5000\n */\n timeout?: number;\n}\n\n/**\n * Result of a write operation\n */\nexport interface WriteResult {\n /** Whether the operation achieved the requested Write Concern level */\n success: boolean;\n\n /** Operation ID */\n opId: string;\n\n /** The Write Concern level actually achieved */\n achievedLevel: WriteConcern;\n\n /** Time taken to achieve the level (ms) */\n latencyMs: number;\n\n /** Error message if success=false */\n error?: string;\n}\n\n/**\n * Internal structure for tracking pending write acknowledgments\n */\nexport interface PendingWrite {\n /** Operation ID */\n opId: string;\n\n /** Target Write Concern level */\n writeConcern: WriteConcern;\n\n /** Timestamp when operation was registered */\n timestamp: number;\n\n /** Timeout duration (ms) */\n timeout: number;\n\n /** Promise resolve callback */\n resolve: (result: WriteResult) => void;\n\n /** Promise reject callback */\n reject: (error: Error) => void;\n\n /** Timeout handle for cleanup */\n timeoutHandle?: ReturnType<typeof setTimeout>;\n\n /** Set of levels that have been achieved */\n achievedLevels: Set<WriteConcern>;\n}\n\n/**\n * Ordered list of Write Concern levels (lowest to highest)\n */\nexport const WRITE_CONCERN_ORDER: readonly WriteConcern[] = [\n WriteConcern.FIRE_AND_FORGET,\n WriteConcern.MEMORY,\n WriteConcern.APPLIED,\n WriteConcern.REPLICATED,\n WriteConcern.PERSISTED,\n] as const;\n\n/**\n * Check if a target Write Concern level is achieved based on achieved levels.\n *\n * @param achieved - Set of achieved Write Concern levels\n * @param target - Target Write Concern level to check\n * @returns true if target level (or higher) is achieved\n */\nexport function isWriteConcernAchieved(\n achieved: Set<WriteConcern>,\n target: WriteConcern\n): boolean {\n const targetIndex = WRITE_CONCERN_ORDER.indexOf(target);\n const achievedIndex = Math.max(\n ...Array.from(achieved).map((l) => WRITE_CONCERN_ORDER.indexOf(l))\n );\n return achievedIndex >= targetIndex;\n}\n\n/**\n * Get the highest achieved Write Concern level from a set of achieved levels.\n *\n * @param achieved - Set of achieved Write Concern levels\n * @returns The highest achieved level\n */\nexport function getHighestWriteConcernLevel(\n achieved: Set<WriteConcern>\n): WriteConcern {\n for (let i = WRITE_CONCERN_ORDER.length - 1; i >= 0; i--) {\n if (achieved.has(WRITE_CONCERN_ORDER[i])) {\n return WRITE_CONCERN_ORDER[i];\n }\n }\n return WriteConcern.FIRE_AND_FORGET;\n}\n","/**\n * Cluster types for Phase 4: Clustering Improvements\n *\n * These types are shared between client and server packages\n * for partition-aware routing and cluster communication.\n */\n\n// ============================================\n// Node and Cluster Status\n// ============================================\n\nexport type NodeStatus = 'ACTIVE' | 'JOINING' | 'LEAVING' | 'SUSPECTED' | 'FAILED';\n\nexport interface NodeInfo {\n nodeId: string;\n endpoints: {\n websocket: string; // ws://host:port or wss://host:port\n http?: string; // Optional REST endpoint\n };\n status: NodeStatus;\n}\n\n// ============================================\n// Partition Map\n// ============================================\n\nexport interface PartitionInfo {\n partitionId: number;\n ownerNodeId: string;\n backupNodeIds: string[];\n}\n\nexport interface PartitionMap {\n version: number; // Incremented on topology change\n partitionCount: number; // 271 by default\n nodes: NodeInfo[];\n partitions: PartitionInfo[];\n generatedAt: number; // Timestamp when map was generated\n}\n\n// ============================================\n// Partition Map Protocol Messages\n// ============================================\n\nexport interface PartitionMapMessage {\n type: 'PARTITION_MAP';\n payload: PartitionMap;\n}\n\nexport interface PartitionMapRequestMessage {\n type: 'PARTITION_MAP_REQUEST';\n payload?: {\n currentVersion?: number;\n };\n}\n\nexport interface PartitionChange {\n partitionId: number;\n previousOwner: string;\n newOwner: string;\n reason: 'REBALANCE' | 'FAILOVER' | 'JOIN' | 'LEAVE';\n}\n\nexport interface PartitionMapDeltaMessage {\n type: 'PARTITION_MAP_DELTA';\n payload: {\n version: number;\n previousVersion: number;\n changes: PartitionChange[];\n timestamp: number;\n };\n}\n\n// ============================================\n// Routing Errors\n// ============================================\n\nexport interface NotOwnerError {\n code: 'NOT_OWNER';\n message: string;\n hint: {\n partitionId: number;\n currentOwner: string;\n mapVersion: number;\n };\n}\n\nexport interface StaleMapError {\n code: 'STALE_MAP';\n message: string;\n hint: {\n clientVersion: number;\n serverVersion: number;\n };\n}\n\nexport type RoutingError = NotOwnerError | StaleMapError;\n\n// ============================================\n// Connection Pool Configuration\n// ============================================\n\nexport interface ConnectionPoolConfig {\n /** Maximum connections per node (default: 1) */\n maxConnectionsPerNode: number;\n /** Connection timeout in ms (default: 5000) */\n connectionTimeoutMs: number;\n /** Health check interval in ms (default: 10000) */\n healthCheckIntervalMs: number;\n /** Reconnect delay base in ms (default: 1000) */\n reconnectDelayMs: number;\n /** Maximum reconnect delay in ms (default: 30000) */\n maxReconnectDelayMs: number;\n /** Maximum reconnect attempts before marking unhealthy (default: 5) */\n maxReconnectAttempts: number;\n}\n\nexport const DEFAULT_CONNECTION_POOL_CONFIG: ConnectionPoolConfig = {\n maxConnectionsPerNode: 1,\n connectionTimeoutMs: 5000,\n healthCheckIntervalMs: 10000,\n reconnectDelayMs: 1000,\n maxReconnectDelayMs: 30000,\n maxReconnectAttempts: 5,\n};\n\n// ============================================\n// Partition Router Configuration\n// ============================================\n\nexport interface PartitionRouterConfig {\n /** Fallback mode when routing fails: 'forward' uses primary, 'error' throws */\n fallbackMode: 'forward' | 'error';\n /** How often to refresh stale partition map in ms (default: 30000) */\n mapRefreshIntervalMs: number;\n /** Max staleness before forcing refresh in ms (default: 60000) */\n maxMapStalenessMs: number;\n}\n\nexport const DEFAULT_PARTITION_ROUTER_CONFIG: PartitionRouterConfig = {\n fallbackMode: 'forward',\n mapRefreshIntervalMs: 30000,\n maxMapStalenessMs: 60000,\n};\n\n// ============================================\n// Cluster Client Configuration\n// ============================================\n\n/**\n * Circuit breaker configuration.\n */\nexport interface CircuitBreakerConfig {\n /** Number of failures before opening circuit (default: 5) */\n failureThreshold: number;\n /** Time in ms before attempting to close circuit (default: 30000) */\n resetTimeoutMs: number;\n}\n\nexport const DEFAULT_CIRCUIT_BREAKER_CONFIG: CircuitBreakerConfig = {\n failureThreshold: 5,\n resetTimeoutMs: 30000,\n};\n\nexport interface ClusterClientConfig {\n /** Enable cluster mode */\n enabled: boolean;\n /** Initial seed nodes to connect to */\n seedNodes: string[];\n /** Routing mode: 'direct' routes to owner, 'forward' uses server forwarding */\n routingMode: 'direct' | 'forward';\n /** Connection pool configuration */\n connectionPool?: Partial<ConnectionPoolConfig>;\n /** Partition router configuration */\n routing?: Partial<PartitionRouterConfig>;\n /** Circuit breaker configuration */\n circuitBreaker?: Partial<CircuitBreakerConfig>;\n}\n\n// ============================================\n// Node Health\n// ============================================\n\nexport type ConnectionState =\n | 'DISCONNECTED'\n | 'CONNECTING'\n | 'CONNECTED'\n | 'AUTHENTICATED'\n | 'RECONNECTING'\n | 'FAILED';\n\nexport interface NodeHealth {\n nodeId: string;\n state: ConnectionState;\n lastSeen: number;\n latencyMs: number;\n reconnectAttempts: number;\n}\n\n// ============================================\n// Cluster Events (for EventEmitter)\n// ============================================\n\nexport interface ClusterEvents {\n 'node:connected': { nodeId: string };\n 'node:disconnected': { nodeId: string; reason: string };\n 'node:healthy': { nodeId: string };\n 'node:unhealthy': { nodeId: string; reason: string };\n 'partitionMap:updated': { version: number; changesCount: number };\n 'partitionMap:stale': { currentVersion: number; lastRefresh: number };\n 'routing:miss': { key: string; expectedOwner: string; actualOwner: string };\n}\n\n// ============================================\n// Migration State Machine (Task 03)\n// ============================================\n\nexport enum PartitionState {\n STABLE = 'STABLE', // Normal operation\n MIGRATING = 'MIGRATING', // Data being transferred\n SYNC = 'SYNC', // Verifying consistency\n FAILED = 'FAILED', // Migration failed, needs retry\n}\n\nexport interface PartitionMigration {\n partitionId: number;\n state: PartitionState;\n sourceNode: string;\n targetNode: string;\n startTime: number;\n bytesTransferred: number;\n totalBytes: number;\n retryCount: number;\n}\n\nexport interface MigrationConfig {\n /** Partitions per batch (default: 10) */\n batchSize: number;\n /** Delay between batches in ms (default: 5000) */\n batchIntervalMs: number;\n /** Bytes per chunk (default: 64KB) */\n transferChunkSize: number;\n /** Retries per partition (default: 3) */\n maxRetries: number;\n /** Sync phase timeout in ms (default: 30000) */\n syncTimeoutMs: number;\n /** Concurrent transfers (default: 4) */\n parallelTransfers: number;\n}\n\nexport const DEFAULT_MIGRATION_CONFIG: MigrationConfig = {\n batchSize: 10,\n batchIntervalMs: 5000,\n transferChunkSize: 65536, // 64KB\n maxRetries: 3,\n syncTimeoutMs: 30000,\n parallelTransfers: 4,\n};\n\nexport interface MigrationStatus {\n inProgress: boolean;\n active: PartitionMigration[];\n queued: number;\n completed: number;\n failed: number;\n estimatedTimeRemainingMs: number;\n}\n\nexport interface MigrationMetrics {\n migrationsStarted: number;\n migrationsCompleted: number;\n migrationsFailed: number;\n chunksTransferred: number;\n bytesTransferred: number;\n activeMigrations: number;\n queuedMigrations: number;\n}\n\n// ============================================\n// Migration Protocol Messages (Task 03)\n// ============================================\n\nexport interface MigrationStartMessage {\n type: 'MIGRATION_START';\n payload: {\n partitionId: number;\n sourceNode: string;\n estimatedSize: number;\n };\n}\n\nexport interface MigrationChunkMessage {\n type: 'MIGRATION_CHUNK';\n payload: {\n partitionId: number;\n chunkIndex: number;\n totalChunks: number;\n data: Uint8Array;\n checksum: string;\n };\n}\n\nexport interface MigrationChunkAckMessage {\n type: 'MIGRATION_CHUNK_ACK';\n payload: {\n partitionId: number;\n chunkIndex: number;\n success: boolean;\n };\n}\n\nexport interface MigrationCompleteMessage {\n type: 'MIGRATION_COMPLETE';\n payload: {\n partitionId: number;\n totalRecords: number;\n checksum: string;\n };\n}\n\nexport interface MigrationVerifyMessage {\n type: 'MIGRATION_VERIFY';\n payload: {\n partitionId: number;\n success: boolean;\n checksumMatch: boolean;\n };\n}\n\nexport type MigrationMessage =\n | MigrationStartMessage\n | MigrationChunkMessage\n | MigrationChunkAckMessage\n | MigrationCompleteMessage\n | MigrationVerifyMessage;\n\n// ============================================\n// Consistency Levels (Task 04)\n// ============================================\n\nexport enum ConsistencyLevel {\n /** Wait for all replicas (owner + all backups) */\n STRONG = 'STRONG',\n /** Wait for majority (owner + N/2 backups) */\n QUORUM = 'QUORUM',\n /** Acknowledge after owner write only, background replication */\n EVENTUAL = 'EVENTUAL',\n}\n\nexport interface WriteOptions {\n consistency?: ConsistencyLevel;\n /** Replication timeout in ms */\n timeout?: number;\n}\n\nexport interface ReadOptions {\n consistency?: ConsistencyLevel;\n /** Read from backup if owner unavailable */\n allowStale?: boolean;\n /** Max acceptable lag in ms */\n maxStaleness?: number;\n}\n\n// ============================================\n// Replication Configuration (Task 04)\n// ============================================\n\nexport interface ReplicationConfig {\n defaultConsistency: ConsistencyLevel;\n /** Max queued operations (default: 10000) */\n queueSizeLimit: number;\n /** Operations per batch (default: 100) */\n batchSize: number;\n /** Batch flush interval in ms (default: 50) */\n batchIntervalMs: number;\n /** Ack timeout in ms (default: 5000) */\n ackTimeoutMs: number;\n /** Retries before marking node unhealthy (default: 3) */\n maxRetries: number;\n}\n\nexport const DEFAULT_REPLICATION_CONFIG: ReplicationConfig = {\n defaultConsistency: ConsistencyLevel.EVENTUAL,\n queueSizeLimit: 10000,\n batchSize: 100,\n batchIntervalMs: 50,\n ackTimeoutMs: 5000,\n maxRetries: 3,\n};\n\nexport interface ReplicationTask {\n opId: string;\n operation: unknown; // Will be typed more specifically in server\n consistency: ConsistencyLevel;\n timestamp: number;\n retryCount: number;\n}\n\nexport interface ReplicationLag {\n /** Current lag in ms */\n current: number;\n /** Average lag */\n avg: number;\n /** Maximum observed lag */\n max: number;\n /** 99th percentile lag */\n percentile99: number;\n}\n\nexport interface ReplicationHealth {\n healthy: boolean;\n unhealthyNodes: string[];\n laggyNodes: string[];\n avgLagMs: number;\n}\n\nexport interface ReplicationResult {\n success: boolean;\n ackedBy: string[];\n}\n\n// ============================================\n// Replication Protocol Messages (Task 04)\n// ============================================\n\nexport interface ReplicationMessage {\n type: 'REPLICATION';\n payload: {\n opId: string;\n operation: unknown;\n consistency: ConsistencyLevel;\n };\n}\n\nexport interface ReplicationBatchMessage {\n type: 'REPLICATION_BATCH';\n payload: {\n operations: unknown[];\n opIds: string[];\n };\n}\n\nexport interface ReplicationAckMessage {\n type: 'REPLICATION_ACK';\n payload: {\n opId: string;\n success: boolean;\n timestamp: number;\n };\n}\n\nexport interface ReplicationBatchAckMessage {\n type: 'REPLICATION_BATCH_ACK';\n payload: {\n opIds: string[];\n success: boolean;\n timestamp: number;\n };\n}\n\nexport type ReplicationProtocolMessage =\n | ReplicationMessage\n | ReplicationBatchMessage\n | ReplicationAckMessage\n | ReplicationBatchAckMessage;\n\n// ============================================\n// Constants\n// ============================================\n\nexport const PARTITION_COUNT = 271;\nexport const DEFAULT_BACKUP_COUNT = 1;\n","/**\n * Type-safe wrapper over sorted-btree for use in NavigableIndex\n *\n * Provides O(log N) operations for:\n * - set/get/delete\n * - range queries\n * - greaterThan/lessThan queries\n */\n\nimport BTree from 'sorted-btree';\nimport { Comparator, RangeOptions, defaultComparator } from './types';\n\n/**\n * A sorted map implementation backed by a B+ tree.\n * Provides efficient range queries and ordered iteration.\n *\n * @template K - Key type (must be comparable)\n * @template V - Value type\n */\nexport class SortedMap<K, V> {\n private readonly tree: BTree<K, V>;\n private readonly comparator: Comparator<K>;\n\n constructor(comparator?: Comparator<K>) {\n this.comparator = comparator ?? (defaultComparator as Comparator<K>);\n this.tree = new BTree<K, V>(undefined, this.comparator);\n }\n\n /**\n * Set a key-value pair. Updates existing key if present.\n * Time complexity: O(log N)\n */\n set(key: K, value: V): this {\n this.tree.set(key, value);\n return this;\n }\n\n /**\n * Get the value for a key.\n * Time complexity: O(log N)\n */\n get(key: K): V | undefined {\n return this.tree.get(key);\n }\n\n /**\n * Delete a key from the map.\n * Time complexity: O(log N)\n * @returns true if the key existed and was deleted\n */\n delete(key: K): boolean {\n return this.tree.delete(key);\n }\n\n /**\n * Check if a key exists in the map.\n * Time complexity: O(log N)\n */\n has(key: K): boolean {\n return this.tree.has(key);\n }\n\n /**\n * Get the number of entries in the map.\n */\n get size(): number {\n return this.tree.size;\n }\n\n /**\n * Check if the map is empty.\n */\n get isEmpty(): boolean {\n return this.tree.size === 0;\n }\n\n /**\n * Get the minimum key in the map.\n * Time complexity: O(log N)\n */\n minKey(): K | undefined {\n return this.tree.minKey();\n }\n\n /**\n * Get the maximum key in the map.\n * Time complexity: O(log N)\n */\n maxKey(): K | undefined {\n return this.tree.maxKey();\n }\n\n /**\n * Iterate over entries in a range [from, to).\n * Time complexity: O(log N + K) where K is the number of results\n *\n * @param from - Lower bound\n * @param to - Upper bound\n * @param options - Range options for inclusive/exclusive bounds\n */\n *range(from: K, to: K, options: RangeOptions = {}): IterableIterator<[K, V]> {\n const { fromInclusive = true, toInclusive = false } = options;\n\n // Validate range\n if (this.comparator(from, to) > 0) {\n return; // Empty range\n }\n\n // Use BTree's getRange which returns [key, value] pairs\n // getRange(lo, hi, includeHi) - lo is always inclusive\n const entries = this.tree.getRange(from, to, toInclusive);\n\n for (const [key, value] of entries) {\n // Skip from if not inclusive\n if (!fromInclusive && this.comparator(key, from) === 0) {\n continue;\n }\n yield [key, value];\n }\n }\n\n /**\n * Iterate over entries where key > value (or >= if inclusive).\n * Time complexity: O(log N + K) where K is the number of results\n *\n * @param key - Lower bound\n * @param inclusive - Include the bound in results (default: false)\n */\n *greaterThan(key: K, inclusive: boolean = false): IterableIterator<[K, V]> {\n // Find entries starting from key\n const entries = this.tree.entries(key);\n\n let first = true;\n for (const [k, v] of entries) {\n if (first) {\n first = false;\n // Skip the exact match if not inclusive\n if (!inclusive && this.comparator(k, key) === 0) {\n continue;\n }\n }\n yield [k, v];\n }\n }\n\n /**\n * Iterate over entries where key < value (or <= if inclusive).\n * Time complexity: O(log N + K) where K is the number of results\n *\n * Note: This method iterates from the beginning of the tree.\n * The O(log N) component is for finding the upper bound,\n * and O(K) is for yielding K results.\n *\n * @param key - Upper bound\n * @param inclusive - Include the bound in results (default: false)\n */\n *lessThan(key: K, inclusive: boolean = false): IterableIterator<[K, V]> {\n // Find the upper bound key\n const upperKey = inclusive ? this.floorKey(key) : this.lowerKey(key);\n\n if (upperKey === undefined) {\n return; // No keys less than the given key\n }\n\n // Use getRange from minKey to upperKey (inclusive)\n const minKey = this.tree.minKey();\n if (minKey === undefined) {\n return;\n }\n\n // getRange(lo, hi, includeHi) - returns entries in [lo, hi] or [lo, hi)\n const entries = this.tree.getRange(minKey, upperKey, true);\n for (const entry of entries) {\n yield entry;\n }\n }\n\n /**\n * Iterate over all entries in sorted order.\n * Time complexity: O(N)\n */\n *entries(): IterableIterator<[K, V]> {\n for (const entry of this.tree.entries()) {\n yield entry;\n }\n }\n\n /**\n * Iterate over all keys in sorted order.\n * Time complexity: O(N)\n */\n *keys(): IterableIterator<K> {\n for (const key of this.tree.keys()) {\n yield key;\n }\n }\n\n /**\n * Iterate over all values in sorted order.\n * Time complexity: O(N)\n */\n *values(): IterableIterator<V> {\n for (const value of this.tree.values()) {\n yield value;\n }\n }\n\n /**\n * Iterate over entries in reverse sorted order.\n * Time complexity: O(N)\n */\n *entriesReversed(): IterableIterator<[K, V]> {\n for (const entry of this.tree.entriesReversed()) {\n yield entry;\n }\n }\n\n /**\n * Remove all entries from the map.\n */\n clear(): void {\n this.tree.clear();\n }\n\n /**\n * Execute a callback for each entry in sorted order.\n */\n forEach(callback: (value: V, key: K, map: this) => void): void {\n this.tree.forEach((value, key) => {\n callback(value, key, this);\n });\n }\n\n /**\n * Create a new SortedMap from entries.\n */\n static from<K, V>(\n entries: Iterable<[K, V]>,\n comparator?: Comparator<K>\n ): SortedMap<K, V> {\n const map = new SortedMap<K, V>(comparator);\n for (const [key, value] of entries) {\n map.set(key, value);\n }\n return map;\n }\n\n /**\n * Get or set a value using a factory function.\n * If the key doesn't exist, the factory is called to create the value.\n */\n getOrSet(key: K, factory: () => V): V {\n const existing = this.tree.get(key);\n if (existing !== undefined) {\n return existing;\n }\n const value = factory();\n this.tree.set(key, value);\n return value;\n }\n\n /**\n * Update a value if the key exists.\n * @returns true if the key existed and was updated\n */\n update(key: K, updater: (value: V) => V): boolean {\n const existing = this.tree.get(key);\n if (existing === undefined) {\n return false;\n }\n this.tree.set(key, updater(existing));\n return true;\n }\n\n /**\n * Get the entry at a specific index (0-based).\n * Time complexity: O(N) - requires linear scan from the beginning.\n * Note: B+ trees do not support O(log N) index-based access.\n */\n at(index: number): [K, V] | undefined {\n if (index < 0 || index >= this.tree.size) {\n return undefined;\n }\n\n let i = 0;\n for (const entry of this.tree.entries()) {\n if (i === index) {\n return entry;\n }\n i++;\n }\n return undefined;\n }\n\n /**\n * Find the greatest key less than the given key.\n * Time complexity: O(log N)\n */\n lowerKey(key: K): K | undefined {\n return this.tree.nextLowerKey(key);\n }\n\n /**\n * Find the greatest key less than or equal to the given key.\n * Time complexity: O(log N)\n */\n floorKey(key: K): K | undefined {\n // Check if exact key exists first\n if (this.tree.has(key)) {\n return key;\n }\n // Otherwise find the next lower key\n return this.tree.nextLowerKey(key);\n }\n\n /**\n * Find the least key greater than the given key.\n * Time complexity: O(log N)\n */\n higherKey(key: K): K | undefined {\n for (const [k] of this.tree.entries(key)) {\n if (this.comparator(k, key) > 0) {\n return k;\n }\n }\n return undefined;\n }\n\n /**\n * Find the least key greater than or equal to the given key.\n * Time complexity: O(log N)\n */\n ceilingKey(key: K): K | undefined {\n for (const [k] of this.tree.entries(key)) {\n return k;\n }\n return undefined;\n }\n\n /**\n * Make the map iterable.\n */\n [Symbol.iterator](): IterableIterator<[K, V]> {\n return this.entries();\n }\n}\n","/**\n * Common types for sorted data structures\n */\n\n/**\n * Comparator function for ordering keys\n */\nexport type Comparator<K> = (a: K, b: K) => number;\n\n/**\n * Options for range queries\n */\nexport interface RangeOptions {\n /** Include the lower bound in results (default: true) */\n fromInclusive?: boolean;\n /** Include the upper bound in results (default: false) */\n toInclusive?: boolean;\n}\n\n/**\n * Default comparator using natural ordering\n */\nexport function defaultComparator<K>(a: K, b: K): number {\n if (a < b) return -1;\n if (a > b) return 1;\n return 0;\n}\n\n/**\n * String comparator for locale-aware ordering\n */\nexport function stringComparator(a: string, b: string): number {\n return a.localeCompare(b);\n}\n\n/**\n * Numeric comparator for number keys\n */\nexport function numericComparator(a: number, b: number): number {\n return a - b;\n}\n\n/**\n * Reverse comparator wrapper\n */\nexport function reverseComparator<K>(comparator: Comparator<K>): Comparator<K> {\n return (a: K, b: K) => -comparator(a, b);\n}\n","/**\n * Attribute System for Query Engine\n *\n * Attributes extract value(s) from records for indexing and querying.\n * Inspired by CQEngine Attribute<O, A>.\n *\n * @module query/Attribute\n */\n\n/**\n * Attribute extracts value(s) from a record.\n * V = Record value type, A = Attribute value type\n */\nexport interface Attribute<V, A> {\n /** Unique attribute name */\n readonly name: string;\n\n /** Attribute value type */\n readonly type: 'simple' | 'multi';\n\n /**\n * Extract value from record.\n * Returns undefined if attribute doesn't exist.\n */\n getValue(record: V): A | undefined;\n\n /**\n * For multi-value attributes, returns all values.\n * For simple attributes, returns single-element array.\n */\n getValues(record: V): A[];\n}\n\n/**\n * Attribute that returns exactly one value per record.\n */\nexport class SimpleAttribute<V, A> implements Attribute<V, A> {\n readonly type = 'simple' as const;\n\n constructor(\n readonly name: string,\n private readonly extractor: (record: V) => A | undefined\n ) {}\n\n getValue(record: V): A | undefined {\n return this.extractor(record);\n }\n\n getValues(record: V): A[] {\n const value = this.getValue(record);\n return value !== undefined ? [value] : [];\n }\n}\n\n/**\n * Factory function for SimpleAttribute.\n */\nexport function simpleAttribute<V, A>(\n name: string,\n extractor: (record: V) => A | undefined\n): SimpleAttribute<V, A> {\n return new SimpleAttribute(name, extractor);\n}\n\n/**\n * Attribute that returns zero or more values per record.\n * Example: tags, categories, roles.\n */\nexport class MultiValueAttribute<V, A> implements Attribute<V, A> {\n readonly type = 'multi' as const;\n\n constructor(\n readonly name: string,\n private readonly extractor: (record: V) => A[]\n ) {}\n\n getValue(record: V): A | undefined {\n const values = this.extractor(record);\n return values.length > 0 ? values[0] : undefined;\n }\n\n getValues(record: V): A[] {\n return this.extractor(record);\n }\n}\n\n/**\n * Factory function for MultiValueAttribute.\n */\nexport function multiAttribute<V, A>(\n name: string,\n extractor: (record: V) => A[]\n): MultiValueAttribute<V, A> {\n return new MultiValueAttribute(name, extractor);\n}\n","/**\n * SetResultSet Implementation\n *\n * ResultSet backed by a Set, used for HashIndex results.\n *\n * @module query/resultset/SetResultSet\n */\n\nimport type { ResultSet } from './ResultSet';\n\n/**\n * ResultSet backed by a Set.\n * Provides O(1) contains() check and direct iteration.\n */\nexport class SetResultSet<K> implements ResultSet<K> {\n constructor(\n private readonly keys: Set<K>,\n private readonly retrievalCost: number\n ) {}\n\n [Symbol.iterator](): Iterator<K> {\n return this.keys[Symbol.iterator]();\n }\n\n getRetrievalCost(): number {\n return this.retrievalCost;\n }\n\n getMergeCost(): number {\n return this.keys.size;\n }\n\n contains(key: K): boolean {\n return this.keys.has(key);\n }\n\n size(): number {\n return this.keys.size;\n }\n\n toArray(): K[] {\n return Array.from(this.keys);\n }\n\n isEmpty(): boolean {\n return this.keys.size === 0;\n }\n}\n","/**\n * HashIndex Implementation\n *\n * Hash-based index for O(1) equality lookups.\n * Supports: equal, in, has queries.\n *\n * Structure: Map<AttributeValue, Set<RecordKey>>\n *\n * CQEngine Reference: HashIndex.java (retrieval cost: 30)\n *\n * @module query/indexes/HashIndex\n */\n\nimport type { Attribute } from '../Attribute';\nimport type { Index, IndexQuery, IndexStats } from './types';\nimport type { ResultSet } from '../resultset/ResultSet';\nimport { SetResultSet } from '../resultset/SetResultSet';\n\n/**\n * Hash-based index for O(1) equality lookups.\n *\n * K = record key type, V = record value type, A = attribute value type\n */\nexport class HashIndex<K, V, A> implements Index<K, V, A> {\n readonly type = 'hash' as const;\n\n /** Map from attribute value to set of record keys */\n private data: Map<A, Set<K>> = new Map();\n\n /** Set of all keys with non-null attribute value */\n private allKeys: Set<K> = new Set();\n\n private static readonly RETRIEVAL_COST = 30;\n private static readonly SUPPORTED_QUERIES = ['equal', 'in', 'has'];\n\n constructor(readonly attribute: Attribute<V, A>) {}\n\n getRetrievalCost(): number {\n return HashIndex.RETRIEVAL_COST;\n }\n\n supportsQuery(queryType: string): boolean {\n return HashIndex.SUPPORTED_QUERIES.includes(queryType);\n }\n\n retrieve(query: IndexQuery<A>): ResultSet<K> {\n switch (query.type) {\n case 'equal':\n return this.retrieveEqual(query.value as A);\n case 'in':\n return this.retrieveIn(query.values as A[]);\n case 'has':\n return this.retrieveHas();\n default:\n throw new Error(`HashIndex does not support query type: ${query.type}`);\n }\n }\n\n private retrieveEqual(value: A): ResultSet<K> {\n const keys = this.data.get(value);\n return new SetResultSet(keys ? new Set(keys) : new Set(), HashIndex.RETRIEVAL_COST);\n }\n\n private retrieveIn(values: A[]): ResultSet<K> {\n const result = new Set<K>();\n for (const value of values) {\n const keys = this.data.get(value);\n if (keys) {\n for (const key of keys) {\n result.add(key);\n }\n }\n }\n return new SetResultSet(result, HashIndex.RETRIEVAL_COST);\n }\n\n private retrieveHas(): ResultSet<K> {\n return new SetResultSet(new Set(this.allKeys), HashIndex.RETRIEVAL_COST);\n }\n\n add(key: K, record: V): void {\n const values = this.attribute.getValues(record);\n if (values.length === 0) return;\n\n for (const value of values) {\n let keys = this.data.get(value);\n if (!keys) {\n keys = new Set();\n this.data.set(value, keys);\n }\n keys.add(key);\n }\n\n this.allKeys.add(key);\n }\n\n remove(key: K, record: V): void {\n const values = this.attribute.getValues(record);\n\n for (const value of values) {\n const keys = this.data.get(value);\n if (keys) {\n keys.delete(key);\n if (keys.size === 0) {\n this.data.delete(value);\n }\n }\n }\n\n this.allKeys.delete(key);\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n const oldValues = this.attribute.getValues(oldRecord);\n const newValues = this.attribute.getValues(newRecord);\n\n // Optimize: check if values actually changed\n if (this.arraysEqual(oldValues, newValues)) {\n return;\n }\n\n this.remove(key, oldRecord);\n this.add(key, newRecord);\n }\n\n clear(): void {\n this.data.clear();\n this.allKeys.clear();\n }\n\n getStats(): IndexStats {\n let totalEntries = 0;\n for (const keys of this.data.values()) {\n totalEntries += keys.size;\n }\n\n return {\n distinctValues: this.data.size,\n totalEntries,\n avgEntriesPerValue: this.data.size > 0 ? totalEntries / this.data.size : 0,\n };\n }\n\n private arraysEqual(a: A[], b: A[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n }\n}\n","/**\n * LazyResultSet Implementation\n *\n * Lazily evaluated result set for range queries.\n * Used when materializing all results upfront would be expensive.\n *\n * @module query/resultset/LazyResultSet\n */\n\nimport type { ResultSet } from './ResultSet';\n\n/**\n * Factory function type that creates a generator for lazy iteration.\n */\nexport type IteratorFactory<K> = () => Generator<K>;\n\n/**\n * Lazily evaluated result set.\n * Used for range queries where materializing all results upfront is expensive.\n *\n * K = record key type\n */\nexport class LazyResultSet<K> implements ResultSet<K> {\n /** Cached materialized results */\n private cached: K[] | null = null;\n\n /**\n * Create a LazyResultSet.\n *\n * @param iteratorFactory - Factory that creates a fresh generator each time\n * @param retrievalCost - Cost of retrieving results from the index\n * @param estimatedSize - Estimated result count for merge cost calculation\n */\n constructor(\n private readonly iteratorFactory: IteratorFactory<K>,\n private readonly retrievalCost: number,\n private readonly estimatedSize: number\n ) {}\n\n *[Symbol.iterator](): Generator<K> {\n if (this.cached) {\n yield* this.cached;\n return;\n }\n\n yield* this.iteratorFactory();\n }\n\n getRetrievalCost(): number {\n return this.retrievalCost;\n }\n\n getMergeCost(): number {\n // Use actual size if cached, otherwise use estimated size\n return this.cached?.length ?? this.estimatedSize;\n }\n\n contains(key: K): boolean {\n // Must materialize to check containment\n return this.toArray().includes(key);\n }\n\n size(): number {\n return this.toArray().length;\n }\n\n toArray(): K[] {\n if (!this.cached) {\n this.cached = [...this.iteratorFactory()];\n }\n return this.cached;\n }\n\n isEmpty(): boolean {\n // If already cached, use the cached value\n if (this.cached) {\n return this.cached.length === 0;\n }\n\n // Try to avoid full materialization by checking just the first element\n const iter = this.iteratorFactory();\n const first = iter.next();\n return first.done === true;\n }\n\n /**\n * Check if the result set has been materialized.\n * Useful for testing lazy evaluation behavior.\n */\n isMaterialized(): boolean {\n return this.cached !== null;\n }\n\n /**\n * Force materialization of the result set.\n * Returns the cached array.\n */\n materialize(): K[] {\n return this.toArray();\n }\n\n /**\n * Get the estimated size before materialization.\n */\n getEstimatedSize(): number {\n return this.estimatedSize;\n }\n}\n","/**\n * NavigableIndex Implementation\n *\n * Sorted index for O(log N) range queries.\n * Supports: equal, in, has, gt, gte, lt, lte, between queries.\n *\n * Structure: SortedMap<AttributeValue, Set<RecordKey>>\n *\n * CQEngine Reference: NavigableIndex.java (retrieval cost: 40)\n *\n * @module query/indexes/NavigableIndex\n */\n\nimport type { Attribute } from '../Attribute';\nimport type { Index, IndexQuery, IndexStats } from './types';\nimport type { ResultSet } from '../resultset/ResultSet';\nimport { SetResultSet } from '../resultset/SetResultSet';\nimport { LazyResultSet } from '../resultset/LazyResultSet';\nimport { SortedMap } from '../ds/SortedMap';\nimport type { Comparator } from '../ds/types';\n\n/**\n * Sorted index for O(log N) range queries.\n *\n * K = record key type, V = record value type, A = attribute value type (must be orderable)\n */\nexport class NavigableIndex<K, V, A extends string | number>\n implements Index<K, V, A>\n{\n readonly type = 'navigable' as const;\n\n /** Sorted map from attribute value to set of record keys */\n private data: SortedMap<A, Set<K>>;\n\n /** Set of all keys with non-null attribute value */\n private allKeys: Set<K> = new Set();\n\n /** Retrieval cost as per CQEngine cost model */\n private static readonly RETRIEVAL_COST = 40;\n\n /** Supported query types */\n private static readonly SUPPORTED_QUERIES = [\n 'equal',\n 'in',\n 'has',\n 'gt',\n 'gte',\n 'lt',\n 'lte',\n 'between',\n ];\n\n /**\n * Create a NavigableIndex.\n *\n * @param attribute - Attribute to index\n * @param comparator - Optional custom comparator for ordering\n */\n constructor(\n readonly attribute: Attribute<V, A>,\n comparator?: Comparator<A>\n ) {\n this.data = new SortedMap<A, Set<K>>(comparator);\n }\n\n getRetrievalCost(): number {\n return NavigableIndex.RETRIEVAL_COST;\n }\n\n supportsQuery(queryType: string): boolean {\n return NavigableIndex.SUPPORTED_QUERIES.includes(queryType);\n }\n\n retrieve(query: IndexQuery<A>): ResultSet<K> {\n switch (query.type) {\n case 'equal':\n return this.retrieveEqual(query.value as A);\n case 'in':\n return this.retrieveIn(query.values as A[]);\n case 'has':\n return this.retrieveHas();\n case 'gt':\n return this.retrieveGreaterThan(query.value as A, false);\n case 'gte':\n return this.retrieveGreaterThan(query.value as A, true);\n case 'lt':\n return this.retrieveLessThan(query.value as A, false);\n case 'lte':\n return this.retrieveLessThan(query.value as A, true);\n case 'between':\n return this.retrieveBetween(\n query.from as A,\n query.to as A,\n query.fromInclusive ?? true,\n query.toInclusive ?? false\n );\n default:\n throw new Error(\n `NavigableIndex does not support query type: ${query.type}`\n );\n }\n }\n\n // ============== Equality Queries ==============\n\n private retrieveEqual(value: A): ResultSet<K> {\n const keys = this.data.get(value);\n return new SetResultSet(\n keys ? new Set(keys) : new Set(),\n NavigableIndex.RETRIEVAL_COST\n );\n }\n\n private retrieveIn(values: A[]): ResultSet<K> {\n const result = new Set<K>();\n for (const value of values) {\n const keys = this.data.get(value);\n if (keys) {\n for (const key of keys) {\n result.add(key);\n }\n }\n }\n return new SetResultSet(result, NavigableIndex.RETRIEVAL_COST);\n }\n\n private retrieveHas(): ResultSet<K> {\n return new SetResultSet(\n new Set(this.allKeys),\n NavigableIndex.RETRIEVAL_COST\n );\n }\n\n // ============== Range Queries ==============\n\n private retrieveGreaterThan(value: A, inclusive: boolean): ResultSet<K> {\n return new LazyResultSet(\n () => this.iterateGreaterThan(value, inclusive),\n NavigableIndex.RETRIEVAL_COST,\n this.estimateGreaterThanSize()\n );\n }\n\n private retrieveLessThan(value: A, inclusive: boolean): ResultSet<K> {\n return new LazyResultSet(\n () => this.iterateLessThan(value, inclusive),\n NavigableIndex.RETRIEVAL_COST,\n this.estimateLessThanSize()\n );\n }\n\n private retrieveBetween(\n from: A,\n to: A,\n fromInclusive: boolean,\n toInclusive: boolean\n ): ResultSet<K> {\n return new LazyResultSet(\n () => this.iterateBetween(from, to, fromInclusive, toInclusive),\n NavigableIndex.RETRIEVAL_COST,\n this.estimateBetweenSize()\n );\n }\n\n // ============== Lazy Iterators ==============\n\n private *iterateGreaterThan(value: A, inclusive: boolean): Generator<K> {\n for (const [, keys] of this.data.greaterThan(value, inclusive)) {\n for (const key of keys) {\n yield key;\n }\n }\n }\n\n private *iterateLessThan(value: A, inclusive: boolean): Generator<K> {\n for (const [, keys] of this.data.lessThan(value, inclusive)) {\n for (const key of keys) {\n yield key;\n }\n }\n }\n\n private *iterateBetween(\n from: A,\n to: A,\n fromInclusive: boolean,\n toInclusive: boolean\n ): Generator<K> {\n for (const [, keys] of this.data.range(from, to, {\n fromInclusive,\n toInclusive,\n })) {\n for (const key of keys) {\n yield key;\n }\n }\n }\n\n // ============== Size Estimation ==============\n\n /**\n * Estimate size for gt/gte queries.\n * Uses rough estimate: assume uniform distribution, return half.\n */\n private estimateGreaterThanSize(): number {\n return Math.max(1, Math.floor(this.allKeys.size / 2));\n }\n\n /**\n * Estimate size for lt/lte queries.\n * Uses rough estimate: assume uniform distribution, return half.\n */\n private estimateLessThanSize(): number {\n return Math.max(1, Math.floor(this.allKeys.size / 2));\n }\n\n /**\n * Estimate size for between queries.\n * Uses rough estimate: assume uniform distribution, return quarter.\n */\n private estimateBetweenSize(): number {\n return Math.max(1, Math.floor(this.allKeys.size / 4));\n }\n\n // ============== Index Mutations ==============\n\n add(key: K, record: V): void {\n const values = this.attribute.getValues(record);\n if (values.length === 0) return;\n\n for (const value of values) {\n let keys = this.data.get(value);\n if (!keys) {\n keys = new Set();\n this.data.set(value, keys);\n }\n keys.add(key);\n }\n\n this.allKeys.add(key);\n }\n\n remove(key: K, record: V): void {\n const values = this.attribute.getValues(record);\n\n for (const value of values) {\n const keys = this.data.get(value);\n if (keys) {\n keys.delete(key);\n if (keys.size === 0) {\n this.data.delete(value);\n }\n }\n }\n\n this.allKeys.delete(key);\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n const oldValues = this.attribute.getValues(oldRecord);\n const newValues = this.attribute.getValues(newRecord);\n\n // Optimize: check if values actually changed\n if (this.arraysEqual(oldValues, newValues)) {\n return;\n }\n\n this.remove(key, oldRecord);\n this.add(key, newRecord);\n }\n\n clear(): void {\n this.data.clear();\n this.allKeys.clear();\n }\n\n getStats(): IndexStats {\n let totalEntries = 0;\n for (const [, keys] of this.data.entries()) {\n totalEntries += keys.size;\n }\n\n return {\n distinctValues: this.data.size,\n totalEntries,\n avgEntriesPerValue:\n this.data.size > 0 ? totalEntries / this.data.size : 0,\n };\n }\n\n // ============== Helpers ==============\n\n private arraysEqual(a: A[], b: A[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n }\n\n /**\n * Get the minimum indexed value.\n * Useful for debugging and range estimation.\n */\n getMinValue(): A | undefined {\n return this.data.minKey();\n }\n\n /**\n * Get the maximum indexed value.\n * Useful for debugging and range estimation.\n */\n getMaxValue(): A | undefined {\n return this.data.maxKey();\n }\n}\n","/**\n * FallbackIndex Implementation\n *\n * Fallback index that performs full scan for queries without suitable index.\n * Has maximum retrieval cost to ensure it's only used as a last resort.\n *\n * @module query/indexes/FallbackIndex\n */\n\nimport type { Index, IndexQuery, IndexStats } from './types';\nimport type { ResultSet } from '../resultset/ResultSet';\nimport { SetResultSet } from '../resultset/SetResultSet';\nimport { simpleAttribute } from '../Attribute';\n\n/**\n * Fallback index that performs full scan.\n * Used when no suitable index exists for a query.\n *\n * K = record key type, V = record value type\n */\nexport class FallbackIndex<K, V> implements Index<K, V, unknown> {\n readonly type = 'hash' as const;\n\n /** Wildcard attribute for fallback */\n readonly attribute = simpleAttribute<V, unknown>('*', () => undefined);\n\n /** Maximum retrieval cost ensures this is only used as fallback */\n private static readonly RETRIEVAL_COST = Number.MAX_SAFE_INTEGER;\n\n /**\n * Create a FallbackIndex.\n *\n * @param getAllKeys - Function to get all keys in the collection\n * @param getRecord - Function to get a record by key\n * @param matchesPredicate - Function to check if a record matches a query\n */\n constructor(\n private readonly getAllKeys: () => Iterable<K>,\n private readonly getRecord: (key: K) => V | undefined,\n private readonly matchesPredicate: (record: V, query: IndexQuery<unknown>) => boolean\n ) {}\n\n getRetrievalCost(): number {\n return FallbackIndex.RETRIEVAL_COST;\n }\n\n /**\n * Supports any query type via full scan.\n */\n supportsQuery(): boolean {\n return true;\n }\n\n /**\n * Retrieve by performing full scan and applying predicate.\n */\n retrieve(query: IndexQuery<unknown>): ResultSet<K> {\n const result = new Set<K>();\n\n for (const key of this.getAllKeys()) {\n const record = this.getRecord(key);\n if (record && this.matchesPredicate(record, query)) {\n result.add(key);\n }\n }\n\n return new SetResultSet(result, FallbackIndex.RETRIEVAL_COST);\n }\n\n // FallbackIndex doesn't maintain state - these are no-ops\n add(): void {}\n remove(): void {}\n update(): void {}\n clear(): void {}\n\n getStats(): IndexStats {\n return {\n distinctValues: 0,\n totalEntries: 0,\n avgEntriesPerValue: 0,\n };\n }\n}\n\n/**\n * Factory to create predicate matcher from query.\n * Used by FallbackIndex to evaluate queries against records.\n *\n * @param getAttribute - Function to get attribute value from record\n */\nexport function createPredicateMatcher<V>(\n getAttribute: (record: V, attrName: string) => unknown\n): (record: V, query: IndexQuery<unknown>) => boolean {\n return (record: V, query: IndexQuery<unknown>): boolean => {\n // For wildcard queries, match everything\n if ((query as { attribute?: string }).attribute === '*') {\n return true;\n }\n\n const attrName = (query as { attribute?: string }).attribute;\n if (!attrName) {\n return true;\n }\n\n const value = getAttribute(record, attrName);\n\n switch (query.type) {\n case 'equal':\n return value === query.value;\n\n case 'in':\n return query.values?.includes(value) ?? false;\n\n case 'has':\n return value !== undefined && value !== null;\n\n case 'gt':\n return typeof value === 'number' && typeof query.value === 'number'\n ? value > query.value\n : typeof value === 'string' && typeof query.value === 'string'\n ? value > query.value\n : false;\n\n case 'gte':\n return typeof value === 'number' && typeof query.value === 'number'\n ? value >= query.value\n : typeof value === 'string' && typeof query.value === 'string'\n ? value >= query.value\n : false;\n\n case 'lt':\n return typeof value === 'number' && typeof query.value === 'number'\n ? value < query.value\n : typeof value === 'string' && typeof query.value === 'string'\n ? value < query.value\n : false;\n\n case 'lte':\n return typeof value === 'number' && typeof query.value === 'number'\n ? value <= query.value\n : typeof value === 'string' && typeof query.value === 'string'\n ? value <= query.value\n : false;\n\n case 'between': {\n if (typeof value !== 'number' && typeof value !== 'string') {\n return false;\n }\n const fromInclusive = query.fromInclusive ?? true;\n const toInclusive = query.toInclusive ?? false;\n const from = query.from;\n const to = query.to;\n\n if (from === undefined || from === null || to === undefined || to === null) {\n return false;\n }\n\n const aboveFrom = fromInclusive ? value >= from : value > from;\n const belowTo = toInclusive ? value <= to : value < to;\n return aboveFrom && belowTo;\n }\n\n default:\n return false;\n }\n };\n}\n","/**\n * Query Types and Plan Types for Query Engine\n *\n * Defines query node types for the cost-based optimizer\n * and execution plan types.\n *\n * @module query/QueryTypes\n */\n\nimport type { Index, IndexQuery } from './indexes/types';\n\n// ============== Query Node Types ==============\n\n/**\n * Base query node interface.\n * Compatible with existing PredicateNode from predicate.ts\n */\nexport interface QueryNode {\n type: string;\n}\n\n/**\n * Simple query node for attribute-based conditions.\n */\nexport interface SimpleQueryNode extends QueryNode {\n type: 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'between' | 'like' | 'regex' | 'in' | 'has' | 'contains' | 'containsAll' | 'containsAny';\n attribute: string;\n value?: unknown;\n values?: unknown[];\n /** For 'between' queries: lower bound */\n from?: unknown;\n /** For 'between' queries: upper bound */\n to?: unknown;\n /** For 'between' queries: include lower bound (default: true) */\n fromInclusive?: boolean;\n /** For 'between' queries: include upper bound (default: false) */\n toInclusive?: boolean;\n}\n\n// ============== Full-Text Search Query Types (Phase 12) ==============\n\n/**\n * Options for full-text search match queries.\n */\nexport interface MatchQueryOptions {\n /** Minimum BM25 score threshold */\n minScore?: number;\n /** Boost factor for this field */\n boost?: number;\n /** Operator for multi-term queries: 'and' requires all terms, 'or' requires any */\n operator?: 'and' | 'or';\n /** Fuzziness level for typo tolerance (0 = exact, 1 = 1 edit, 2 = 2 edits) */\n fuzziness?: number;\n}\n\n/**\n * Match query node for BM25 full-text search.\n */\nexport interface MatchQueryNode extends QueryNode {\n type: 'match';\n attribute: string;\n query: string;\n options?: MatchQueryOptions;\n}\n\n/**\n * Match phrase query node for exact phrase matching.\n */\nexport interface MatchPhraseQueryNode extends QueryNode {\n type: 'matchPhrase';\n attribute: string;\n query: string;\n /** Word distance tolerance (0 = exact phrase) */\n slop?: number;\n}\n\n/**\n * Match prefix query node for prefix matching.\n */\nexport interface MatchPrefixQueryNode extends QueryNode {\n type: 'matchPrefix';\n attribute: string;\n prefix: string;\n /** Maximum number of term expansions */\n maxExpansions?: number;\n}\n\n/**\n * Union type for FTS query nodes.\n */\nexport type FTSQueryNode = MatchQueryNode | MatchPhraseQueryNode | MatchPrefixQueryNode;\n\n/**\n * Logical query node for combining conditions.\n */\nexport interface LogicalQueryNode {\n type: 'and' | 'or' | 'not';\n children?: Query[];\n child?: Query;\n}\n\n/**\n * Union type for all query types.\n */\nexport type Query = SimpleQueryNode | LogicalQueryNode | FTSQueryNode;\n\n// ============== Query Options ==============\n\n/**\n * Query execution options for sort/limit/cursor.\n */\nexport interface QueryOptions {\n /** Sort by field(s): field name -> direction */\n sort?: Record<string, 'asc' | 'desc'>;\n /** Maximum number of results to return */\n limit?: number;\n /** Cursor for pagination (Phase 14.1: replaces offset) */\n cursor?: string;\n}\n\n// ============== Execution Plan Types ==============\n\n/**\n * Execution plan step.\n * Represents a single operation in the query execution plan.\n */\nexport type PlanStep =\n | IndexScanStep\n | FullScanStep\n | IntersectionStep\n | UnionStep\n | FilterStep\n | NotStep\n | FTSScanStep\n | FusionStep;\n\n/**\n * Index scan step - retrieves from an index.\n */\nexport interface IndexScanStep {\n type: 'index-scan';\n index: Index<unknown, unknown, unknown>;\n query: IndexQuery<unknown>;\n}\n\n/**\n * Full scan step - scans all records.\n */\nexport interface FullScanStep {\n type: 'full-scan';\n predicate: Query;\n}\n\n/**\n * Intersection step - AND of multiple result sets.\n */\nexport interface IntersectionStep {\n type: 'intersection';\n steps: PlanStep[];\n}\n\n/**\n * Union step - OR of multiple result sets.\n */\nexport interface UnionStep {\n type: 'union';\n steps: PlanStep[];\n}\n\n/**\n * Filter step - applies predicate to source results.\n */\nexport interface FilterStep {\n type: 'filter';\n source: PlanStep;\n predicate: Query;\n}\n\n/**\n * NOT step - negation (all keys minus matching keys).\n */\nexport interface NotStep {\n type: 'not';\n source: PlanStep;\n allKeys: () => Set<unknown>;\n}\n\n// ============== Full-Text Search Plan Types (Phase 12) ==============\n\n/**\n * Fusion strategy for combining results from different search methods.\n */\nexport type FusionStrategy = 'intersection' | 'rrf' | 'score-filter';\n\n/**\n * FTS scan step - full-text search using FullTextIndex.\n * Returns scored results (documents with BM25 scores).\n */\nexport interface FTSScanStep {\n type: 'fts-scan';\n /** Field to search */\n field: string;\n /** Search query or phrase */\n query: string;\n /** Type of FTS query */\n ftsType: 'match' | 'matchPhrase' | 'matchPrefix';\n /** Query options (minScore, boost, etc.) */\n options?: MatchQueryOptions;\n /** This step returns scored results */\n returnsScored: true;\n /** Estimated cost */\n estimatedCost: number;\n}\n\n/**\n * Fusion step - combines results from multiple steps using RRF or other strategy.\n */\nexport interface FusionStep {\n type: 'fusion';\n /** Steps to combine */\n steps: PlanStep[];\n /** Fusion strategy */\n strategy: FusionStrategy;\n /** Whether result is scored (true if any child is scored) */\n returnsScored: boolean;\n}\n\n// ============== Query Plan ==============\n\n/**\n * Complete query execution plan.\n */\nexport interface QueryPlan {\n /** Root execution step */\n root: PlanStep;\n /** Estimated execution cost */\n estimatedCost: number;\n /** Whether any index is used */\n usesIndexes: boolean;\n /** Whether sort can use index order */\n indexedSort?: boolean;\n /** Sort configuration */\n sort?: {\n field: string;\n direction: 'asc' | 'desc';\n };\n /** Limit configuration */\n limit?: number;\n /** Cursor for pagination (Phase 14.1: replaces offset) */\n cursor?: string;\n}\n\n// ============== Type Guards ==============\n\n/**\n * Check if a query is a simple query node.\n */\nexport function isSimpleQuery(query: Query): query is SimpleQueryNode {\n return [\n 'eq',\n 'neq',\n 'gt',\n 'gte',\n 'lt',\n 'lte',\n 'between',\n 'like',\n 'regex',\n 'in',\n 'has',\n 'contains',\n 'containsAll',\n 'containsAny',\n ].includes(query.type);\n}\n\n/**\n * Check if a query is a logical query node.\n */\nexport function isLogicalQuery(query: Query): query is LogicalQueryNode {\n return query.type === 'and' || query.type === 'or' || query.type === 'not';\n}\n\n/**\n * Check if a query is a full-text search query node.\n */\nexport function isFTSQuery(query: Query): query is FTSQueryNode {\n return query.type === 'match' || query.type === 'matchPhrase' || query.type === 'matchPrefix';\n}\n\n/**\n * Check if a query is a match query node.\n */\nexport function isMatchQuery(query: Query): query is MatchQueryNode {\n return query.type === 'match';\n}\n\n/**\n * Check if a query is a match phrase query node.\n */\nexport function isMatchPhraseQuery(query: Query): query is MatchPhraseQueryNode {\n return query.type === 'matchPhrase';\n}\n\n/**\n * Check if a query is a match prefix query node.\n */\nexport function isMatchPrefixQuery(query: Query): query is MatchPrefixQueryNode {\n return query.type === 'matchPrefix';\n}\n","/**\n * StandingQueryIndex Implementation\n *\n * Pre-computed index for a specific query.\n * Maintains result set incrementally as data changes.\n *\n * Lowest retrieval cost (10) - O(1) query execution.\n * Critical for Live Queries in TopGun where the same query\n * is executed repeatedly on every data change.\n *\n * CQEngine Reference: StandingQueryIndex.java (retrieval cost: 10)\n *\n * @module query/indexes/StandingQueryIndex\n */\n\nimport type { Attribute } from '../Attribute';\nimport { simpleAttribute } from '../Attribute';\nimport type { Index, IndexQuery, IndexStats } from './types';\nimport type { ResultSet } from '../resultset/ResultSet';\nimport { SetResultSet } from '../resultset/SetResultSet';\nimport type { Query, SimpleQueryNode, LogicalQueryNode } from '../QueryTypes';\nimport { isSimpleQuery, isLogicalQuery } from '../QueryTypes';\n\n/**\n * Change type for standing query updates.\n */\nexport type StandingQueryChange = 'added' | 'removed' | 'updated' | 'unchanged';\n\n/**\n * Options for creating a StandingQueryIndex.\n */\nexport interface StandingQueryIndexOptions<K, V> {\n /** Query this index answers */\n query: Query;\n /** Function to get record by key (optional, for validation) */\n getRecord?: (key: K) => V | undefined;\n}\n\n/**\n * Pre-computed index for a specific query.\n * Maintains result set incrementally as data changes.\n *\n * K = record key type, V = record value type\n */\nexport class StandingQueryIndex<K, V> implements Index<K, V, unknown> {\n readonly type = 'standing' as const;\n\n /**\n * Wildcard attribute - StandingQueryIndex doesn't index by attribute,\n * it indexes by query match.\n */\n readonly attribute: Attribute<V, unknown> = simpleAttribute<V, unknown>(\n '*',\n () => undefined\n );\n\n /** Pre-computed result set */\n private results: Set<K> = new Set();\n\n /** Query this index answers */\n private readonly query: Query;\n\n /** Record accessor (optional) */\n private readonly getRecord?: (key: K) => V | undefined;\n\n /** Retrieval cost - lowest of all index types */\n private static readonly RETRIEVAL_COST = 10;\n\n constructor(options: StandingQueryIndexOptions<K, V>) {\n this.query = options.query;\n this.getRecord = options.getRecord;\n }\n\n /**\n * Get the query this index answers.\n */\n getQuery(): Query {\n return this.query;\n }\n\n /**\n * Check if this index answers the given query.\n */\n answersQuery(query: Query): boolean {\n return this.queriesEqual(this.query, query);\n }\n\n getRetrievalCost(): number {\n return StandingQueryIndex.RETRIEVAL_COST;\n }\n\n supportsQuery(_queryType: string): boolean {\n // StandingQueryIndex supports any query type since it pre-computes results\n // The actual query matching is done via answersQuery()\n return true;\n }\n\n retrieve(_query: IndexQuery<unknown>): ResultSet<K> {\n // Return pre-computed results (copy to avoid mutation)\n return new SetResultSet(new Set(this.results), StandingQueryIndex.RETRIEVAL_COST);\n }\n\n /**\n * Get current result set (for live query updates).\n * Returns a copy to avoid external mutation.\n */\n getResults(): Set<K> {\n return new Set(this.results);\n }\n\n /**\n * Get result count.\n */\n getResultCount(): number {\n return this.results.size;\n }\n\n /**\n * Check if key is in results.\n */\n contains(key: K): boolean {\n return this.results.has(key);\n }\n\n add(key: K, record: V): void {\n // Evaluate predicate and add if matches\n if (this.evaluateRecord(record)) {\n this.results.add(key);\n }\n }\n\n remove(key: K, _record: V): void {\n // Always try to remove (may or may not be in results)\n this.results.delete(key);\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n const wasMatch = this.evaluateRecord(oldRecord);\n const isMatch = this.evaluateRecord(newRecord);\n\n if (wasMatch && !isMatch) {\n // Was in results, no longer matches\n this.results.delete(key);\n } else if (!wasMatch && isMatch) {\n // Was not in results, now matches\n this.results.add(key);\n }\n // If both match or neither match, no change to results set\n // (though the record itself may have changed)\n }\n\n /**\n * Determine what changed for a record update.\n * Returns the type of change relative to the query results.\n *\n * @param key - Record key\n * @param oldRecord - Previous record value (undefined for new records)\n * @param newRecord - New record value (undefined for deleted records)\n * @returns Change type: 'added', 'removed', 'updated', or 'unchanged'\n */\n determineChange(\n _key: K,\n oldRecord: V | undefined,\n newRecord: V | undefined\n ): StandingQueryChange {\n const wasMatch = oldRecord ? this.evaluateRecord(oldRecord) : false;\n const isMatch = newRecord ? this.evaluateRecord(newRecord) : false;\n\n if (!wasMatch && isMatch) {\n return 'added';\n } else if (wasMatch && !isMatch) {\n return 'removed';\n } else if (wasMatch && isMatch) {\n return 'updated';\n }\n return 'unchanged';\n }\n\n clear(): void {\n this.results.clear();\n }\n\n getStats(): IndexStats {\n return {\n distinctValues: 1, // Single query\n totalEntries: this.results.size,\n avgEntriesPerValue: this.results.size,\n };\n }\n\n /**\n * Build index from existing data.\n *\n * @param entries - Iterable of [key, record] pairs\n */\n buildFromData(entries: Iterable<[K, V]>): void {\n this.results.clear();\n for (const [key, record] of entries) {\n if (this.evaluateRecord(record)) {\n this.results.add(key);\n }\n }\n }\n\n /**\n * Evaluate a record against the query predicate.\n *\n * @param record - Record to evaluate\n * @returns true if record matches the query\n */\n private evaluateRecord(record: V): boolean {\n try {\n return this.evaluateQuery(this.query, record);\n } catch {\n return false;\n }\n }\n\n /**\n * Evaluate a query node against a record.\n * Implements predicate evaluation logic.\n */\n private evaluateQuery(query: Query, record: V): boolean {\n if (isSimpleQuery(query)) {\n return this.evaluateSimpleQuery(query, record);\n } else if (isLogicalQuery(query)) {\n return this.evaluateLogicalQuery(query, record);\n }\n return false;\n }\n\n /**\n * Evaluate a simple query (attribute-based condition).\n */\n private evaluateSimpleQuery(query: SimpleQueryNode, record: V): boolean {\n const value = this.getAttributeValue(record, query.attribute);\n\n switch (query.type) {\n case 'eq':\n return value === query.value;\n\n case 'neq':\n return value !== query.value;\n\n case 'gt':\n return (\n value !== undefined &&\n value !== null &&\n (value as number) > (query.value as number)\n );\n\n case 'gte':\n return (\n value !== undefined &&\n value !== null &&\n (value as number) >= (query.value as number)\n );\n\n case 'lt':\n return (\n value !== undefined &&\n value !== null &&\n (value as number) < (query.value as number)\n );\n\n case 'lte':\n return (\n value !== undefined &&\n value !== null &&\n (value as number) <= (query.value as number)\n );\n\n case 'in':\n return query.values !== undefined && query.values.includes(value);\n\n case 'has':\n return value !== undefined && value !== null;\n\n case 'like':\n if (typeof value !== 'string' || typeof query.value !== 'string') {\n return false;\n }\n return this.matchLike(value, query.value);\n\n case 'regex':\n if (typeof value !== 'string' || typeof query.value !== 'string') {\n return false;\n }\n try {\n return new RegExp(query.value).test(value);\n } catch {\n return false;\n }\n\n case 'between':\n if (value === undefined || value === null) {\n return false;\n }\n const val = value as number | string;\n const from = query.from as number | string;\n const to = query.to as number | string;\n const fromOk = query.fromInclusive !== false ? val >= from : val > from;\n const toOk = query.toInclusive !== false ? val <= to : val < to;\n return fromOk && toOk;\n\n case 'contains':\n if (typeof value !== 'string' || typeof query.value !== 'string') {\n return false;\n }\n return value.toLowerCase().includes((query.value as string).toLowerCase());\n\n case 'containsAll':\n if (typeof value !== 'string' || !query.values) {\n return false;\n }\n return query.values.every(\n (v) => typeof v === 'string' && value.toLowerCase().includes(v.toLowerCase())\n );\n\n case 'containsAny':\n if (typeof value !== 'string' || !query.values) {\n return false;\n }\n return query.values.some(\n (v) => typeof v === 'string' && value.toLowerCase().includes(v.toLowerCase())\n );\n\n default:\n return false;\n }\n }\n\n /**\n * Evaluate a logical query (AND/OR/NOT).\n */\n private evaluateLogicalQuery(query: LogicalQueryNode, record: V): boolean {\n switch (query.type) {\n case 'and':\n if (!query.children || query.children.length === 0) {\n return true;\n }\n return query.children.every((child) => this.evaluateQuery(child, record));\n\n case 'or':\n if (!query.children || query.children.length === 0) {\n return false;\n }\n return query.children.some((child) => this.evaluateQuery(child, record));\n\n case 'not':\n if (!query.child) {\n return true;\n }\n return !this.evaluateQuery(query.child, record);\n\n default:\n return false;\n }\n }\n\n /**\n * Get attribute value from record using dot notation.\n */\n private getAttributeValue(record: V, path: string): unknown {\n if (record === null || record === undefined) {\n return undefined;\n }\n\n const parts = path.split('.');\n let current: unknown = record;\n\n for (const part of parts) {\n if (current === null || current === undefined) {\n return undefined;\n }\n if (typeof current !== 'object') {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n }\n\n /**\n * Match a value against a LIKE pattern.\n * Supports % as wildcard for any characters.\n */\n private matchLike(value: string, pattern: string): boolean {\n // Convert LIKE pattern to regex\n const escaped = pattern.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n const regex = escaped.replace(/%/g, '.*').replace(/_/g, '.');\n return new RegExp(`^${regex}$`, 'i').test(value);\n }\n\n /**\n * Deep equality check for queries.\n */\n private queriesEqual(a: Query, b: Query): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n }\n}\n","/**\n * Tokenizer Interface and Implementations\n *\n * Provides text tokenization for InvertedIndex full-text search.\n * Tokenizers split text into searchable tokens.\n *\n * @module query/tokenization/Tokenizer\n */\n\n/**\n * Interface for text tokenizers.\n * Tokenizers split text into an array of tokens (words, n-grams, etc.)\n */\nexport interface Tokenizer {\n /**\n * Split text into tokens.\n *\n * @param text - Text to tokenize\n * @returns Array of tokens\n */\n tokenize(text: string): string[];\n}\n\n/**\n * Tokenizer that splits on whitespace.\n * Simplest tokenizer - splits on any whitespace characters.\n *\n * Example: \"hello world\" → [\"hello\", \"world\"]\n */\nexport class WhitespaceTokenizer implements Tokenizer {\n tokenize(text: string): string[] {\n if (!text || typeof text !== 'string') {\n return [];\n }\n return text.split(/\\s+/).filter((t) => t.length > 0);\n }\n}\n\n/**\n * Tokenizer that splits on word boundaries.\n * Splits on non-word characters (anything not [a-zA-Z0-9_]).\n *\n * Example: \"hello-world! test123\" → [\"hello\", \"world\", \"test123\"]\n */\nexport class WordBoundaryTokenizer implements Tokenizer {\n tokenize(text: string): string[] {\n if (!text || typeof text !== 'string') {\n return [];\n }\n return text.split(/\\W+/).filter((t) => t.length > 0);\n }\n}\n\n/**\n * N-gram tokenizer for substring matching.\n * Creates overlapping character sequences of length n.\n *\n * Example (n=3): \"hello\" → [\"hel\", \"ell\", \"llo\"]\n *\n * Use cases:\n * - Fuzzy search (typo tolerance)\n * - Substring matching (contains anywhere)\n * - Partial word matching\n */\nexport class NGramTokenizer implements Tokenizer {\n /**\n * Create an N-gram tokenizer.\n *\n * @param n - Length of each n-gram (default: 3)\n */\n constructor(private readonly n: number = 3) {\n if (n < 1) {\n throw new Error('N-gram size must be at least 1');\n }\n }\n\n tokenize(text: string): string[] {\n if (!text || typeof text !== 'string') {\n return [];\n }\n\n // Remove whitespace for n-gram generation\n const normalized = text.replace(/\\s+/g, ' ').trim();\n\n if (normalized.length < this.n) {\n // Text is shorter than n-gram size - return text itself if non-empty\n return normalized.length > 0 ? [normalized] : [];\n }\n\n const tokens: string[] = [];\n for (let i = 0; i <= normalized.length - this.n; i++) {\n tokens.push(normalized.substring(i, i + this.n));\n }\n\n return tokens;\n }\n\n /**\n * Get the n-gram size.\n */\n get size(): number {\n return this.n;\n }\n}\n","/**\n * Token Filter Interface and Implementations\n *\n * Token filters transform or filter tokens produced by tokenizers.\n * Common uses: lowercase normalization, stop word removal, length filtering.\n *\n * @module query/tokenization/TokenFilter\n */\n\n/**\n * Interface for token filters.\n * Filters transform an array of tokens into another array of tokens.\n */\nexport interface TokenFilter {\n /**\n * Apply filter to tokens.\n *\n * @param tokens - Input tokens\n * @returns Filtered tokens\n */\n apply(tokens: string[]): string[];\n}\n\n/**\n * Filter that converts all tokens to lowercase.\n * Essential for case-insensitive search.\n *\n * Example: [\"Hello\", \"WORLD\"] → [\"hello\", \"world\"]\n */\nexport class LowercaseFilter implements TokenFilter {\n apply(tokens: string[]): string[] {\n return tokens.map((t) => t.toLowerCase());\n }\n}\n\n/**\n * Default English stop words.\n * Common words that don't add search value.\n */\nexport const DEFAULT_STOP_WORDS = [\n 'a',\n 'an',\n 'and',\n 'are',\n 'as',\n 'at',\n 'be',\n 'but',\n 'by',\n 'for',\n 'if',\n 'in',\n 'into',\n 'is',\n 'it',\n 'no',\n 'not',\n 'of',\n 'on',\n 'or',\n 'such',\n 'that',\n 'the',\n 'their',\n 'then',\n 'there',\n 'these',\n 'they',\n 'this',\n 'to',\n 'was',\n 'will',\n 'with',\n];\n\n/**\n * Filter that removes stop words.\n * Stop words are common words that don't contribute to search relevance.\n *\n * Example: [\"the\", \"quick\", \"brown\", \"fox\"] → [\"quick\", \"brown\", \"fox\"]\n */\nexport class StopWordFilter implements TokenFilter {\n private readonly stopWords: Set<string>;\n\n /**\n * Create a stop word filter.\n *\n * @param stopWords - Array of stop words to remove (default: English stop words)\n */\n constructor(stopWords: string[] = DEFAULT_STOP_WORDS) {\n // Store in lowercase for case-insensitive matching\n this.stopWords = new Set(stopWords.map((w) => w.toLowerCase()));\n }\n\n apply(tokens: string[]): string[] {\n return tokens.filter((t) => !this.stopWords.has(t.toLowerCase()));\n }\n\n /**\n * Get the set of stop words.\n */\n getStopWords(): Set<string> {\n return new Set(this.stopWords);\n }\n}\n\n/**\n * Filter that removes tokens shorter than a minimum length.\n * Useful for filtering out single characters or very short tokens.\n *\n * Example (minLength=3): [\"a\", \"is\", \"the\", \"quick\"] → [\"the\", \"quick\"]\n */\nexport class MinLengthFilter implements TokenFilter {\n /**\n * Create a minimum length filter.\n *\n * @param minLength - Minimum token length (default: 2)\n */\n constructor(private readonly minLength: number = 2) {\n if (minLength < 1) {\n throw new Error('Minimum length must be at least 1');\n }\n }\n\n apply(tokens: string[]): string[] {\n return tokens.filter((t) => t.length >= this.minLength);\n }\n\n /**\n * Get the minimum length setting.\n */\n getMinLength(): number {\n return this.minLength;\n }\n}\n\n/**\n * Filter that removes tokens longer than a maximum length.\n * Useful for preventing very long tokens from being indexed.\n *\n * Example (maxLength=10): [\"short\", \"verylongword\"] → [\"short\"]\n */\nexport class MaxLengthFilter implements TokenFilter {\n /**\n * Create a maximum length filter.\n *\n * @param maxLength - Maximum token length (default: 50)\n */\n constructor(private readonly maxLength: number = 50) {\n if (maxLength < 1) {\n throw new Error('Maximum length must be at least 1');\n }\n }\n\n apply(tokens: string[]): string[] {\n return tokens.filter((t) => t.length <= this.maxLength);\n }\n\n /**\n * Get the maximum length setting.\n */\n getMaxLength(): number {\n return this.maxLength;\n }\n}\n\n/**\n * Filter that trims whitespace from tokens.\n * Ensures clean tokens without leading/trailing spaces.\n */\nexport class TrimFilter implements TokenFilter {\n apply(tokens: string[]): string[] {\n return tokens.map((t) => t.trim()).filter((t) => t.length > 0);\n }\n}\n\n/**\n * Filter that removes duplicate tokens.\n * Useful for reducing index size when tokens repeat.\n *\n * Example: [\"hello\", \"world\", \"hello\"] → [\"hello\", \"world\"]\n */\nexport class UniqueFilter implements TokenFilter {\n apply(tokens: string[]): string[] {\n return [...new Set(tokens)];\n }\n}\n","/**\n * Tokenization Pipeline\n *\n * Chains a tokenizer with multiple filters for text processing.\n * Provides factory methods for common configurations.\n *\n * @module query/tokenization/TokenizationPipeline\n */\n\nimport type { Tokenizer } from './Tokenizer';\nimport { WordBoundaryTokenizer } from './Tokenizer';\nimport type { TokenFilter } from './TokenFilter';\nimport { LowercaseFilter, MinLengthFilter, StopWordFilter } from './TokenFilter';\n\n/**\n * Pipeline configuration options.\n */\nexport interface TokenizationPipelineOptions {\n /** Tokenizer to use */\n tokenizer: Tokenizer;\n /** Filters to apply (in order) */\n filters?: TokenFilter[];\n}\n\n/**\n * Tokenization pipeline that chains a tokenizer with filters.\n *\n * Processing order:\n * 1. Tokenizer splits text into tokens\n * 2. Each filter transforms the token array in sequence\n *\n * Example:\n * ```typescript\n * const pipeline = TokenizationPipeline.simple();\n * pipeline.process(\"Hello World!\"); // [\"hello\", \"world\"]\n * ```\n */\nexport class TokenizationPipeline {\n private readonly tokenizer: Tokenizer;\n private readonly filters: TokenFilter[];\n\n /**\n * Create a tokenization pipeline.\n *\n * @param options - Pipeline configuration\n */\n constructor(options: TokenizationPipelineOptions) {\n this.tokenizer = options.tokenizer;\n this.filters = options.filters ?? [];\n }\n\n /**\n * Process text through the pipeline.\n *\n * @param text - Text to process\n * @returns Array of processed tokens\n */\n process(text: string): string[] {\n if (!text || typeof text !== 'string') {\n return [];\n }\n\n // Step 1: Tokenize\n let tokens = this.tokenizer.tokenize(text);\n\n // Step 2: Apply filters in order\n for (const filter of this.filters) {\n tokens = filter.apply(tokens);\n }\n\n return tokens;\n }\n\n /**\n * Get the tokenizer.\n */\n getTokenizer(): Tokenizer {\n return this.tokenizer;\n }\n\n /**\n * Get the filters.\n */\n getFilters(): TokenFilter[] {\n return [...this.filters];\n }\n\n // ==================== Factory Methods ====================\n\n /**\n * Create a simple pipeline with common defaults.\n * Uses word boundary tokenizer with lowercase and minimum length filters.\n *\n * Configuration:\n * - Tokenizer: WordBoundaryTokenizer\n * - Filters: LowercaseFilter, MinLengthFilter(2)\n *\n * @returns Simple tokenization pipeline\n */\n static simple(): TokenizationPipeline {\n return new TokenizationPipeline({\n tokenizer: new WordBoundaryTokenizer(),\n filters: [new LowercaseFilter(), new MinLengthFilter(2)],\n });\n }\n\n /**\n * Create a pipeline optimized for search.\n * Includes stop word removal for better search relevance.\n *\n * Configuration:\n * - Tokenizer: WordBoundaryTokenizer\n * - Filters: LowercaseFilter, MinLengthFilter(2), StopWordFilter\n *\n * @returns Search-optimized tokenization pipeline\n */\n static search(): TokenizationPipeline {\n return new TokenizationPipeline({\n tokenizer: new WordBoundaryTokenizer(),\n filters: [new LowercaseFilter(), new MinLengthFilter(2), new StopWordFilter()],\n });\n }\n\n /**\n * Create a minimal pipeline with just tokenization and lowercase.\n * No filtering - preserves all tokens.\n *\n * Configuration:\n * - Tokenizer: WordBoundaryTokenizer\n * - Filters: LowercaseFilter\n *\n * @returns Minimal tokenization pipeline\n */\n static minimal(): TokenizationPipeline {\n return new TokenizationPipeline({\n tokenizer: new WordBoundaryTokenizer(),\n filters: [new LowercaseFilter()],\n });\n }\n\n /**\n * Create a custom pipeline from a tokenizer and filters.\n *\n * @param tokenizer - Tokenizer to use\n * @param filters - Filters to apply\n * @returns Custom tokenization pipeline\n */\n static custom(tokenizer: Tokenizer, filters: TokenFilter[] = []): TokenizationPipeline {\n return new TokenizationPipeline({ tokenizer, filters });\n }\n}\n","/**\n * InvertedIndex Implementation\n *\n * Full-text search index using inverted index structure.\n * Supports: contains, containsAll, containsAny, has queries.\n *\n * Structure:\n * tokenIndex: Map<Token, Set<RecordKey>>\n * reverseIndex: Map<RecordKey, Set<Token>>\n *\n * Retrieval cost: 50 (between NavigableIndex:40 and FallbackIndex)\n *\n * @module query/indexes/InvertedIndex\n */\n\nimport type { Attribute } from '../Attribute';\nimport type { Index, IndexQuery, IndexStats } from './types';\nimport type { ResultSet } from '../resultset/ResultSet';\nimport { SetResultSet } from '../resultset/SetResultSet';\nimport { TokenizationPipeline } from '../tokenization';\n\n/**\n * Extended statistics for InvertedIndex.\n */\nexport interface InvertedIndexStats extends IndexStats {\n /** Total unique tokens in the index */\n totalTokens: number;\n /** Average number of tokens per indexed document */\n avgTokensPerDocument: number;\n /** Maximum documents for any single token */\n maxDocumentsPerToken: number;\n}\n\n/**\n * Inverted index for full-text search.\n * Maps tokens to sets of document keys for O(K) query performance.\n *\n * K = record key type, V = record value type, A = attribute value type (should be string)\n */\nexport class InvertedIndex<K, V, A extends string = string> implements Index<K, V, A> {\n readonly type = 'inverted' as const;\n\n /** Token → Set of keys */\n private tokenIndex: Map<string, Set<K>> = new Map();\n\n /** Key → Set of tokens (for efficient removal/update) */\n private reverseIndex: Map<K, Set<string>> = new Map();\n\n /** All keys with indexed content */\n private allKeys: Set<K> = new Set();\n\n private static readonly RETRIEVAL_COST = 50;\n private static readonly SUPPORTED_QUERIES = ['contains', 'containsAll', 'containsAny', 'has'];\n\n /**\n * Create an InvertedIndex.\n *\n * @param attribute - Attribute to index (should return string values)\n * @param pipeline - Tokenization pipeline (default: simple pipeline)\n */\n constructor(\n readonly attribute: Attribute<V, A>,\n private readonly pipeline: TokenizationPipeline = TokenizationPipeline.simple()\n ) {}\n\n getRetrievalCost(): number {\n return InvertedIndex.RETRIEVAL_COST;\n }\n\n supportsQuery(queryType: string): boolean {\n return InvertedIndex.SUPPORTED_QUERIES.includes(queryType);\n }\n\n retrieve(query: IndexQuery<A>): ResultSet<K> {\n switch (query.type) {\n case 'contains':\n return this.retrieveContains(query.value as A);\n case 'containsAll':\n return this.retrieveContainsAll(query.values as A[]);\n case 'containsAny':\n return this.retrieveContainsAny(query.values as A[]);\n case 'has':\n return this.retrieveHas();\n default:\n throw new Error(`InvertedIndex does not support query type: ${query.type}`);\n }\n }\n\n /**\n * Retrieve documents containing all tokens from the search text.\n * Uses AND semantics - document must contain ALL tokens.\n */\n private retrieveContains(searchText: A): ResultSet<K> {\n if (!searchText) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n const searchTokens = this.pipeline.process(String(searchText));\n if (searchTokens.length === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n // Sort tokens by frequency (ascending) for efficient intersection\n const sortedTokens = [...searchTokens].sort((a, b) => {\n const sizeA = this.tokenIndex.get(a)?.size ?? 0;\n const sizeB = this.tokenIndex.get(b)?.size ?? 0;\n return sizeA - sizeB;\n });\n\n // Start with smallest set\n const firstTokenKeys = this.tokenIndex.get(sortedTokens[0]);\n if (!firstTokenKeys || firstTokenKeys.size === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n const result = new Set(firstTokenKeys);\n\n // Intersect with remaining tokens\n for (let i = 1; i < sortedTokens.length; i++) {\n const tokenKeys = this.tokenIndex.get(sortedTokens[i]);\n if (!tokenKeys || tokenKeys.size === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n for (const key of result) {\n if (!tokenKeys.has(key)) {\n result.delete(key);\n }\n }\n\n if (result.size === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n }\n\n return new SetResultSet(result, InvertedIndex.RETRIEVAL_COST);\n }\n\n /**\n * Retrieve documents containing ALL specified values.\n * Each value is tokenized, and ALL resulting tokens must match.\n */\n private retrieveContainsAll(values: A[]): ResultSet<K> {\n if (!values || values.length === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n // Collect all tokens from all values\n const allTokens = new Set<string>();\n for (const value of values) {\n const tokens = this.pipeline.process(String(value));\n tokens.forEach((t) => allTokens.add(t));\n }\n\n if (allTokens.size === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n // Sort tokens by frequency for efficient intersection\n const sortedTokens = [...allTokens].sort((a, b) => {\n const sizeA = this.tokenIndex.get(a)?.size ?? 0;\n const sizeB = this.tokenIndex.get(b)?.size ?? 0;\n return sizeA - sizeB;\n });\n\n // Start with smallest set\n const firstTokenKeys = this.tokenIndex.get(sortedTokens[0]);\n if (!firstTokenKeys || firstTokenKeys.size === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n const result = new Set(firstTokenKeys);\n\n // Intersect with remaining tokens\n for (let i = 1; i < sortedTokens.length; i++) {\n const tokenKeys = this.tokenIndex.get(sortedTokens[i]);\n if (!tokenKeys || tokenKeys.size === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n for (const key of result) {\n if (!tokenKeys.has(key)) {\n result.delete(key);\n }\n }\n\n if (result.size === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n }\n\n return new SetResultSet(result, InvertedIndex.RETRIEVAL_COST);\n }\n\n /**\n * Retrieve documents containing ANY of the specified values.\n * Uses OR semantics - document can contain any token from any value.\n */\n private retrieveContainsAny(values: A[]): ResultSet<K> {\n if (!values || values.length === 0) {\n return new SetResultSet(new Set(), InvertedIndex.RETRIEVAL_COST);\n }\n\n const result = new Set<K>();\n\n for (const value of values) {\n const tokens = this.pipeline.process(String(value));\n for (const token of tokens) {\n const keys = this.tokenIndex.get(token);\n if (keys) {\n for (const key of keys) {\n result.add(key);\n }\n }\n }\n }\n\n return new SetResultSet(result, InvertedIndex.RETRIEVAL_COST);\n }\n\n /**\n * Retrieve all documents with indexed content.\n */\n private retrieveHas(): ResultSet<K> {\n return new SetResultSet(new Set(this.allKeys), InvertedIndex.RETRIEVAL_COST);\n }\n\n // ==================== Index Operations ====================\n\n add(key: K, record: V): void {\n const values = this.attribute.getValues(record);\n if (values.length === 0) return;\n\n const allTokens = new Set<string>();\n\n // Tokenize all attribute values\n for (const value of values) {\n if (value === undefined || value === null) continue;\n const tokens = this.pipeline.process(String(value));\n tokens.forEach((t) => allTokens.add(t));\n }\n\n if (allTokens.size === 0) return;\n\n // Add to token index\n for (const token of allTokens) {\n let keys = this.tokenIndex.get(token);\n if (!keys) {\n keys = new Set();\n this.tokenIndex.set(token, keys);\n }\n keys.add(key);\n }\n\n // Add to reverse index\n this.reverseIndex.set(key, allTokens);\n this.allKeys.add(key);\n }\n\n remove(key: K, _record: V): void {\n const tokens = this.reverseIndex.get(key);\n if (!tokens) return;\n\n // Remove from token index\n for (const token of tokens) {\n const keys = this.tokenIndex.get(token);\n if (keys) {\n keys.delete(key);\n if (keys.size === 0) {\n this.tokenIndex.delete(token);\n }\n }\n }\n\n // Remove from reverse index\n this.reverseIndex.delete(key);\n this.allKeys.delete(key);\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n // Get old and new values\n const oldValues = this.attribute.getValues(oldRecord);\n const newValues = this.attribute.getValues(newRecord);\n\n // Quick check: if values are same, skip\n if (this.valuesEqual(oldValues, newValues)) {\n return;\n }\n\n // Full re-index\n this.remove(key, oldRecord);\n this.add(key, newRecord);\n }\n\n clear(): void {\n this.tokenIndex.clear();\n this.reverseIndex.clear();\n this.allKeys.clear();\n }\n\n // ==================== Statistics ====================\n\n getStats(): IndexStats {\n return {\n distinctValues: this.tokenIndex.size,\n totalEntries: this.allKeys.size,\n avgEntriesPerValue:\n this.tokenIndex.size > 0 ? this.allKeys.size / this.tokenIndex.size : 0,\n };\n }\n\n /**\n * Get extended statistics for full-text index.\n */\n getExtendedStats(): InvertedIndexStats {\n let maxDocuments = 0;\n let totalTokensPerDoc = 0;\n\n for (const keys of this.tokenIndex.values()) {\n if (keys.size > maxDocuments) {\n maxDocuments = keys.size;\n }\n }\n\n for (const tokens of this.reverseIndex.values()) {\n totalTokensPerDoc += tokens.size;\n }\n\n return {\n ...this.getStats(),\n totalTokens: this.tokenIndex.size,\n avgTokensPerDocument:\n this.reverseIndex.size > 0 ? totalTokensPerDoc / this.reverseIndex.size : 0,\n maxDocumentsPerToken: maxDocuments,\n };\n }\n\n /**\n * Get the tokenization pipeline.\n */\n getPipeline(): TokenizationPipeline {\n return this.pipeline;\n }\n\n /**\n * Check if a specific token exists in the index.\n */\n hasToken(token: string): boolean {\n return this.tokenIndex.has(token);\n }\n\n /**\n * Get the number of documents for a specific token.\n */\n getTokenDocumentCount(token: string): number {\n return this.tokenIndex.get(token)?.size ?? 0;\n }\n\n // ==================== Private Helpers ====================\n\n private valuesEqual(a: A[], b: A[]): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n }\n}\n","/**\n * CompoundIndex Implementation (Phase 9.03)\n *\n * Multi-attribute index for optimizing AND queries.\n * Creates a composite key from multiple attribute values for O(1) lookup.\n *\n * Benefits:\n * - 100-1000× speedup for compound AND queries\n * - Eliminates ResultSet intersection overhead\n * - Single lookup instead of multiple index scans\n *\n * @module query/indexes/CompoundIndex\n */\n\nimport type { Attribute } from '../Attribute';\nimport type { Index, IndexQuery, IndexStats } from './types';\nimport type { ResultSet } from '../resultset/ResultSet';\nimport { SetResultSet } from '../resultset/SetResultSet';\n\n/**\n * Compound query specification for multi-attribute matching.\n */\nexport interface CompoundQuery<A = unknown> {\n /** Query type - only 'compound' for compound indexes */\n type: 'compound';\n /** Array of attribute values in order of compound index attributes */\n values: A[];\n}\n\n/**\n * Options for compound index creation.\n */\nexport interface CompoundIndexOptions {\n /**\n * Separator for composite key generation.\n * Default: '|'\n * Choose a separator that won't appear in attribute values.\n */\n separator?: string;\n}\n\n/**\n * Compound index for O(1) multi-attribute queries.\n * Indexes multiple attributes as a single composite key.\n *\n * K = record key type, V = record value type\n */\nexport class CompoundIndex<K, V> implements Index<K, V, unknown> {\n readonly type = 'compound' as const;\n\n /** Attributes that make up this compound index (in order) */\n private readonly _attributes: Attribute<V, unknown>[];\n\n /** Map from composite key to set of record keys */\n private data: Map<string, Set<K>> = new Map();\n\n /** Set of all indexed keys */\n private allKeys: Set<K> = new Set();\n\n /** Key separator */\n private readonly separator: string;\n\n /** Retrieval cost (lower than individual indexes combined) */\n private static readonly RETRIEVAL_COST = 20;\n\n /**\n * Create a CompoundIndex.\n *\n * @param attributes - Array of attributes to index (order matters!)\n * @param options - Optional configuration\n *\n * @example\n * ```typescript\n * const statusAttr = simpleAttribute<Product, string>('status', p => p.status);\n * const categoryAttr = simpleAttribute<Product, string>('category', p => p.category);\n *\n * const compoundIndex = new CompoundIndex<string, Product>([statusAttr, categoryAttr]);\n * ```\n */\n constructor(\n attributes: Attribute<V, unknown>[],\n options: CompoundIndexOptions = {}\n ) {\n if (attributes.length < 2) {\n throw new Error('CompoundIndex requires at least 2 attributes');\n }\n this._attributes = attributes;\n this.separator = options.separator ?? '|';\n }\n\n /**\n * Get the first attribute (used for Index interface compatibility).\n * Note: CompoundIndex spans multiple attributes.\n */\n get attribute(): Attribute<V, unknown> {\n return this._attributes[0];\n }\n\n /**\n * Get all attributes in this compound index.\n */\n get attributes(): Attribute<V, unknown>[] {\n return [...this._attributes];\n }\n\n /**\n * Get attribute names as a combined identifier.\n */\n get compoundName(): string {\n return this._attributes.map((a) => a.name).join('+');\n }\n\n getRetrievalCost(): number {\n return CompoundIndex.RETRIEVAL_COST;\n }\n\n supportsQuery(queryType: string): boolean {\n return queryType === 'compound';\n }\n\n /**\n * Retrieve records matching compound query.\n *\n * @param query - Compound query with values matching each attribute\n * @returns ResultSet of matching keys\n *\n * @example\n * ```typescript\n * // Find products where status='active' AND category='electronics'\n * index.retrieve({\n * type: 'compound',\n * values: ['active', 'electronics']\n * });\n * ```\n */\n retrieve(query: IndexQuery<unknown>): ResultSet<K> {\n if (query.type !== 'compound') {\n throw new Error(`CompoundIndex only supports 'compound' query type, got: ${query.type}`);\n }\n\n const compoundQuery = query as unknown as CompoundQuery;\n const values = compoundQuery.values;\n\n if (values.length !== this._attributes.length) {\n throw new Error(\n `CompoundIndex requires ${this._attributes.length} values, got ${values.length}`\n );\n }\n\n const compositeKey = this.buildCompositeKey(values);\n const keys = this.data.get(compositeKey);\n\n return new SetResultSet(\n keys ? new Set(keys) : new Set(),\n CompoundIndex.RETRIEVAL_COST\n );\n }\n\n /**\n * Retrieve with explicit values (convenience method).\n *\n * @param values - Values in order of index attributes\n * @returns ResultSet of matching keys\n */\n retrieveByValues(...values: unknown[]): ResultSet<K> {\n return this.retrieve({ type: 'compound', values } as IndexQuery<unknown>);\n }\n\n add(key: K, record: V): void {\n const compositeKey = this.buildCompositeKeyFromRecord(record);\n if (compositeKey === null) return;\n\n let keys = this.data.get(compositeKey);\n if (!keys) {\n keys = new Set();\n this.data.set(compositeKey, keys);\n }\n keys.add(key);\n this.allKeys.add(key);\n }\n\n remove(key: K, record: V): void {\n const compositeKey = this.buildCompositeKeyFromRecord(record);\n if (compositeKey === null) return;\n\n const keys = this.data.get(compositeKey);\n if (keys) {\n keys.delete(key);\n if (keys.size === 0) {\n this.data.delete(compositeKey);\n }\n }\n this.allKeys.delete(key);\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n const oldKey = this.buildCompositeKeyFromRecord(oldRecord);\n const newKey = this.buildCompositeKeyFromRecord(newRecord);\n\n // Optimize: check if composite key changed\n if (oldKey === newKey) {\n return;\n }\n\n this.remove(key, oldRecord);\n this.add(key, newRecord);\n }\n\n clear(): void {\n this.data.clear();\n this.allKeys.clear();\n }\n\n getStats(): IndexStats {\n let totalEntries = 0;\n for (const keys of this.data.values()) {\n totalEntries += keys.size;\n }\n\n return {\n distinctValues: this.data.size,\n totalEntries,\n avgEntriesPerValue: this.data.size > 0 ? totalEntries / this.data.size : 0,\n };\n }\n\n /**\n * Get extended statistics for compound index.\n */\n getExtendedStats(): CompoundIndexStats {\n const stats = this.getStats();\n return {\n ...stats,\n attributeCount: this._attributes.length,\n attributeNames: this._attributes.map((a) => a.name),\n compositeKeyCount: this.data.size,\n };\n }\n\n /**\n * Check if this compound index can answer a query on the given attributes.\n * Compound indexes can be used if query attributes match in prefix order.\n *\n * @param attributeNames - Attribute names being queried\n * @returns true if this index can answer the query\n */\n canAnswerQuery(attributeNames: string[]): boolean {\n if (attributeNames.length !== this._attributes.length) {\n return false;\n }\n\n // Check if all attribute names match (order matters for now)\n for (let i = 0; i < attributeNames.length; i++) {\n if (attributeNames[i] !== this._attributes[i].name) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Build composite key from array of values.\n */\n private buildCompositeKey(values: unknown[]): string {\n return values.map((v) => this.encodeValue(v)).join(this.separator);\n }\n\n /**\n * Build composite key from record by extracting attribute values.\n * Returns null if any attribute value is undefined.\n */\n private buildCompositeKeyFromRecord(record: V): string | null {\n const values: unknown[] = [];\n\n for (const attr of this._attributes) {\n const value = attr.getValue(record);\n if (value === undefined) {\n return null; // Can't index record with missing attribute\n }\n values.push(value);\n }\n\n return this.buildCompositeKey(values);\n }\n\n /**\n * Encode value for composite key.\n * Handles common types and escapes separator.\n */\n private encodeValue(value: unknown): string {\n if (value === null) return '__null__';\n if (value === undefined) return '__undefined__';\n\n const str = String(value);\n // Escape any separator characters in the value\n return str.replace(\n new RegExp(this.escapeRegex(this.separator), 'g'),\n `\\\\${this.separator}`\n );\n }\n\n /**\n * Escape regex special characters.\n */\n private escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n }\n}\n\n/**\n * Extended statistics for compound index.\n */\nexport interface CompoundIndexStats extends IndexStats {\n /** Number of attributes in compound key */\n attributeCount: number;\n /** Names of indexed attributes */\n attributeNames: string[];\n /** Number of unique composite keys */\n compositeKeyCount: number;\n}\n\n/**\n * Helper to check if an index is a compound index.\n */\nexport function isCompoundIndex<K, V>(index: Index<K, V, unknown>): index is CompoundIndex<K, V> {\n return index.type === 'compound';\n}\n","/**\n * LazyHashIndex Implementation\n *\n * Hash-based index with deferred building (Phase 9.01).\n * Records are buffered until first query, then index is materialized.\n *\n * Benefits:\n * - Fast application startup (indexes built on-demand)\n * - Memory efficiency (unused indexes not built)\n * - Bulk import optimization (no index overhead during import)\n *\n * @module query/indexes/lazy/LazyHashIndex\n */\n\nimport type { Attribute } from '../../Attribute';\nimport type { Index, IndexQuery, IndexStats } from '../types';\nimport type { ResultSet } from '../../resultset/ResultSet';\nimport { HashIndex } from '../HashIndex';\nimport type { LazyIndex, LazyIndexOptions } from './types';\nimport type { IndexBuildProgressCallback } from '../../adaptive/types';\n\n/**\n * Lazy hash-based index for O(1) equality lookups.\n * Defers index construction until first query.\n *\n * K = record key type, V = record value type, A = attribute value type\n */\nexport class LazyHashIndex<K, V, A> implements LazyIndex<K, V, A> {\n readonly type = 'hash' as const;\n readonly isLazy = true as const;\n\n /** Underlying hash index (created on first query) */\n private innerIndex: HashIndex<K, V, A> | null = null;\n\n /** Pending records before materialization */\n private pendingRecords: Map<K, V> = new Map();\n\n /** Track if index has been built */\n private built = false;\n\n /** Progress callback */\n private readonly onProgress?: IndexBuildProgressCallback;\n\n /** Batch size for progress reporting */\n private readonly progressBatchSize: number;\n\n constructor(\n readonly attribute: Attribute<V, A>,\n options: LazyIndexOptions = {}\n ) {\n this.onProgress = options.onProgress;\n this.progressBatchSize = options.progressBatchSize ?? 1000;\n }\n\n get isBuilt(): boolean {\n return this.built;\n }\n\n get pendingCount(): number {\n return this.pendingRecords.size;\n }\n\n getRetrievalCost(): number {\n // Return HashIndex cost\n return 30;\n }\n\n supportsQuery(queryType: string): boolean {\n return ['equal', 'in', 'has'].includes(queryType);\n }\n\n retrieve(query: IndexQuery<A>): ResultSet<K> {\n // Materialize on first query\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.retrieve(query);\n }\n\n add(key: K, record: V): void {\n if (this.built) {\n this.innerIndex!.add(key, record);\n } else {\n this.pendingRecords.set(key, record);\n }\n }\n\n remove(key: K, record: V): void {\n if (this.built) {\n this.innerIndex!.remove(key, record);\n } else {\n this.pendingRecords.delete(key);\n }\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n if (this.built) {\n this.innerIndex!.update(key, oldRecord, newRecord);\n } else {\n // Just update pending record\n this.pendingRecords.set(key, newRecord);\n }\n }\n\n clear(): void {\n if (this.built) {\n this.innerIndex!.clear();\n }\n this.pendingRecords.clear();\n }\n\n getStats(): IndexStats {\n if (this.built) {\n return this.innerIndex!.getStats();\n }\n // Return pending stats\n return {\n distinctValues: 0,\n totalEntries: this.pendingRecords.size,\n avgEntriesPerValue: 0,\n };\n }\n\n /**\n * Force materialization of the index.\n * Called automatically on first query.\n */\n materialize(progressCallback?: IndexBuildProgressCallback): void {\n if (this.built) return;\n\n const callback = progressCallback ?? this.onProgress;\n const total = this.pendingRecords.size;\n\n // Create inner index\n this.innerIndex = new HashIndex<K, V, A>(this.attribute);\n\n // Build from pending records\n let processed = 0;\n for (const [key, record] of this.pendingRecords) {\n this.innerIndex.add(key, record);\n processed++;\n\n // Report progress\n if (callback && processed % this.progressBatchSize === 0) {\n const progress = Math.round((processed / total) * 100);\n callback(this.attribute.name, progress, processed, total);\n }\n }\n\n // Final progress report\n if (callback && total > 0) {\n callback(this.attribute.name, 100, total, total);\n }\n\n // Clear pending and mark as built\n this.pendingRecords.clear();\n this.built = true;\n }\n\n /**\n * Get the underlying HashIndex (for testing/debugging).\n * Returns null if not yet materialized.\n */\n getInnerIndex(): HashIndex<K, V, A> | null {\n return this.innerIndex;\n }\n}\n","/**\n * LazyNavigableIndex Implementation\n *\n * Sorted index with deferred building (Phase 9.01).\n * Records are buffered until first query, then index is materialized.\n *\n * Benefits:\n * - Fast application startup (indexes built on-demand)\n * - Memory efficiency (unused indexes not built)\n * - Bulk import optimization (no index overhead during import)\n *\n * @module query/indexes/lazy/LazyNavigableIndex\n */\n\nimport type { Attribute } from '../../Attribute';\nimport type { Index, IndexQuery, IndexStats } from '../types';\nimport type { ResultSet } from '../../resultset/ResultSet';\nimport type { Comparator } from '../../ds/types';\nimport { NavigableIndex } from '../NavigableIndex';\nimport type { LazyIndex, LazyIndexOptions } from './types';\nimport type { IndexBuildProgressCallback } from '../../adaptive/types';\n\n/**\n * Lazy sorted index for O(log N) range queries.\n * Defers index construction until first query.\n *\n * K = record key type, V = record value type, A = attribute value type (must be orderable)\n */\nexport class LazyNavigableIndex<K, V, A extends string | number>\n implements LazyIndex<K, V, A>\n{\n readonly type = 'navigable' as const;\n readonly isLazy = true as const;\n\n /** Underlying navigable index (created on first query) */\n private innerIndex: NavigableIndex<K, V, A> | null = null;\n\n /** Pending records before materialization */\n private pendingRecords: Map<K, V> = new Map();\n\n /** Track if index has been built */\n private built = false;\n\n /** Custom comparator (stored for later index creation) */\n private readonly comparator?: Comparator<A>;\n\n /** Progress callback */\n private readonly onProgress?: IndexBuildProgressCallback;\n\n /** Batch size for progress reporting */\n private readonly progressBatchSize: number;\n\n constructor(\n readonly attribute: Attribute<V, A>,\n comparator?: Comparator<A>,\n options: LazyIndexOptions = {}\n ) {\n this.comparator = comparator;\n this.onProgress = options.onProgress;\n this.progressBatchSize = options.progressBatchSize ?? 1000;\n }\n\n get isBuilt(): boolean {\n return this.built;\n }\n\n get pendingCount(): number {\n return this.pendingRecords.size;\n }\n\n getRetrievalCost(): number {\n // Return NavigableIndex cost\n return 40;\n }\n\n supportsQuery(queryType: string): boolean {\n return ['equal', 'in', 'has', 'gt', 'gte', 'lt', 'lte', 'between'].includes(queryType);\n }\n\n retrieve(query: IndexQuery<A>): ResultSet<K> {\n // Materialize on first query\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.retrieve(query);\n }\n\n add(key: K, record: V): void {\n if (this.built) {\n this.innerIndex!.add(key, record);\n } else {\n this.pendingRecords.set(key, record);\n }\n }\n\n remove(key: K, record: V): void {\n if (this.built) {\n this.innerIndex!.remove(key, record);\n } else {\n this.pendingRecords.delete(key);\n }\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n if (this.built) {\n this.innerIndex!.update(key, oldRecord, newRecord);\n } else {\n // Just update pending record\n this.pendingRecords.set(key, newRecord);\n }\n }\n\n clear(): void {\n if (this.built) {\n this.innerIndex!.clear();\n }\n this.pendingRecords.clear();\n }\n\n getStats(): IndexStats {\n if (this.built) {\n return this.innerIndex!.getStats();\n }\n // Return pending stats\n return {\n distinctValues: 0,\n totalEntries: this.pendingRecords.size,\n avgEntriesPerValue: 0,\n };\n }\n\n /**\n * Force materialization of the index.\n * Called automatically on first query.\n */\n materialize(progressCallback?: IndexBuildProgressCallback): void {\n if (this.built) return;\n\n const callback = progressCallback ?? this.onProgress;\n const total = this.pendingRecords.size;\n\n // Create inner index with comparator\n this.innerIndex = new NavigableIndex<K, V, A>(this.attribute, this.comparator);\n\n // Build from pending records\n let processed = 0;\n for (const [key, record] of this.pendingRecords) {\n this.innerIndex.add(key, record);\n processed++;\n\n // Report progress\n if (callback && processed % this.progressBatchSize === 0) {\n const progress = Math.round((processed / total) * 100);\n callback(this.attribute.name, progress, processed, total);\n }\n }\n\n // Final progress report\n if (callback && total > 0) {\n callback(this.attribute.name, 100, total, total);\n }\n\n // Clear pending and mark as built\n this.pendingRecords.clear();\n this.built = true;\n }\n\n /**\n * Get the underlying NavigableIndex (for testing/debugging).\n * Returns null if not yet materialized.\n */\n getInnerIndex(): NavigableIndex<K, V, A> | null {\n return this.innerIndex;\n }\n\n /**\n * Get the minimum indexed value.\n * Forces materialization if not built.\n */\n getMinValue(): A | undefined {\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.getMinValue();\n }\n\n /**\n * Get the maximum indexed value.\n * Forces materialization if not built.\n */\n getMaxValue(): A | undefined {\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.getMaxValue();\n }\n}\n","/**\n * LazyInvertedIndex Implementation\n *\n * Full-text search index with deferred building (Phase 9.01).\n * Records are buffered until first query, then index is materialized.\n *\n * Benefits:\n * - Fast application startup (indexes built on-demand)\n * - Memory efficiency (unused indexes not built)\n * - Bulk import optimization (no index overhead during import)\n *\n * @module query/indexes/lazy/LazyInvertedIndex\n */\n\nimport type { Attribute } from '../../Attribute';\nimport type { Index, IndexQuery, IndexStats } from '../types';\nimport type { ResultSet } from '../../resultset/ResultSet';\nimport { InvertedIndex, type InvertedIndexStats } from '../InvertedIndex';\nimport { TokenizationPipeline } from '../../tokenization';\nimport type { LazyIndex, LazyIndexOptions } from './types';\nimport type { IndexBuildProgressCallback } from '../../adaptive/types';\n\n/**\n * Lazy inverted index for full-text search.\n * Defers index construction until first query.\n *\n * K = record key type, V = record value type, A = attribute value type (should be string)\n */\nexport class LazyInvertedIndex<K, V, A extends string = string>\n implements LazyIndex<K, V, A>\n{\n readonly type = 'inverted' as const;\n readonly isLazy = true as const;\n\n /** Underlying inverted index (created on first query) */\n private innerIndex: InvertedIndex<K, V, A> | null = null;\n\n /** Pending records before materialization */\n private pendingRecords: Map<K, V> = new Map();\n\n /** Track if index has been built */\n private built = false;\n\n /** Tokenization pipeline (stored for later index creation) */\n private readonly pipeline: TokenizationPipeline;\n\n /** Progress callback */\n private readonly onProgress?: IndexBuildProgressCallback;\n\n /** Batch size for progress reporting */\n private readonly progressBatchSize: number;\n\n constructor(\n readonly attribute: Attribute<V, A>,\n pipeline?: TokenizationPipeline,\n options: LazyIndexOptions = {}\n ) {\n this.pipeline = pipeline ?? TokenizationPipeline.simple();\n this.onProgress = options.onProgress;\n this.progressBatchSize = options.progressBatchSize ?? 1000;\n }\n\n get isBuilt(): boolean {\n return this.built;\n }\n\n get pendingCount(): number {\n return this.pendingRecords.size;\n }\n\n getRetrievalCost(): number {\n // Return InvertedIndex cost\n return 50;\n }\n\n supportsQuery(queryType: string): boolean {\n return ['contains', 'containsAll', 'containsAny', 'has'].includes(queryType);\n }\n\n retrieve(query: IndexQuery<A>): ResultSet<K> {\n // Materialize on first query\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.retrieve(query);\n }\n\n add(key: K, record: V): void {\n if (this.built) {\n this.innerIndex!.add(key, record);\n } else {\n this.pendingRecords.set(key, record);\n }\n }\n\n remove(key: K, record: V): void {\n if (this.built) {\n this.innerIndex!.remove(key, record);\n } else {\n this.pendingRecords.delete(key);\n }\n }\n\n update(key: K, oldRecord: V, newRecord: V): void {\n if (this.built) {\n this.innerIndex!.update(key, oldRecord, newRecord);\n } else {\n // Just update pending record\n this.pendingRecords.set(key, newRecord);\n }\n }\n\n clear(): void {\n if (this.built) {\n this.innerIndex!.clear();\n }\n this.pendingRecords.clear();\n }\n\n getStats(): IndexStats {\n if (this.built) {\n return this.innerIndex!.getStats();\n }\n // Return pending stats\n return {\n distinctValues: 0,\n totalEntries: this.pendingRecords.size,\n avgEntriesPerValue: 0,\n };\n }\n\n /**\n * Get extended statistics for full-text index.\n * Forces materialization if not built.\n */\n getExtendedStats(): InvertedIndexStats {\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.getExtendedStats();\n }\n\n /**\n * Force materialization of the index.\n * Called automatically on first query.\n */\n materialize(progressCallback?: IndexBuildProgressCallback): void {\n if (this.built) return;\n\n const callback = progressCallback ?? this.onProgress;\n const total = this.pendingRecords.size;\n\n // Create inner index with pipeline\n this.innerIndex = new InvertedIndex<K, V, A>(this.attribute, this.pipeline);\n\n // Build from pending records\n let processed = 0;\n for (const [key, record] of this.pendingRecords) {\n this.innerIndex.add(key, record);\n processed++;\n\n // Report progress\n if (callback && processed % this.progressBatchSize === 0) {\n const progress = Math.round((processed / total) * 100);\n callback(this.attribute.name, progress, processed, total);\n }\n }\n\n // Final progress report\n if (callback && total > 0) {\n callback(this.attribute.name, 100, total, total);\n }\n\n // Clear pending and mark as built\n this.pendingRecords.clear();\n this.built = true;\n }\n\n /**\n * Get the underlying InvertedIndex (for testing/debugging).\n * Returns null if not yet materialized.\n */\n getInnerIndex(): InvertedIndex<K, V, A> | null {\n return this.innerIndex;\n }\n\n /**\n * Get the tokenization pipeline.\n */\n getPipeline(): TokenizationPipeline {\n return this.pipeline;\n }\n\n /**\n * Check if a specific token exists in the index.\n * Forces materialization if not built.\n */\n hasToken(token: string): boolean {\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.hasToken(token);\n }\n\n /**\n * Get the number of documents for a specific token.\n * Forces materialization if not built.\n */\n getTokenDocumentCount(token: string): number {\n if (!this.built) {\n this.materialize();\n }\n return this.innerIndex!.getTokenDocumentCount(token);\n }\n}\n","/**\n * IntersectionResultSet Implementation\n *\n * Intersection of multiple result sets (AND logic).\n * Implements CQEngine \"smallest first\" strategy:\n * iterate the smallest set, check membership in others.\n *\n * @module query/resultset/IntersectionResultSet\n */\n\nimport type { ResultSet } from './ResultSet';\n\n/**\n * Intersection of multiple result sets (AND logic).\n * CQEngine strategy: iterate smallest set, check membership in others.\n *\n * K = record key type\n */\nexport class IntersectionResultSet<K> implements ResultSet<K> {\n /** Cached materialized results */\n private cached: K[] | null = null;\n\n /** Result sets sorted by merge cost */\n private sortedResultSets: ResultSet<K>[];\n\n /**\n * Create an IntersectionResultSet.\n *\n * @param resultSets - Result sets to intersect\n */\n constructor(resultSets: ResultSet<K>[]) {\n // Sort by merge cost (ascending) - iterate smallest first\n this.sortedResultSets = [...resultSets].sort(\n (a, b) => a.getMergeCost() - b.getMergeCost()\n );\n }\n\n /**\n * Lazy iteration over intersection.\n * Iterates smallest set, yields only keys present in all sets.\n */\n *[Symbol.iterator](): Generator<K> {\n // Use cached results if available\n if (this.cached) {\n yield* this.cached;\n return;\n }\n\n // Empty intersection if no result sets\n if (this.sortedResultSets.length === 0) {\n return;\n }\n\n // Get smallest set (first after sort)\n const [smallest, ...rest] = this.sortedResultSets;\n\n // Iterate smallest, check membership in all others\n for (const key of smallest) {\n if (rest.every((rs) => rs.contains(key))) {\n yield key;\n }\n }\n }\n\n /**\n * Retrieval cost is minimum of all (we only iterate smallest).\n */\n getRetrievalCost(): number {\n if (this.sortedResultSets.length === 0) {\n return 0;\n }\n return Math.min(...this.sortedResultSets.map((rs) => rs.getRetrievalCost()));\n }\n\n /**\n * Merge cost is estimated as smallest set size (upper bound).\n */\n getMergeCost(): number {\n if (this.sortedResultSets.length === 0) {\n return 0;\n }\n // After sorting, first has smallest merge cost\n return this.sortedResultSets[0].getMergeCost();\n }\n\n /**\n * Check if key is in all result sets.\n */\n contains(key: K): boolean {\n return this.sortedResultSets.every((rs) => rs.contains(key));\n }\n\n /**\n * Get size by materializing results.\n */\n size(): number {\n return this.toArray().length;\n }\n\n /**\n * Materialize to array with caching.\n */\n toArray(): K[] {\n if (!this.cached) {\n this.cached = [...this];\n }\n return this.cached;\n }\n\n /**\n * Check if empty (tries to avoid full materialization).\n */\n isEmpty(): boolean {\n // If cached, use cached value\n if (this.cached) {\n return this.cached.length === 0;\n }\n\n // If any source is empty, intersection is empty\n if (this.sortedResultSets.some((rs) => rs.isEmpty())) {\n return true;\n }\n\n // Check by trying to get first element\n for (const _ of this) {\n return false;\n }\n return true;\n }\n\n /**\n * Check if results have been materialized.\n */\n isMaterialized(): boolean {\n return this.cached !== null;\n }\n}\n","/**\n * UnionResultSet Implementation\n *\n * Union of multiple result sets (OR logic).\n * Deduplicates results using a Set during iteration.\n *\n * @module query/resultset/UnionResultSet\n */\n\nimport type { ResultSet } from './ResultSet';\n\n/**\n * Union of multiple result sets (OR logic).\n * Deduplicates results.\n *\n * K = record key type\n */\nexport class UnionResultSet<K> implements ResultSet<K> {\n /** Cached materialized results */\n private cached: K[] | null = null;\n\n /**\n * Create a UnionResultSet.\n *\n * @param resultSets - Result sets to union\n */\n constructor(private readonly resultSets: ResultSet<K>[]) {}\n\n /**\n * Lazy iteration over union with deduplication.\n */\n *[Symbol.iterator](): Generator<K> {\n // Use cached results if available\n if (this.cached) {\n yield* this.cached;\n return;\n }\n\n // Track seen keys to avoid duplicates\n const seen = new Set<K>();\n\n for (const rs of this.resultSets) {\n for (const key of rs) {\n if (!seen.has(key)) {\n seen.add(key);\n yield key;\n }\n }\n }\n }\n\n /**\n * Retrieval cost is sum of all costs.\n */\n getRetrievalCost(): number {\n return this.resultSets.reduce((sum, rs) => {\n const cost = rs.getRetrievalCost();\n // Avoid overflow\n if (cost === Number.MAX_SAFE_INTEGER || sum === Number.MAX_SAFE_INTEGER) {\n return Number.MAX_SAFE_INTEGER;\n }\n return Math.min(sum + cost, Number.MAX_SAFE_INTEGER);\n }, 0);\n }\n\n /**\n * Merge cost upper bound: sum of all sizes.\n */\n getMergeCost(): number {\n return this.resultSets.reduce((sum, rs) => sum + rs.getMergeCost(), 0);\n }\n\n /**\n * Check if key is in any result set.\n */\n contains(key: K): boolean {\n return this.resultSets.some((rs) => rs.contains(key));\n }\n\n /**\n * Get size by materializing results.\n */\n size(): number {\n return this.toArray().length;\n }\n\n /**\n * Materialize to array with caching.\n */\n toArray(): K[] {\n if (!this.cached) {\n this.cached = [...this];\n }\n return this.cached;\n }\n\n /**\n * Check if empty (all sources must be empty).\n */\n isEmpty(): boolean {\n // If cached, use cached value\n if (this.cached) {\n return this.cached.length === 0;\n }\n\n // Union is empty only if all sources are empty\n return this.resultSets.every((rs) => rs.isEmpty());\n }\n\n /**\n * Check if results have been materialized.\n */\n isMaterialized(): boolean {\n return this.cached !== null;\n }\n}\n","/**\n * FilteringResultSet Implementation\n *\n * Filters a source result set with a predicate.\n * Used when an index is available for part of a query,\n * but additional filtering is needed.\n *\n * @module query/resultset/FilteringResultSet\n */\n\nimport type { ResultSet } from './ResultSet';\n\n/**\n * Predicate function for filtering records.\n */\nexport type PredicateFn<V> = (record: V) => boolean;\n\n/**\n * Filters a source result set with a predicate.\n *\n * K = record key type, V = record value type\n */\nexport class FilteringResultSet<K, V> implements ResultSet<K> {\n /** Cached materialized results */\n private cached: K[] | null = null;\n\n /**\n * Create a FilteringResultSet.\n *\n * @param source - Source result set to filter\n * @param getRecord - Function to get record by key\n * @param predicate - Predicate function to filter records\n */\n constructor(\n private readonly source: ResultSet<K>,\n private readonly getRecord: (key: K) => V | undefined,\n private readonly predicate: PredicateFn<V>\n ) {}\n\n /**\n * Lazy iteration with filtering.\n */\n *[Symbol.iterator](): Generator<K> {\n // Use cached results if available\n if (this.cached) {\n yield* this.cached;\n return;\n }\n\n for (const key of this.source) {\n const record = this.getRecord(key);\n if (record !== undefined && this.predicate(record)) {\n yield key;\n }\n }\n }\n\n /**\n * Retrieval cost: source cost + filter overhead.\n */\n getRetrievalCost(): number {\n return this.source.getRetrievalCost() + 10;\n }\n\n /**\n * Merge cost: estimate half of source (pessimistic).\n */\n getMergeCost(): number {\n return Math.max(1, Math.ceil(this.source.getMergeCost() / 2));\n }\n\n /**\n * Check if key is in source and passes predicate.\n */\n contains(key: K): boolean {\n if (!this.source.contains(key)) {\n return false;\n }\n const record = this.getRecord(key);\n return record !== undefined && this.predicate(record);\n }\n\n /**\n * Get size by materializing results.\n */\n size(): number {\n return this.toArray().length;\n }\n\n /**\n * Materialize to array with caching.\n */\n toArray(): K[] {\n if (!this.cached) {\n this.cached = [...this];\n }\n return this.cached;\n }\n\n /**\n * Check if empty (tries to find at least one match).\n */\n isEmpty(): boolean {\n // If cached, use cached value\n if (this.cached) {\n return this.cached.length === 0;\n }\n\n // Try to find at least one matching element\n for (const _ of this) {\n return false;\n }\n return true;\n }\n\n /**\n * Check if results have been materialized.\n */\n isMaterialized(): boolean {\n return this.cached !== null;\n }\n}\n","/**\n * SortedResultSet Implementation\n *\n * ResultSet with sorting support.\n * If source is from NavigableIndex on sort field, results are already sorted.\n * Otherwise, performs in-memory sort.\n *\n * @module query/resultset/SortedResultSet\n */\n\nimport type { ResultSet } from './ResultSet';\n\n/**\n * Comparator function for sorting.\n */\nexport type CompareFn<V> = (a: V, b: V) => number;\n\n/**\n * ResultSet with sorting support.\n *\n * K = record key type, V = record value type\n */\nexport class SortedResultSet<K, V> implements ResultSet<K> {\n /** Cached sorted results */\n private cached: K[] | null = null;\n\n /**\n * Create a SortedResultSet.\n *\n * @param source - Source result set\n * @param getRecord - Function to get record by key\n * @param sortField - Field to sort by\n * @param direction - Sort direction ('asc' or 'desc')\n * @param isPreSorted - Whether source is already sorted (from NavigableIndex)\n */\n constructor(\n private readonly source: ResultSet<K>,\n private readonly getRecord: (key: K) => V | undefined,\n private readonly sortField: string,\n private readonly direction: 'asc' | 'desc',\n private readonly isPreSorted: boolean = false\n ) {}\n\n /**\n * Lazy iteration with sorting.\n */\n *[Symbol.iterator](): Generator<K> {\n // Use cached results if available\n if (this.cached) {\n yield* this.cached;\n return;\n }\n\n // If pre-sorted (from NavigableIndex), handle direction\n if (this.isPreSorted) {\n if (this.direction === 'desc') {\n // Reverse iteration for descending\n const keys = [...this.source];\n for (let i = keys.length - 1; i >= 0; i--) {\n yield keys[i];\n }\n } else {\n // Forward iteration for ascending\n yield* this.source;\n }\n return;\n }\n\n // In-memory sort\n yield* this.toArray();\n }\n\n /**\n * Materialize to sorted array with caching.\n */\n toArray(): K[] {\n if (this.cached) {\n return this.cached;\n }\n\n const keys = [...this.source];\n\n if (!this.isPreSorted) {\n // In-memory sort\n keys.sort((a, b) => {\n const recA = this.getRecord(a);\n const recB = this.getRecord(b);\n\n if (recA === undefined && recB === undefined) return 0;\n if (recA === undefined) return this.direction === 'asc' ? 1 : -1;\n if (recB === undefined) return this.direction === 'asc' ? -1 : 1;\n\n const valA = (recA as Record<string, unknown>)[this.sortField];\n const valB = (recB as Record<string, unknown>)[this.sortField];\n\n let cmp = 0;\n if (valA === undefined || valA === null) {\n if (valB === undefined || valB === null) {\n cmp = 0;\n } else {\n cmp = 1;\n }\n } else if (valB === undefined || valB === null) {\n cmp = -1;\n } else if (valA < valB) {\n cmp = -1;\n } else if (valA > valB) {\n cmp = 1;\n }\n\n return this.direction === 'desc' ? -cmp : cmp;\n });\n } else if (this.direction === 'desc') {\n // Pre-sorted, just reverse for descending\n keys.reverse();\n }\n\n this.cached = keys;\n return keys;\n }\n\n /**\n * Retrieval cost: source cost + sort overhead.\n * Pre-sorted has minimal overhead.\n */\n getRetrievalCost(): number {\n const baseCost = this.source.getRetrievalCost();\n // Pre-sorted: minimal overhead\n // In-memory sort: O(N log N) overhead\n const sortOverhead = this.isPreSorted ? 1 : 50;\n return baseCost + sortOverhead;\n }\n\n /**\n * Merge cost: same as source (sorting doesn't change size).\n */\n getMergeCost(): number {\n return this.source.getMergeCost();\n }\n\n /**\n * Check if key is in source.\n */\n contains(key: K): boolean {\n return this.source.contains(key);\n }\n\n /**\n * Get size (same as source).\n */\n size(): number {\n return this.source.size();\n }\n\n /**\n * Check if empty.\n */\n isEmpty(): boolean {\n return this.source.isEmpty();\n }\n\n /**\n * Check if results have been materialized.\n */\n isMaterialized(): boolean {\n return this.cached !== null;\n }\n\n /**\n * Check if this result set is pre-sorted.\n */\n isIndexSorted(): boolean {\n return this.isPreSorted;\n }\n\n /**\n * Get sort field.\n */\n getSortField(): string {\n return this.sortField;\n }\n\n /**\n * Get sort direction.\n */\n getSortDirection(): 'asc' | 'desc' {\n return this.direction;\n }\n}\n\n/**\n * Create a comparator function for a field.\n *\n * @param field - Field name to compare\n * @param direction - Sort direction\n */\nexport function createFieldComparator<V>(\n field: string,\n direction: 'asc' | 'desc'\n): CompareFn<V> {\n return (a: V, b: V): number => {\n const valA = (a as Record<string, unknown>)[field];\n const valB = (b as Record<string, unknown>)[field];\n\n let cmp = 0;\n if (valA === undefined || valA === null) {\n if (valB === undefined || valB === null) {\n cmp = 0;\n } else {\n cmp = 1;\n }\n } else if (valB === undefined || valB === null) {\n cmp = -1;\n } else if (valA < valB) {\n cmp = -1;\n } else if (valA > valB) {\n cmp = 1;\n }\n\n // Avoid -0 result when cmp is 0\n if (cmp === 0) return 0;\n return direction === 'desc' ? -cmp : cmp;\n };\n}\n","/**\n * LimitResultSet Implementation\n *\n * Applies offset/limit to source ResultSet.\n * Implements early termination for efficiency.\n *\n * NOTE: The offset parameter is intentionally retained in this internal component\n * even though Phase 14.1 replaced offset with cursor-based pagination in the query API.\n * This class is used internally by:\n * - EventJournalService (SQL queries require numeric offset)\n * - Index result set operations where offset is computed internally\n * - Unit tests for result set behavior\n *\n * The query API (QueryOptions, QueryHandle) uses cursor-based pagination via QueryCursor.\n *\n * @module query/resultset/LimitResultSet\n */\n\nimport type { ResultSet } from './ResultSet';\n\n/**\n * Applies offset/limit to source ResultSet.\n * Implements early termination for efficiency.\n *\n * K = record key type\n */\nexport class LimitResultSet<K> implements ResultSet<K> {\n /** Cached materialized results */\n private cached: K[] | null = null;\n\n /**\n * Create a LimitResultSet.\n *\n * @param source - Source result set\n * @param offset - Number of results to skip (default: 0)\n * @param limit - Maximum number of results (default: Infinity)\n */\n constructor(\n private readonly source: ResultSet<K>,\n private readonly offset: number = 0,\n private readonly limit: number = Infinity\n ) {}\n\n /**\n * Lazy iteration with offset/limit and early termination.\n */\n *[Symbol.iterator](): Generator<K> {\n // Use cached results if available\n if (this.cached) {\n yield* this.cached;\n return;\n }\n\n // If no offset and no limit, just pass through\n if (this.offset === 0 && this.limit === Infinity) {\n yield* this.source;\n return;\n }\n\n let skipped = 0;\n let returned = 0;\n\n for (const key of this.source) {\n // Skip offset\n if (skipped < this.offset) {\n skipped++;\n continue;\n }\n\n // Early termination when limit reached\n if (returned >= this.limit) {\n break;\n }\n\n yield key;\n returned++;\n }\n }\n\n /**\n * Retrieval cost: source cost (limit doesn't change retrieval cost).\n */\n getRetrievalCost(): number {\n return this.source.getRetrievalCost();\n }\n\n /**\n * Merge cost: min(source size, offset + limit).\n */\n getMergeCost(): number {\n const sourceCost = this.source.getMergeCost();\n if (this.limit === Infinity) {\n return Math.max(0, sourceCost - this.offset);\n }\n return Math.min(sourceCost, this.offset + this.limit);\n }\n\n /**\n * Check if key is in result (with offset/limit constraints).\n * This is expensive as it requires iteration to determine position.\n */\n contains(key: K): boolean {\n // First check if key is in source at all\n if (!this.source.contains(key)) {\n return false;\n }\n\n // Need to materialize to check if key is within offset/limit\n return this.toArray().includes(key);\n }\n\n /**\n * Get size by materializing results.\n */\n size(): number {\n return this.toArray().length;\n }\n\n /**\n * Materialize to array with caching.\n */\n toArray(): K[] {\n if (!this.cached) {\n this.cached = [...this];\n }\n return this.cached;\n }\n\n /**\n * Check if empty.\n */\n isEmpty(): boolean {\n // If cached, use cached value\n if (this.cached) {\n return this.cached.length === 0;\n }\n\n // If limit is 0, always empty\n if (this.limit === 0) {\n return true;\n }\n\n // Try to get first element\n for (const _ of this) {\n return false;\n }\n return true;\n }\n\n /**\n * Check if results have been materialized.\n */\n isMaterialized(): boolean {\n return this.cached !== null;\n }\n\n /**\n * Get the offset value.\n */\n getOffset(): number {\n return this.offset;\n }\n\n /**\n * Get the limit value.\n */\n getLimit(): number {\n return this.limit;\n }\n}\n","/**\n * IndexRegistry Implementation\n *\n * Central registry for managing indexes on a collection.\n * Provides index lookup, lifecycle management, and bulk operations.\n *\n * @module query/IndexRegistry\n */\n\nimport type { Index, IndexQuery } from './indexes/types';\nimport type { Attribute } from './Attribute';\nimport { isCompoundIndex, type CompoundIndex } from './indexes/CompoundIndex';\n\n/**\n * Registry for managing indexes on a collection.\n * Provides index lookup and lifecycle management.\n *\n * K = record key type, V = record value type\n */\nexport class IndexRegistry<K, V> {\n /** Indexes grouped by attribute name */\n private attributeIndexes: Map<string, Index<K, V, unknown>[]> = new Map();\n\n /** Compound indexes (Phase 9.03) - keyed by sorted attribute names */\n private compoundIndexes: Map<string, CompoundIndex<K, V>> = new Map();\n\n /** Fallback index for full scan (optional) */\n private fallbackIndex: Index<K, V, unknown> | null = null;\n\n /**\n * Register an index for an attribute.\n * Multiple indexes can be registered for the same attribute.\n *\n * @param index - Index to register\n */\n addIndex<A>(index: Index<K, V, A>): void {\n // Handle compound indexes specially (Phase 9.03)\n if (isCompoundIndex(index)) {\n this.addCompoundIndex(index as unknown as CompoundIndex<K, V>);\n return;\n }\n\n const attrName = index.attribute.name;\n let indexes = this.attributeIndexes.get(attrName);\n\n if (!indexes) {\n indexes = [];\n this.attributeIndexes.set(attrName, indexes);\n }\n\n // Avoid duplicate registration\n if (!indexes.includes(index as Index<K, V, unknown>)) {\n indexes.push(index as Index<K, V, unknown>);\n }\n }\n\n /**\n * Register a compound index (Phase 9.03).\n *\n * @param index - Compound index to register\n */\n addCompoundIndex(index: CompoundIndex<K, V>): void {\n const key = this.makeCompoundKey(index.attributes.map((a) => a.name));\n this.compoundIndexes.set(key, index);\n }\n\n /**\n * Remove an index from the registry.\n *\n * @param index - Index to remove\n * @returns true if index was found and removed\n */\n removeIndex<A>(index: Index<K, V, A>): boolean {\n // Handle compound indexes specially (Phase 9.03)\n if (isCompoundIndex(index)) {\n return this.removeCompoundIndex(index as unknown as CompoundIndex<K, V>);\n }\n\n const attrName = index.attribute.name;\n const indexes = this.attributeIndexes.get(attrName);\n\n if (!indexes) {\n return false;\n }\n\n const idx = indexes.indexOf(index as Index<K, V, unknown>);\n if (idx === -1) {\n return false;\n }\n\n indexes.splice(idx, 1);\n\n // Clean up empty arrays\n if (indexes.length === 0) {\n this.attributeIndexes.delete(attrName);\n }\n\n return true;\n }\n\n /**\n * Remove a compound index (Phase 9.03).\n *\n * @param index - Compound index to remove\n * @returns true if index was found and removed\n */\n removeCompoundIndex(index: CompoundIndex<K, V>): boolean {\n const key = this.makeCompoundKey(index.attributes.map((a) => a.name));\n return this.compoundIndexes.delete(key);\n }\n\n /**\n * Get all indexes for an attribute.\n *\n * @param attributeName - Attribute name\n * @returns Array of indexes (empty if none)\n */\n getIndexes(attributeName: string): Index<K, V, unknown>[] {\n return this.attributeIndexes.get(attributeName) ?? [];\n }\n\n /**\n * Get all registered indexes across all attributes.\n *\n * @returns Array of all indexes\n */\n getAllIndexes(): Index<K, V, unknown>[] {\n const all: Index<K, V, unknown>[] = [];\n for (const indexes of this.attributeIndexes.values()) {\n all.push(...indexes);\n }\n return all;\n }\n\n /**\n * Get all indexed attribute names.\n *\n * @returns Array of attribute names\n */\n getIndexedAttributes(): string[] {\n return Array.from(this.attributeIndexes.keys());\n }\n\n /**\n * Check if an attribute has any indexes.\n *\n * @param attributeName - Attribute name\n * @returns true if attribute has indexes\n */\n hasIndex(attributeName: string): boolean {\n const indexes = this.attributeIndexes.get(attributeName);\n return indexes !== undefined && indexes.length > 0;\n }\n\n /**\n * Find the best index for a query type on an attribute.\n * Returns the index with lowest retrieval cost that supports the query type.\n *\n * @param attributeName - Attribute name to search on\n * @param queryType - Query type (e.g., 'equal', 'gt', 'between')\n * @returns Best matching index or null if none found\n */\n findBestIndex(\n attributeName: string,\n queryType: string\n ): Index<K, V, unknown> | null {\n const indexes = this.getIndexes(attributeName);\n let best: Index<K, V, unknown> | null = null;\n let bestCost = Infinity;\n\n for (const index of indexes) {\n if (index.supportsQuery(queryType) && index.getRetrievalCost() < bestCost) {\n best = index;\n bestCost = index.getRetrievalCost();\n }\n }\n\n return best;\n }\n\n /**\n * Find all indexes that support a query type on an attribute.\n *\n * @param attributeName - Attribute name\n * @param queryType - Query type\n * @returns Array of matching indexes sorted by retrieval cost\n */\n findIndexes(\n attributeName: string,\n queryType: string\n ): Index<K, V, unknown>[] {\n const indexes = this.getIndexes(attributeName);\n return indexes\n .filter((index) => index.supportsQuery(queryType))\n .sort((a, b) => a.getRetrievalCost() - b.getRetrievalCost());\n }\n\n // ========================================\n // Phase 9.03: Compound Index Methods\n // ========================================\n\n /**\n * Find a compound index that covers the given attribute names (Phase 9.03).\n * The compound index must cover ALL the attributes (exact match or superset).\n *\n * @param attributeNames - Array of attribute names to search for\n * @returns Matching compound index or null\n */\n findCompoundIndex(attributeNames: string[]): CompoundIndex<K, V> | null {\n if (attributeNames.length < 2) {\n return null;\n }\n\n // Try exact match first (most efficient)\n const key = this.makeCompoundKey(attributeNames);\n const exactMatch = this.compoundIndexes.get(key);\n if (exactMatch) {\n return exactMatch;\n }\n\n // No exact match - compound indexes require exact attribute match\n // (unlike SQL where prefix matching is possible)\n return null;\n }\n\n /**\n * Check if a compound index exists for the given attributes (Phase 9.03).\n *\n * @param attributeNames - Array of attribute names\n * @returns true if a compound index exists\n */\n hasCompoundIndex(attributeNames: string[]): boolean {\n return this.findCompoundIndex(attributeNames) !== null;\n }\n\n /**\n * Get all compound indexes (Phase 9.03).\n *\n * @returns Array of all compound indexes\n */\n getCompoundIndexes(): CompoundIndex<K, V>[] {\n return Array.from(this.compoundIndexes.values());\n }\n\n /**\n * Create a compound key from attribute names (sorted for consistency).\n */\n private makeCompoundKey(attributeNames: string[]): string {\n return [...attributeNames].sort().join('+');\n }\n\n /**\n * Set a fallback index for queries without a suitable index.\n * Typically a FallbackIndex that performs full scan.\n *\n * @param fallback - Fallback index\n */\n setFallbackIndex(fallback: Index<K, V, unknown>): void {\n this.fallbackIndex = fallback;\n }\n\n /**\n * Get the fallback index.\n *\n * @returns Fallback index or null if not set\n */\n getFallbackIndex(): Index<K, V, unknown> | null {\n return this.fallbackIndex;\n }\n\n /**\n * Notify all indexes of a record addition.\n * Should be called when a new record is added to the collection.\n *\n * @param key - Record key\n * @param record - Record value\n */\n onRecordAdded(key: K, record: V): void {\n for (const indexes of this.attributeIndexes.values()) {\n for (const index of indexes) {\n index.add(key, record);\n }\n }\n // Also update compound indexes (Phase 9.03)\n for (const compoundIndex of this.compoundIndexes.values()) {\n compoundIndex.add(key, record);\n }\n }\n\n /**\n * Notify all indexes of a record update.\n * Should be called when a record's value changes.\n *\n * @param key - Record key\n * @param oldRecord - Previous record value\n * @param newRecord - New record value\n */\n onRecordUpdated(key: K, oldRecord: V, newRecord: V): void {\n for (const indexes of this.attributeIndexes.values()) {\n for (const index of indexes) {\n index.update(key, oldRecord, newRecord);\n }\n }\n // Also update compound indexes (Phase 9.03)\n for (const compoundIndex of this.compoundIndexes.values()) {\n compoundIndex.update(key, oldRecord, newRecord);\n }\n }\n\n /**\n * Notify all indexes of a record removal.\n * Should be called when a record is removed from the collection.\n *\n * @param key - Record key\n * @param record - Removed record value\n */\n onRecordRemoved(key: K, record: V): void {\n for (const indexes of this.attributeIndexes.values()) {\n for (const index of indexes) {\n index.remove(key, record);\n }\n }\n // Also update compound indexes (Phase 9.03)\n for (const compoundIndex of this.compoundIndexes.values()) {\n compoundIndex.remove(key, record);\n }\n }\n\n /**\n * Clear all indexes.\n * Does not remove index registrations, only clears their data.\n */\n clear(): void {\n for (const indexes of this.attributeIndexes.values()) {\n for (const index of indexes) {\n index.clear();\n }\n }\n // Also clear compound indexes (Phase 9.03)\n for (const compoundIndex of this.compoundIndexes.values()) {\n compoundIndex.clear();\n }\n }\n\n /**\n * Get total number of registered indexes.\n */\n get size(): number {\n let count = 0;\n for (const indexes of this.attributeIndexes.values()) {\n count += indexes.length;\n }\n // Include compound indexes (Phase 9.03)\n count += this.compoundIndexes.size;\n return count;\n }\n\n /**\n * Get statistics about the registry.\n */\n getStats(): IndexRegistryStats {\n const indexes = this.getAllIndexes();\n const indexStats = indexes.map((index) => ({\n attribute: index.attribute.name,\n type: index.type,\n stats: index.getStats(),\n }));\n\n // Add compound index stats (Phase 9.03)\n for (const compoundIndex of this.compoundIndexes.values()) {\n indexStats.push({\n attribute: compoundIndex.compoundName,\n type: 'compound',\n stats: compoundIndex.getStats(),\n });\n }\n\n return {\n totalIndexes: indexes.length + this.compoundIndexes.size,\n indexedAttributes: this.getIndexedAttributes().length,\n compoundIndexes: this.compoundIndexes.size,\n indexes: indexStats,\n };\n }\n}\n\n/**\n * Statistics about the IndexRegistry.\n */\nexport interface IndexRegistryStats {\n /** Total number of indexes */\n totalIndexes: number;\n /** Number of indexed attributes */\n indexedAttributes: number;\n /** Number of compound indexes (Phase 9.03) */\n compoundIndexes?: number;\n /** Stats for each index */\n indexes: Array<{\n attribute: string;\n type: string;\n stats: {\n distinctValues: number;\n totalEntries: number;\n avgEntriesPerValue: number;\n };\n }>;\n}\n","/**\n * QueryOptimizer Implementation\n *\n * Cost-based query optimizer for the Query Engine.\n * Selects optimal index and execution strategy for queries.\n *\n * Algorithm based on CQEngine CollectionQueryEngine:\n * - StandingQueryIndex: Check first (lowest cost = 10)\n * - AND queries: \"smallest first\" strategy - sort by merge cost, iterate smallest\n * - OR queries: Union all results with deduplication\n * - NOT queries: Get all keys, subtract matching keys\n *\n * @module query/QueryOptimizer\n */\n\nimport { IndexRegistry } from './IndexRegistry';\nimport { StandingQueryRegistry } from './StandingQueryRegistry';\nimport type {\n Query,\n SimpleQueryNode,\n LogicalQueryNode,\n QueryPlan,\n PlanStep,\n QueryOptions,\n FTSQueryNode,\n FTSScanStep,\n FusionStep,\n FusionStrategy,\n MatchQueryNode,\n MatchPhraseQueryNode,\n MatchPrefixQueryNode,\n} from './QueryTypes';\nimport { isLogicalQuery, isSimpleQuery, isFTSQuery } from './QueryTypes';\nimport type { FullTextIndex } from '../fts';\nimport type { IndexQuery } from './indexes/types';\nimport type { CompoundIndex } from './indexes/CompoundIndex';\n\n/**\n * Options for creating a QueryOptimizer.\n */\nexport interface QueryOptimizerOptions<K, V> {\n /** Index registry for attribute-based indexes */\n indexRegistry: IndexRegistry<K, V>;\n /** Standing query registry for pre-computed queries (optional) */\n standingQueryRegistry?: StandingQueryRegistry<K, V>;\n /** Full-text index registry for FTS queries (Phase 12) */\n fullTextIndexes?: Map<string, FullTextIndex>;\n}\n\n/**\n * Classified predicates by type for hybrid query planning.\n */\nexport interface ClassifiedPredicates {\n /** Exact match predicates (eq, neq, in) */\n exactPredicates: Query[];\n /** Range predicates (gt, gte, lt, lte, between) */\n rangePredicates: Query[];\n /** Full-text search predicates (match, matchPhrase, matchPrefix) */\n ftsPredicates: FTSQueryNode[];\n /** Other predicates (like, regex, contains, etc.) */\n otherPredicates: Query[];\n}\n\n/**\n * Cost-based query optimizer.\n * Selects optimal index and execution strategy for queries.\n *\n * K = record key type, V = record value type\n */\nexport class QueryOptimizer<K, V> {\n private readonly indexRegistry: IndexRegistry<K, V>;\n private readonly standingQueryRegistry?: StandingQueryRegistry<K, V>;\n private readonly fullTextIndexes: Map<string, FullTextIndex>;\n\n /**\n * Create a QueryOptimizer.\n *\n * @param indexRegistryOrOptions - IndexRegistry or options object\n * @param standingQueryRegistry - Optional StandingQueryRegistry (deprecated, use options)\n */\n constructor(\n indexRegistryOrOptions: IndexRegistry<K, V> | QueryOptimizerOptions<K, V>,\n standingQueryRegistry?: StandingQueryRegistry<K, V>\n ) {\n if ('indexRegistry' in indexRegistryOrOptions) {\n // Options object\n this.indexRegistry = indexRegistryOrOptions.indexRegistry;\n this.standingQueryRegistry = indexRegistryOrOptions.standingQueryRegistry;\n this.fullTextIndexes = indexRegistryOrOptions.fullTextIndexes ?? new Map();\n } else {\n // Legacy: direct IndexRegistry\n this.indexRegistry = indexRegistryOrOptions;\n this.standingQueryRegistry = standingQueryRegistry;\n this.fullTextIndexes = new Map();\n }\n }\n\n /**\n * Register a full-text index for a field (Phase 12).\n *\n * @param field - Field name\n * @param index - FullTextIndex instance\n */\n registerFullTextIndex(field: string, index: FullTextIndex): void {\n this.fullTextIndexes.set(field, index);\n }\n\n /**\n * Unregister a full-text index (Phase 12).\n *\n * @param field - Field name\n */\n unregisterFullTextIndex(field: string): void {\n this.fullTextIndexes.delete(field);\n }\n\n /**\n * Get registered full-text index for a field (Phase 12).\n *\n * @param field - Field name\n * @returns FullTextIndex or undefined\n */\n getFullTextIndex(field: string): FullTextIndex | undefined {\n return this.fullTextIndexes.get(field);\n }\n\n /**\n * Check if a full-text index exists for a field (Phase 12).\n *\n * @param field - Field name\n * @returns True if FTS index exists\n */\n hasFullTextIndex(field: string): boolean {\n return this.fullTextIndexes.has(field);\n }\n\n /**\n * Optimize a query and return an execution plan.\n *\n * Optimization order (by cost):\n * 1. StandingQueryIndex (cost: 10) - pre-computed results\n * 2. Other indexes via optimizeNode\n *\n * @param query - Query to optimize\n * @returns Query execution plan\n */\n optimize(query: Query): QueryPlan {\n // Check for standing query index first (lowest cost)\n if (this.standingQueryRegistry) {\n const standingIndex = this.standingQueryRegistry.getIndex(query);\n if (standingIndex) {\n return {\n root: {\n type: 'index-scan',\n index: standingIndex,\n query: { type: 'equal', value: null }, // Dummy query, index returns pre-computed results\n },\n estimatedCost: standingIndex.getRetrievalCost(),\n usesIndexes: true,\n };\n }\n }\n\n // Fall back to regular optimization\n const step = this.optimizeNode(query);\n return {\n root: step,\n estimatedCost: this.estimateCost(step),\n usesIndexes: this.usesIndexes(step),\n };\n }\n\n /**\n * Optimize a query with sort/limit/offset options.\n *\n * @param query - Query to optimize\n * @param options - Query options (sort, limit, offset)\n * @returns Query execution plan with options\n */\n optimizeWithOptions(query: Query, options: QueryOptions): QueryPlan {\n const basePlan = this.optimize(query);\n\n // If no options specified, return base plan\n if (!options.sort && options.limit === undefined && options.cursor === undefined) {\n return basePlan;\n }\n\n let indexedSort = false;\n let sortField: string | undefined;\n let sortDirection: 'asc' | 'desc' | undefined;\n\n // Check if sort can use NavigableIndex\n if (options.sort) {\n const sortFields = Object.keys(options.sort);\n if (sortFields.length > 0) {\n sortField = sortFields[0];\n sortDirection = options.sort[sortField];\n\n // Look for a NavigableIndex on the sort field\n const sortIndex = this.indexRegistry.findBestIndex(sortField, 'gte');\n if (sortIndex?.type === 'navigable') {\n indexedSort = true;\n }\n }\n }\n\n return {\n ...basePlan,\n indexedSort,\n sort:\n sortField && sortDirection\n ? { field: sortField, direction: sortDirection }\n : undefined,\n limit: options.limit,\n cursor: options.cursor, // Phase 14.1: replaces offset\n };\n }\n\n /**\n * Optimize a single query node.\n */\n private optimizeNode(query: Query): PlanStep {\n if (isLogicalQuery(query)) {\n return this.optimizeLogical(query);\n } else if (isFTSQuery(query)) {\n return this.optimizeFTS(query);\n } else if (isSimpleQuery(query)) {\n return this.optimizeSimple(query);\n } else {\n // Unknown query type - fall back to full scan\n return { type: 'full-scan', predicate: query };\n }\n }\n\n /**\n * Optimize a full-text search query (Phase 12).\n */\n private optimizeFTS(query: FTSQueryNode): PlanStep {\n const field = query.attribute;\n\n // Check if we have a FTS index for this field\n if (!this.hasFullTextIndex(field)) {\n // No FTS index - fall back to full scan\n return { type: 'full-scan', predicate: query };\n }\n\n // Create FTS scan step\n return this.buildFTSScanStep(query);\n }\n\n /**\n * Build an FTS scan step from a query node (Phase 12).\n */\n private buildFTSScanStep(query: FTSQueryNode): FTSScanStep {\n const field = query.attribute;\n\n switch (query.type) {\n case 'match':\n return {\n type: 'fts-scan',\n field,\n query: query.query,\n ftsType: 'match',\n options: query.options,\n returnsScored: true,\n estimatedCost: this.estimateFTSCost(field),\n };\n\n case 'matchPhrase':\n return {\n type: 'fts-scan',\n field,\n query: query.query,\n ftsType: 'matchPhrase',\n options: query.slop !== undefined ? { fuzziness: query.slop } : undefined,\n returnsScored: true,\n estimatedCost: this.estimateFTSCost(field),\n };\n\n case 'matchPrefix':\n return {\n type: 'fts-scan',\n field,\n query: query.prefix,\n ftsType: 'matchPrefix',\n options: query.maxExpansions !== undefined ? { fuzziness: query.maxExpansions } : undefined,\n returnsScored: true,\n estimatedCost: this.estimateFTSCost(field),\n };\n\n default:\n throw new Error(`Unknown FTS query type: ${(query as FTSQueryNode).type}`);\n }\n }\n\n /**\n * Estimate cost of FTS query based on index size (Phase 12).\n */\n private estimateFTSCost(field: string): number {\n const index = this.fullTextIndexes.get(field);\n if (!index) {\n return Number.MAX_SAFE_INTEGER;\n }\n\n // FTS cost is based on document count\n // Roughly O(log N) for term lookup + O(M) for scoring M matching docs\n const docCount = index.getSize();\n\n // Base cost + log scale factor\n return 50 + Math.log2(docCount + 1) * 10;\n }\n\n /**\n * Classify predicates by type for hybrid query planning (Phase 12).\n *\n * @param predicates - Array of predicates to classify\n * @returns Classified predicates\n */\n classifyPredicates(predicates: Query[]): ClassifiedPredicates {\n const result: ClassifiedPredicates = {\n exactPredicates: [],\n rangePredicates: [],\n ftsPredicates: [],\n otherPredicates: [],\n };\n\n for (const pred of predicates) {\n if (isFTSQuery(pred)) {\n result.ftsPredicates.push(pred);\n } else if (isSimpleQuery(pred)) {\n switch (pred.type) {\n case 'eq':\n case 'neq':\n case 'in':\n result.exactPredicates.push(pred);\n break;\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte':\n case 'between':\n result.rangePredicates.push(pred);\n break;\n default:\n result.otherPredicates.push(pred);\n }\n } else if (isLogicalQuery(pred)) {\n // Logical predicates go to other\n result.otherPredicates.push(pred);\n } else {\n result.otherPredicates.push(pred);\n }\n }\n\n return result;\n }\n\n /**\n * Determine fusion strategy based on step types (Phase 12).\n *\n * Strategy selection:\n * - All binary (exact/range with no scores) → 'intersection'\n * - All scored (FTS) → 'score-filter' (filter by score, sort by score)\n * - Mixed (binary + scored) → 'rrf' (Reciprocal Rank Fusion)\n *\n * @param steps - Plan steps to fuse\n * @returns Fusion strategy\n */\n determineFusionStrategy(steps: PlanStep[]): FusionStrategy {\n const hasScored = steps.some((s) => this.stepReturnsScored(s));\n const hasBinary = steps.some((s) => !this.stepReturnsScored(s));\n\n if (hasScored && hasBinary) {\n // Mixed: use RRF to combine ranked and unranked results\n return 'rrf';\n } else if (hasScored) {\n // All scored: filter by score, combine scores\n return 'score-filter';\n } else {\n // All binary: simple intersection\n return 'intersection';\n }\n }\n\n /**\n * Check if a plan step returns scored results (Phase 12).\n */\n private stepReturnsScored(step: PlanStep): boolean {\n switch (step.type) {\n case 'fts-scan':\n return true;\n case 'fusion':\n return step.returnsScored;\n default:\n return false;\n }\n }\n\n /**\n * Optimize a simple (attribute-based) query.\n */\n private optimizeSimple(query: SimpleQueryNode): PlanStep {\n // Map query type to index query type\n const indexQueryType = this.mapQueryType(query.type);\n\n // Find best index for this attribute and query type\n const index = this.indexRegistry.findBestIndex(query.attribute, indexQueryType);\n\n if (index) {\n // Use index scan\n const indexQuery = this.buildIndexQuery(query);\n return { type: 'index-scan', index, query: indexQuery };\n }\n\n // No suitable index - fall back to full scan\n return { type: 'full-scan', predicate: query };\n }\n\n /**\n * Optimize a logical (AND/OR/NOT) query.\n */\n private optimizeLogical(query: LogicalQueryNode): PlanStep {\n switch (query.type) {\n case 'and':\n return this.optimizeAnd(query);\n case 'or':\n return this.optimizeOr(query);\n case 'not':\n return this.optimizeNot(query);\n default:\n throw new Error(`Unknown logical query type: ${query.type}`);\n }\n }\n\n /**\n * Optimize AND query.\n * Strategy: Find child with lowest cost, use as base, filter with rest.\n *\n * CQEngine \"smallest first\" strategy:\n * 1. Check for CompoundIndex covering all eq children (Phase 9.03)\n * 2. Sort children by merge cost\n * 3. Use intersection if multiple indexes available\n * 4. Apply remaining predicates as filters\n */\n private optimizeAnd(query: LogicalQueryNode): PlanStep {\n if (!query.children || query.children.length === 0) {\n throw new Error('AND query must have children');\n }\n\n // Single child - just optimize it directly\n if (query.children.length === 1) {\n return this.optimizeNode(query.children[0]);\n }\n\n // Phase 9.03: Check if a CompoundIndex can handle this AND query\n const compoundStep = this.tryCompoundIndex(query.children);\n if (compoundStep) {\n return compoundStep;\n }\n\n // Optimize all children\n const childSteps = query.children.map((child) => this.optimizeNode(child));\n\n // Sort by estimated cost (ascending)\n const sortedWithIndex = childSteps\n .map((step, index) => ({ step, originalIndex: index }))\n .sort((a, b) => this.estimateCost(a.step) - this.estimateCost(b.step));\n\n const sortedSteps = sortedWithIndex.map((s) => s.step);\n\n // Separate indexed steps from full scan steps\n const indexedSteps = sortedSteps.filter((s) => s.type === 'index-scan');\n const fullScanSteps = sortedSteps.filter((s) => s.type === 'full-scan');\n\n // No indexes available - fall back to single full scan\n if (indexedSteps.length === 0) {\n return { type: 'full-scan', predicate: query };\n }\n\n // One index available - use it as base, filter with remaining predicates\n if (indexedSteps.length === 1) {\n const [indexStep] = indexedSteps;\n\n if (fullScanSteps.length === 0) {\n return indexStep;\n }\n\n // Build filter predicate from remaining conditions\n const remainingPredicates = fullScanSteps.map((s) => {\n if (s.type === 'full-scan') {\n return s.predicate;\n }\n throw new Error('Unexpected step type in remaining predicates');\n });\n\n const filterPredicate: Query =\n remainingPredicates.length === 1\n ? remainingPredicates[0]\n : { type: 'and', children: remainingPredicates };\n\n return { type: 'filter', source: indexStep, predicate: filterPredicate };\n }\n\n // Multiple indexes available - use intersection\n // CQEngine strategy: iterate smallest, check membership in others\n return { type: 'intersection', steps: indexedSteps };\n }\n\n /**\n * Try to use a CompoundIndex for an AND query (Phase 9.03).\n *\n * Returns a compound index scan step if:\n * 1. All children are simple 'eq' queries\n * 2. A CompoundIndex exists covering all queried attributes\n *\n * @param children - Children of the AND query\n * @returns IndexScanStep using CompoundIndex, or null if not applicable\n */\n private tryCompoundIndex(children: Query[]): PlanStep | null {\n // Check if all children are simple 'eq' queries\n const eqQueries: SimpleQueryNode[] = [];\n const otherQueries: Query[] = [];\n\n for (const child of children) {\n if (isSimpleQuery(child) && child.type === 'eq') {\n eqQueries.push(child);\n } else {\n otherQueries.push(child);\n }\n }\n\n // Need at least 2 'eq' queries to use compound index\n if (eqQueries.length < 2) {\n return null;\n }\n\n // Extract attribute names from eq queries\n const attributeNames = eqQueries.map((q) => q.attribute);\n\n // Find a compound index covering these attributes\n const compoundIndex = this.indexRegistry.findCompoundIndex(attributeNames);\n if (!compoundIndex) {\n return null;\n }\n\n // Build values array in the order expected by the compound index\n const values = this.buildCompoundValues(compoundIndex, eqQueries);\n if (!values) {\n return null; // Attribute order mismatch\n }\n\n // Create compound index scan step\n const compoundStep: PlanStep = {\n type: 'index-scan',\n index: compoundIndex as unknown as import('./indexes/types').Index<unknown, unknown, unknown>,\n query: { type: 'compound', values },\n };\n\n // If there are other (non-eq) queries, apply them as filters\n if (otherQueries.length > 0) {\n const filterPredicate: Query =\n otherQueries.length === 1\n ? otherQueries[0]\n : { type: 'and', children: otherQueries };\n\n return { type: 'filter', source: compoundStep, predicate: filterPredicate };\n }\n\n return compoundStep;\n }\n\n /**\n * Build values array for compound index query in correct attribute order.\n *\n * @param compoundIndex - The compound index to use\n * @param eqQueries - Array of 'eq' queries\n * @returns Values array in compound index order, or null if mismatch\n */\n private buildCompoundValues(\n compoundIndex: CompoundIndex<K, V>,\n eqQueries: SimpleQueryNode[]\n ): unknown[] | null {\n const attributeNames = compoundIndex.attributes.map((a) => a.name);\n const values: unknown[] = [];\n\n // Build a map of attribute -> value from eq queries\n const queryMap = new Map<string, unknown>();\n for (const q of eqQueries) {\n queryMap.set(q.attribute, q.value);\n }\n\n // Build values array in compound index order\n for (const attrName of attributeNames) {\n if (!queryMap.has(attrName)) {\n return null; // Missing attribute value\n }\n values.push(queryMap.get(attrName));\n }\n\n return values;\n }\n\n /**\n * Optimize OR query.\n * Strategy: Union of all child results with deduplication.\n */\n private optimizeOr(query: LogicalQueryNode): PlanStep {\n if (!query.children || query.children.length === 0) {\n throw new Error('OR query must have children');\n }\n\n // Single child - just optimize it directly\n if (query.children.length === 1) {\n return this.optimizeNode(query.children[0]);\n }\n\n const childSteps = query.children.map((child) => this.optimizeNode(child));\n\n // If all children are full scans, do a single full scan\n if (childSteps.every((s) => s.type === 'full-scan')) {\n return { type: 'full-scan', predicate: query };\n }\n\n // Create union of all results\n return { type: 'union', steps: childSteps };\n }\n\n /**\n * Optimize NOT query.\n * Strategy: Get all keys, subtract matching keys.\n */\n private optimizeNot(query: LogicalQueryNode): PlanStep {\n if (!query.child) {\n throw new Error('NOT query must have a child');\n }\n\n const childStep = this.optimizeNode(query.child);\n\n return {\n type: 'not',\n source: childStep,\n allKeys: () => new Set(), // Will be provided by executor at runtime\n };\n }\n\n /**\n * Map query type to index query type.\n * Some query types have different names in indexes.\n */\n private mapQueryType(type: string): string {\n const mapping: Record<string, string> = {\n eq: 'equal',\n neq: 'equal', // Will negate in execution\n gt: 'gt',\n gte: 'gte',\n lt: 'lt',\n lte: 'lte',\n in: 'in',\n has: 'has',\n like: 'like',\n regex: 'regex',\n between: 'between',\n contains: 'contains',\n containsAll: 'containsAll',\n containsAny: 'containsAny',\n };\n return mapping[type] ?? type;\n }\n\n /**\n * Build an IndexQuery from a SimpleQueryNode.\n */\n private buildIndexQuery(query: SimpleQueryNode): IndexQuery<unknown> {\n switch (query.type) {\n case 'eq':\n case 'neq':\n return { type: 'equal', value: query.value };\n case 'gt':\n return { type: 'gt', value: query.value };\n case 'gte':\n return { type: 'gte', value: query.value };\n case 'lt':\n return { type: 'lt', value: query.value };\n case 'lte':\n return { type: 'lte', value: query.value };\n case 'in':\n return { type: 'in', values: query.values };\n case 'has':\n return { type: 'has' };\n case 'between':\n return {\n type: 'between',\n from: query.from,\n to: query.to,\n fromInclusive: query.fromInclusive,\n toInclusive: query.toInclusive,\n };\n case 'contains':\n return { type: 'contains', value: query.value };\n case 'containsAll':\n return { type: 'containsAll', values: query.values };\n case 'containsAny':\n return { type: 'containsAny', values: query.values };\n default:\n throw new Error(`Cannot build index query for type: ${query.type}`);\n }\n }\n\n /**\n * Estimate the execution cost of a plan step.\n */\n private estimateCost(step: PlanStep): number {\n switch (step.type) {\n case 'index-scan':\n return step.index.getRetrievalCost();\n\n case 'full-scan':\n return Number.MAX_SAFE_INTEGER;\n\n case 'intersection':\n // Cost is minimum of all (we only iterate smallest)\n return Math.min(...step.steps.map((s) => this.estimateCost(s)));\n\n case 'union':\n // Cost is sum of all\n return step.steps.reduce((sum, s) => {\n const cost = this.estimateCost(s);\n // Avoid overflow\n if (cost === Number.MAX_SAFE_INTEGER) {\n return Number.MAX_SAFE_INTEGER;\n }\n return Math.min(sum + cost, Number.MAX_SAFE_INTEGER);\n }, 0);\n\n case 'filter':\n // Filter adds overhead to source cost\n return this.estimateCost(step.source) + 10;\n\n case 'not':\n // NOT is expensive (needs all keys)\n return this.estimateCost(step.source) + 100;\n\n // Phase 12: FTS step types\n case 'fts-scan':\n return step.estimatedCost;\n\n case 'fusion':\n // Fusion cost is sum of all child costs + fusion overhead\n return step.steps.reduce((sum, s) => {\n const cost = this.estimateCost(s);\n if (cost === Number.MAX_SAFE_INTEGER) {\n return Number.MAX_SAFE_INTEGER;\n }\n return Math.min(sum + cost, Number.MAX_SAFE_INTEGER);\n }, 0) + 20; // Fusion overhead\n\n default:\n return Number.MAX_SAFE_INTEGER;\n }\n }\n\n /**\n * Check if a plan step uses any indexes.\n */\n private usesIndexes(step: PlanStep): boolean {\n switch (step.type) {\n case 'index-scan':\n return true;\n\n case 'full-scan':\n return false;\n\n case 'intersection':\n case 'union':\n return step.steps.some((s) => this.usesIndexes(s));\n\n case 'filter':\n return this.usesIndexes(step.source);\n\n case 'not':\n return this.usesIndexes(step.source);\n\n // Phase 12: FTS step types\n case 'fts-scan':\n return true; // FTS uses FullTextIndex\n\n case 'fusion':\n return step.steps.some((s) => this.usesIndexes(s));\n\n default:\n return false;\n }\n }\n}\n","/**\n * StandingQueryRegistry Implementation\n *\n * Registry for managing StandingQueryIndexes.\n * Used by Live Query system to maintain pre-computed results.\n *\n * Features:\n * - Reference counting for shared indexes\n * - Automatic cleanup when all subscribers unsubscribe\n * - Efficient update propagation to all indexes\n *\n * @module query/StandingQueryRegistry\n */\n\nimport {\n StandingQueryIndex,\n type StandingQueryChange,\n type StandingQueryIndexOptions,\n} from './indexes/StandingQueryIndex';\nimport type { Query } from './QueryTypes';\n\n/**\n * Options for creating a StandingQueryRegistry.\n */\nexport interface StandingQueryRegistryOptions<K, V> {\n /** Function to get record by key */\n getRecord: (key: K) => V | undefined;\n /** Function to get all entries for building index */\n getAllEntries: () => Iterable<[K, V]>;\n}\n\n/**\n * Statistics about the StandingQueryRegistry.\n */\nexport interface StandingQueryRegistryStats {\n /** Number of registered indexes */\n indexCount: number;\n /** Total reference count across all indexes */\n totalRefCount: number;\n /** Total number of results across all indexes */\n totalResults: number;\n}\n\n/**\n * Registry for managing StandingQueryIndexes.\n * Provides reference counting and lifecycle management.\n *\n * K = record key type, V = record value type\n */\nexport class StandingQueryRegistry<K, V> {\n /** Map from query hash to StandingQueryIndex */\n private indexes: Map<string, StandingQueryIndex<K, V>> = new Map();\n\n /** Reference count for each query (multiple subscriptions can use same index) */\n private refCounts: Map<string, number> = new Map();\n\n /** Record accessor */\n private readonly getRecord: (key: K) => V | undefined;\n\n /** All entries accessor (for building index) */\n private readonly getAllEntries: () => Iterable<[K, V]>;\n\n constructor(options: StandingQueryRegistryOptions<K, V>) {\n this.getRecord = options.getRecord;\n this.getAllEntries = options.getAllEntries;\n }\n\n /**\n * Register a standing query.\n * Creates new index or returns existing if query already registered.\n * Increments reference count.\n *\n * @param query - Query to register\n * @returns StandingQueryIndex for the query\n */\n register(query: Query): StandingQueryIndex<K, V> {\n const hash = this.hashQuery(query);\n\n let index = this.indexes.get(hash);\n if (index) {\n // Increment reference count\n this.refCounts.set(hash, (this.refCounts.get(hash) || 0) + 1);\n return index;\n }\n\n // Create new index\n const options: StandingQueryIndexOptions<K, V> = {\n query,\n getRecord: this.getRecord,\n };\n index = new StandingQueryIndex(options);\n\n // Build from existing data\n index.buildFromData(this.getAllEntries());\n\n this.indexes.set(hash, index);\n this.refCounts.set(hash, 1);\n\n return index;\n }\n\n /**\n * Unregister a standing query.\n * Decrements reference count. Only removes when refcount reaches 0.\n *\n * @param query - Query to unregister\n * @returns true if index was removed, false if still has references\n */\n unregister(query: Query): boolean {\n const hash = this.hashQuery(query);\n const refCount = this.refCounts.get(hash) || 0;\n\n if (refCount <= 1) {\n this.indexes.delete(hash);\n this.refCounts.delete(hash);\n return true;\n }\n\n this.refCounts.set(hash, refCount - 1);\n return false;\n }\n\n /**\n * Get index for a query if registered.\n *\n * @param query - Query to look up\n * @returns StandingQueryIndex or undefined if not registered\n */\n getIndex(query: Query): StandingQueryIndex<K, V> | undefined {\n const hash = this.hashQuery(query);\n return this.indexes.get(hash);\n }\n\n /**\n * Get index by hash directly.\n *\n * @param hash - Query hash\n * @returns StandingQueryIndex or undefined if not registered\n */\n getIndexByHash(hash: string): StandingQueryIndex<K, V> | undefined {\n return this.indexes.get(hash);\n }\n\n /**\n * Check if query has a standing index.\n *\n * @param query - Query to check\n * @returns true if index exists\n */\n hasIndex(query: Query): boolean {\n const hash = this.hashQuery(query);\n return this.indexes.has(hash);\n }\n\n /**\n * Get reference count for a query.\n *\n * @param query - Query to check\n * @returns Reference count (0 if not registered)\n */\n getRefCount(query: Query): number {\n const hash = this.hashQuery(query);\n return this.refCounts.get(hash) || 0;\n }\n\n /**\n * Notify all indexes of record addition.\n * Returns map of query hash to change type for affected queries.\n *\n * @param key - Record key\n * @param record - New record value\n * @returns Map of query hash to change type\n */\n onRecordAdded(key: K, record: V): Map<string, StandingQueryChange> {\n const changes = new Map<string, StandingQueryChange>();\n\n for (const [hash, index] of this.indexes) {\n const change = index.determineChange(key, undefined, record);\n if (change !== 'unchanged') {\n index.add(key, record);\n changes.set(hash, change);\n }\n }\n\n return changes;\n }\n\n /**\n * Notify all indexes of record update.\n * Returns map of query hash to change type for affected queries.\n *\n * @param key - Record key\n * @param oldRecord - Previous record value\n * @param newRecord - New record value\n * @returns Map of query hash to change type\n */\n onRecordUpdated(\n key: K,\n oldRecord: V,\n newRecord: V\n ): Map<string, StandingQueryChange> {\n const changes = new Map<string, StandingQueryChange>();\n\n for (const [hash, index] of this.indexes) {\n const change = index.determineChange(key, oldRecord, newRecord);\n if (change !== 'unchanged') {\n index.update(key, oldRecord, newRecord);\n changes.set(hash, change);\n }\n }\n\n return changes;\n }\n\n /**\n * Notify all indexes of record removal.\n * Returns map of query hash to change type for affected queries.\n *\n * @param key - Record key\n * @param record - Removed record value\n * @returns Map of query hash to change type\n */\n onRecordRemoved(key: K, record: V): Map<string, StandingQueryChange> {\n const changes = new Map<string, StandingQueryChange>();\n\n for (const [hash, index] of this.indexes) {\n const change = index.determineChange(key, record, undefined);\n if (change !== 'unchanged') {\n index.remove(key, record);\n changes.set(hash, change);\n }\n }\n\n return changes;\n }\n\n /**\n * Get all registered queries.\n *\n * @returns Array of registered queries\n */\n getRegisteredQueries(): Query[] {\n return Array.from(this.indexes.values()).map((idx) => idx.getQuery());\n }\n\n /**\n * Get all query hashes.\n *\n * @returns Array of query hashes\n */\n getQueryHashes(): string[] {\n return Array.from(this.indexes.keys());\n }\n\n /**\n * Get statistics about the registry.\n *\n * @returns Registry statistics\n */\n getStats(): StandingQueryRegistryStats {\n return {\n indexCount: this.indexes.size,\n totalRefCount: Array.from(this.refCounts.values()).reduce(\n (a, b) => a + b,\n 0\n ),\n totalResults: Array.from(this.indexes.values()).reduce(\n (sum, idx) => sum + idx.getResultCount(),\n 0\n ),\n };\n }\n\n /**\n * Clear all indexes.\n */\n clear(): void {\n for (const index of this.indexes.values()) {\n index.clear();\n }\n this.indexes.clear();\n this.refCounts.clear();\n }\n\n /**\n * Get number of registered indexes.\n */\n get size(): number {\n return this.indexes.size;\n }\n\n /**\n * Compute hash for a query.\n * Used as key in indexes map.\n */\n hashQuery(query: Query): string {\n return JSON.stringify(query);\n }\n}\n","/**\n * LiveQueryManager Implementation\n *\n * Manages live query subscriptions using StandingQueryIndexes.\n * Provides reactive updates when data changes.\n *\n * Features:\n * - Initial results on subscribe\n * - Delta updates on record changes\n * - Shared indexes for identical queries\n * - Automatic cleanup on unsubscribe\n *\n * @module query/LiveQueryManager\n */\n\nimport {\n StandingQueryRegistry,\n type StandingQueryRegistryOptions,\n type StandingQueryRegistryStats,\n} from './StandingQueryRegistry';\nimport type { StandingQueryChange } from './indexes/StandingQueryIndex';\nimport type { Query } from './QueryTypes';\n\n/**\n * Initial results event sent when subscribing.\n */\nexport interface LiveQueryInitialEvent<K> {\n type: 'initial';\n query: Query;\n results: K[];\n}\n\n/**\n * Delta event sent when data changes.\n */\nexport interface LiveQueryDeltaEvent<K, V> {\n type: 'delta';\n query: Query;\n key: K;\n record: V;\n change: StandingQueryChange;\n operation: 'added' | 'updated' | 'removed';\n newResultCount: number;\n}\n\n/**\n * Union type for all live query events.\n */\nexport type LiveQueryEvent<K, V> = LiveQueryInitialEvent<K> | LiveQueryDeltaEvent<K, V>;\n\n/**\n * Callback for live query events.\n */\nexport type LiveQueryCallback<K, V> = (event: LiveQueryEvent<K, V>) => void;\n\n/**\n * Options for creating a LiveQueryManager.\n */\nexport interface LiveQueryManagerOptions<K, V> {\n /** Function to get record by key */\n getRecord: (key: K) => V | undefined;\n /** Function to get all entries for building index */\n getAllEntries: () => Iterable<[K, V]>;\n}\n\n/**\n * Manages live query subscriptions using StandingQueryIndexes.\n * Provides reactive updates when data changes.\n *\n * K = record key type, V = record value type\n */\nexport class LiveQueryManager<K, V> {\n private registry: StandingQueryRegistry<K, V>;\n\n /** Subscription callbacks by query hash */\n private subscriptions: Map<string, Set<LiveQueryCallback<K, V>>> = new Map();\n\n constructor(options: LiveQueryManagerOptions<K, V>) {\n const registryOptions: StandingQueryRegistryOptions<K, V> = {\n getRecord: options.getRecord,\n getAllEntries: options.getAllEntries,\n };\n this.registry = new StandingQueryRegistry(registryOptions);\n }\n\n /**\n * Subscribe to a live query.\n * Sends initial results immediately, then delta updates on changes.\n *\n * @param query - Query to subscribe to\n * @param callback - Callback for query events\n * @returns Unsubscribe function\n */\n subscribe(query: Query, callback: LiveQueryCallback<K, V>): () => void {\n const hash = this.registry.hashQuery(query);\n\n // Register standing query index\n const index = this.registry.register(query);\n\n // Add callback to subscriptions\n let callbacks = this.subscriptions.get(hash);\n if (!callbacks) {\n callbacks = new Set();\n this.subscriptions.set(hash, callbacks);\n }\n callbacks.add(callback);\n\n // Send initial results\n const initialResults = Array.from(index.getResults());\n try {\n callback({\n type: 'initial',\n query,\n results: initialResults,\n });\n } catch (error) {\n console.error('LiveQueryManager initial callback error:', error);\n }\n\n // Return unsubscribe function\n return () => {\n callbacks?.delete(callback);\n if (callbacks?.size === 0) {\n this.subscriptions.delete(hash);\n }\n this.registry.unregister(query);\n };\n }\n\n /**\n * Get current results for a query (snapshot).\n * Does not subscribe to updates.\n *\n * @param query - Query to execute\n * @returns Array of matching keys\n */\n getResults(query: Query): K[] {\n const index = this.registry.getIndex(query);\n return index ? Array.from(index.getResults()) : [];\n }\n\n /**\n * Check if a query has active subscriptions.\n *\n * @param query - Query to check\n * @returns true if query has subscribers\n */\n hasSubscribers(query: Query): boolean {\n const hash = this.registry.hashQuery(query);\n const callbacks = this.subscriptions.get(hash);\n return callbacks !== undefined && callbacks.size > 0;\n }\n\n /**\n * Get subscriber count for a query.\n *\n * @param query - Query to check\n * @returns Number of subscribers\n */\n getSubscriberCount(query: Query): number {\n const hash = this.registry.hashQuery(query);\n const callbacks = this.subscriptions.get(hash);\n return callbacks?.size ?? 0;\n }\n\n /**\n * Notify of record addition.\n * Triggers subscription callbacks for affected queries.\n *\n * @param key - Record key\n * @param record - New record value\n */\n onRecordAdded(key: K, record: V): void {\n const changes = this.registry.onRecordAdded(key, record);\n this.notifySubscribers(key, record, changes, 'added');\n }\n\n /**\n * Notify of record update.\n * Triggers subscription callbacks for affected queries.\n *\n * @param key - Record key\n * @param oldRecord - Previous record value\n * @param newRecord - New record value\n */\n onRecordUpdated(key: K, oldRecord: V, newRecord: V): void {\n const changes = this.registry.onRecordUpdated(key, oldRecord, newRecord);\n this.notifySubscribers(key, newRecord, changes, 'updated');\n }\n\n /**\n * Notify of record removal.\n * Triggers subscription callbacks for affected queries.\n *\n * @param key - Record key\n * @param record - Removed record value\n */\n onRecordRemoved(key: K, record: V): void {\n const changes = this.registry.onRecordRemoved(key, record);\n this.notifySubscribers(key, record, changes, 'removed');\n }\n\n /**\n * Notify subscribers of changes.\n */\n private notifySubscribers(\n key: K,\n record: V,\n changes: Map<string, StandingQueryChange>,\n operation: 'added' | 'updated' | 'removed'\n ): void {\n for (const [hash, change] of changes) {\n const callbacks = this.subscriptions.get(hash);\n if (!callbacks || callbacks.size === 0) continue;\n\n const index = this.registry.getIndexByHash(hash);\n if (!index) continue;\n\n const query = index.getQuery();\n\n for (const callback of callbacks) {\n try {\n callback({\n type: 'delta',\n query,\n key,\n record,\n change,\n operation,\n newResultCount: index.getResultCount(),\n });\n } catch (error) {\n // Don't let one callback failure affect others\n console.error('LiveQueryManager callback error:', error);\n }\n }\n }\n }\n\n /**\n * Get the underlying registry for direct access.\n * Useful for testing and debugging.\n *\n * @returns StandingQueryRegistry instance\n */\n getRegistry(): StandingQueryRegistry<K, V> {\n return this.registry;\n }\n\n /**\n * Get all active query hashes.\n *\n * @returns Array of query hashes with active subscriptions\n */\n getActiveQueries(): string[] {\n return Array.from(this.subscriptions.keys());\n }\n\n /**\n * Get statistics about the manager.\n *\n * @returns Statistics object\n */\n getStats(): LiveQueryManagerStats {\n const registryStats = this.registry.getStats();\n const totalSubscribers = Array.from(this.subscriptions.values()).reduce(\n (sum, callbacks) => sum + callbacks.size,\n 0\n );\n\n return {\n ...registryStats,\n activeQueries: this.subscriptions.size,\n totalSubscribers,\n };\n }\n\n /**\n * Clear all subscriptions and indexes.\n */\n clear(): void {\n this.subscriptions.clear();\n this.registry.clear();\n }\n}\n\n/**\n * Statistics about the LiveQueryManager.\n */\nexport interface LiveQueryManagerStats extends StandingQueryRegistryStats {\n /** Number of active queries with subscribers */\n activeQueries: number;\n /** Total number of subscribers across all queries */\n totalSubscribers: number;\n}\n","/**\n * Types for Adaptive Indexing System (Phase 8.02)\n *\n * Defines interfaces for query pattern tracking, index suggestions,\n * and auto-indexing configuration.\n *\n * @module query/adaptive/types\n */\n\n/**\n * Query type for pattern tracking.\n * Matches the query types from QueryTypes.ts and indexes/types.ts\n */\nexport type TrackedQueryType =\n | 'eq'\n | 'neq'\n | 'gt'\n | 'gte'\n | 'lt'\n | 'lte'\n | 'between'\n | 'in'\n | 'has'\n | 'contains'\n | 'containsAll'\n | 'containsAny'\n | 'compound'; // Phase 9.03: Compound query patterns\n\n/**\n * Statistics for a single attribute + query type combination.\n */\nexport interface QueryStatistics {\n /** Attribute name being queried */\n attribute: string;\n /** Type of query (eq, gt, between, etc.) */\n queryType: TrackedQueryType;\n /** Number of times this pattern was queried */\n queryCount: number;\n /** Cumulative execution time in milliseconds */\n totalCost: number;\n /** Average execution time per query */\n averageCost: number;\n /** Timestamp of last query */\n lastQueried: number;\n /** Estimated result size (max observed) */\n estimatedCardinality: number;\n /** Whether an index exists for this attribute */\n hasIndex: boolean;\n}\n\n/**\n * Statistics for compound query patterns (Phase 9.03).\n * Tracks AND combinations of attributes for compound index suggestions.\n */\nexport interface CompoundQueryStatistics {\n /** Attribute names in the compound query (sorted) */\n attributes: string[];\n /** Combined key for identification */\n compoundKey: string;\n /** Number of times this pattern was queried */\n queryCount: number;\n /** Cumulative execution time in milliseconds */\n totalCost: number;\n /** Average execution time per query */\n averageCost: number;\n /** Timestamp of last query */\n lastQueried: number;\n /** Whether a compound index exists for this combination */\n hasCompoundIndex: boolean;\n}\n\n/**\n * Index type recommendation.\n */\nexport type RecommendedIndexType = 'hash' | 'navigable' | 'inverted' | 'compound';\n\n/**\n * Priority level for index suggestions.\n */\nexport type SuggestionPriority = 'high' | 'medium' | 'low';\n\n/**\n * Index suggestion generated by IndexAdvisor.\n */\nexport interface IndexSuggestion {\n /** Attribute to index (or compound key for compound indexes) */\n attribute: string;\n /** Recommended index type */\n indexType: RecommendedIndexType;\n /** Human-readable explanation */\n reason: string;\n /** Expected performance improvement multiplier */\n estimatedBenefit: number;\n /** Estimated memory overhead in bytes */\n estimatedCost: number;\n /** Priority based on query patterns */\n priority: SuggestionPriority;\n /** Query count that triggered this suggestion */\n queryCount: number;\n /** Average query cost in milliseconds */\n averageCost: number;\n /** For compound indexes: array of attribute names in order */\n compoundAttributes?: string[];\n}\n\n/**\n * Options for getting index suggestions.\n */\nexport interface IndexSuggestionOptions {\n /** Minimum query count to consider (default: 10) */\n minQueryCount?: number;\n /** Minimum average cost in ms to consider (default: 1) */\n minAverageCost?: number;\n /** Whether to exclude already indexed attributes (default: true) */\n excludeExistingIndexes?: boolean;\n /** Maximum number of suggestions to return (default: unlimited) */\n maxSuggestions?: number;\n}\n\n/**\n * Configuration for Index Advisor.\n */\nexport interface AdvisorConfig {\n /** Enable advisor mode (default: true) */\n enabled: boolean;\n /** Minimum query count before suggesting (default: 10) */\n minQueryCount?: number;\n /** Minimum average cost in ms to suggest (default: 1) */\n minAverageCost?: number;\n}\n\n/**\n * Callback for index creation events.\n */\nexport type IndexCreatedCallback = (attribute: string, indexType: RecommendedIndexType) => void;\n\n/**\n * Configuration for Auto-Index Manager.\n */\nexport interface AutoIndexConfig {\n /** Enable auto-indexing (default: false) */\n enabled: boolean;\n /** Number of queries before auto-creating index (default: 10) */\n threshold?: number;\n /** Maximum number of auto-created indexes (default: 20) */\n maxIndexes?: number;\n /** Callback when index is automatically created */\n onIndexCreated?: IndexCreatedCallback;\n}\n\n/**\n * Default indexing strategy.\n * - 'none': No automatic indexing (default)\n * - 'scalar': Index all top-level scalar (primitive) fields\n * - 'all': Index all fields including nested (not recommended)\n */\nexport type DefaultIndexingStrategy = 'none' | 'scalar' | 'all';\n\n/**\n * Complete adaptive indexing configuration.\n */\nexport interface AdaptiveIndexingConfig {\n /** Index Advisor configuration */\n advisor?: AdvisorConfig;\n /** Auto-Index Manager configuration */\n autoIndex?: AutoIndexConfig;\n}\n\n/**\n * Progress callback for lazy index building (Phase 9.01).\n */\nexport type IndexBuildProgressCallback = (\n attributeName: string,\n progress: number, // 0-100\n recordsProcessed: number,\n totalRecords: number\n) => void;\n\n/**\n * Extended options for IndexedLWWMap/IndexedORMap.\n */\nexport interface IndexedMapOptions {\n /** Adaptive indexing configuration */\n adaptiveIndexing?: AdaptiveIndexingConfig;\n /** Default indexing strategy (default: 'none') */\n defaultIndexing?: DefaultIndexingStrategy;\n /**\n * Enable lazy index building (Phase 9.01).\n * When true, indexes are not built until first query.\n * Default: false\n */\n lazyIndexBuilding?: boolean;\n /**\n * Callback for index building progress (Phase 9.01).\n * Called during lazy index materialization.\n */\n onIndexBuilding?: IndexBuildProgressCallback;\n}\n\n/**\n * Default values for adaptive indexing configuration.\n */\nexport const ADAPTIVE_INDEXING_DEFAULTS = {\n advisor: {\n enabled: true,\n minQueryCount: 10,\n minAverageCost: 1,\n },\n autoIndex: {\n enabled: false,\n threshold: 10,\n maxIndexes: 20,\n },\n} as const;\n\n/**\n * Sampling rate for query tracking (1 = track all, 10 = track 1 in 10).\n * Used to reduce overhead in high-throughput scenarios.\n */\nexport const TRACKING_SAMPLE_RATE = 1;\n\n/**\n * Memory overhead estimation constants (bytes per record).\n */\nexport const MEMORY_OVERHEAD_ESTIMATES = {\n /** Hash index overhead per record */\n hash: 24,\n /** Navigable index overhead per record */\n navigable: 32,\n /** Inverted index overhead per record (depends on token count) */\n inverted: 48,\n /** Compound index overhead per record (includes composite key) */\n compound: 40,\n} as const;\n","/**\n * QueryPatternTracker (Phase 8.02.1)\n *\n * Collects runtime statistics on query execution patterns.\n * Used by IndexAdvisor to generate index suggestions.\n *\n * Features:\n * - Tracks query count, cost, and cardinality per attribute\n * - Low overhead (< 1% of query time)\n * - Optional sampling for high-throughput scenarios\n * - Memory-bounded (circular buffer for old stats)\n *\n * @module query/adaptive/QueryPatternTracker\n */\n\nimport type { QueryStatistics, TrackedQueryType, CompoundQueryStatistics } from './types';\nimport { TRACKING_SAMPLE_RATE } from './types';\n\n/**\n * Options for QueryPatternTracker.\n */\nexport interface QueryPatternTrackerOptions {\n /**\n * Sampling rate: 1 = track all queries, N = track 1 in N queries.\n * Higher values reduce overhead but decrease accuracy.\n * Default: 1 (track all)\n */\n samplingRate?: number;\n\n /**\n * Maximum number of unique attribute+queryType combinations to track.\n * Prevents unbounded memory growth.\n * Default: 1000\n */\n maxTrackedPatterns?: number;\n\n /**\n * Time-to-live for statistics in milliseconds.\n * Statistics older than this are considered stale.\n * Default: 24 hours\n */\n statsTtl?: number;\n}\n\n/**\n * Internal storage key for statistics.\n */\ntype StatsKey = string;\n\n/**\n * Create a stats key from attribute and query type.\n */\nfunction makeStatsKey(attribute: string, queryType: TrackedQueryType): StatsKey {\n return `${attribute}:${queryType}`;\n}\n\n/**\n * Parse a stats key back to attribute and query type.\n */\nfunction parseStatsKey(key: StatsKey): { attribute: string; queryType: TrackedQueryType } {\n const colonIndex = key.lastIndexOf(':');\n return {\n attribute: key.slice(0, colonIndex),\n queryType: key.slice(colonIndex + 1) as TrackedQueryType,\n };\n}\n\n/**\n * QueryPatternTracker collects runtime statistics on query execution.\n *\n * @example\n * ```typescript\n * const tracker = new QueryPatternTracker();\n *\n * // Record queries during execution\n * tracker.recordQuery('category', 'eq', 5.2, 100, false);\n * tracker.recordQuery('category', 'eq', 4.8, 100, false);\n *\n * // Record compound AND queries (Phase 9.03)\n * tracker.recordCompoundQuery(['status', 'category'], 10.5, 50, false);\n *\n * // Get statistics\n * const stats = tracker.getStatistics();\n * // [{ attribute: 'category', queryType: 'eq', queryCount: 2, averageCost: 5.0, ... }]\n * ```\n */\nexport class QueryPatternTracker {\n private stats = new Map<StatsKey, QueryStatistics>();\n private compoundStats = new Map<string, CompoundQueryStatistics>();\n private queryCounter = 0;\n private readonly samplingRate: number;\n private readonly maxTrackedPatterns: number;\n private readonly statsTtl: number;\n\n constructor(options: QueryPatternTrackerOptions = {}) {\n this.samplingRate = options.samplingRate ?? TRACKING_SAMPLE_RATE;\n this.maxTrackedPatterns = options.maxTrackedPatterns ?? 1000;\n this.statsTtl = options.statsTtl ?? 24 * 60 * 60 * 1000; // 24 hours\n }\n\n /**\n * Record a query execution for pattern tracking.\n *\n * @param attribute - The attribute being queried\n * @param queryType - The type of query (eq, gt, between, etc.)\n * @param executionTime - Query execution time in milliseconds\n * @param resultSize - Number of results returned\n * @param hasIndex - Whether an index was used\n */\n recordQuery(\n attribute: string,\n queryType: TrackedQueryType,\n executionTime: number,\n resultSize: number,\n hasIndex: boolean\n ): void {\n // Sampling: skip if not selected\n this.queryCounter++;\n if (this.samplingRate > 1 && this.queryCounter % this.samplingRate !== 0) {\n return;\n }\n\n const key = makeStatsKey(attribute, queryType);\n const existing = this.stats.get(key);\n const now = Date.now();\n\n if (existing) {\n // Update existing statistics\n existing.queryCount++;\n existing.totalCost += executionTime;\n existing.averageCost = existing.totalCost / existing.queryCount;\n existing.lastQueried = now;\n existing.estimatedCardinality = Math.max(existing.estimatedCardinality, resultSize);\n existing.hasIndex = hasIndex;\n } else {\n // Check capacity before adding new entry\n if (this.stats.size >= this.maxTrackedPatterns) {\n this.evictOldest();\n }\n\n // Create new statistics entry\n this.stats.set(key, {\n attribute,\n queryType,\n queryCount: this.samplingRate, // Adjust for sampling\n totalCost: executionTime * this.samplingRate,\n averageCost: executionTime,\n lastQueried: now,\n estimatedCardinality: resultSize,\n hasIndex,\n });\n }\n }\n\n /**\n * Record a compound (AND) query execution for pattern tracking (Phase 9.03).\n *\n * @param attributes - Array of attribute names being queried together\n * @param executionTime - Query execution time in milliseconds\n * @param resultSize - Number of results returned\n * @param hasCompoundIndex - Whether a compound index was used\n */\n recordCompoundQuery(\n attributes: string[],\n executionTime: number,\n resultSize: number,\n hasCompoundIndex: boolean\n ): void {\n // Need at least 2 attributes for a compound query\n if (attributes.length < 2) return;\n\n // Sampling: skip if not selected\n this.queryCounter++;\n if (this.samplingRate > 1 && this.queryCounter % this.samplingRate !== 0) {\n return;\n }\n\n // Sort attributes for consistent key generation\n const sortedAttrs = [...attributes].sort();\n const compoundKey = sortedAttrs.join('+');\n const existing = this.compoundStats.get(compoundKey);\n const now = Date.now();\n\n if (existing) {\n // Update existing statistics\n existing.queryCount++;\n existing.totalCost += executionTime;\n existing.averageCost = existing.totalCost / existing.queryCount;\n existing.lastQueried = now;\n existing.hasCompoundIndex = hasCompoundIndex;\n } else {\n // Check capacity before adding new entry\n if (this.compoundStats.size >= this.maxTrackedPatterns) {\n this.evictOldestCompound();\n }\n\n // Create new statistics entry\n this.compoundStats.set(compoundKey, {\n attributes: sortedAttrs,\n compoundKey,\n queryCount: this.samplingRate, // Adjust for sampling\n totalCost: executionTime * this.samplingRate,\n averageCost: executionTime,\n lastQueried: now,\n hasCompoundIndex,\n });\n }\n }\n\n /**\n * Get all compound query statistics (Phase 9.03).\n *\n * @returns Array of compound query statistics, sorted by query count descending\n */\n getCompoundStatistics(): CompoundQueryStatistics[] {\n this.pruneStaleCompound();\n return Array.from(this.compoundStats.values()).sort((a, b) => b.queryCount - a.queryCount);\n }\n\n /**\n * Get compound statistics for a specific attribute combination.\n *\n * @param attributes - Array of attribute names\n * @returns Compound query statistics or undefined\n */\n getCompoundStats(attributes: string[]): CompoundQueryStatistics | undefined {\n const sortedAttrs = [...attributes].sort();\n const compoundKey = sortedAttrs.join('+');\n return this.compoundStats.get(compoundKey);\n }\n\n /**\n * Check if attributes appear in any tracked compound queries.\n *\n * @param attribute - The attribute name to check\n * @returns True if attribute is part of any compound query pattern\n */\n isInCompoundPattern(attribute: string): boolean {\n for (const stat of this.compoundStats.values()) {\n if (stat.attributes.includes(attribute)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Update compound index status.\n *\n * @param attributes - Array of attribute names\n * @param hasCompoundIndex - Whether a compound index exists\n */\n updateCompoundIndexStatus(attributes: string[], hasCompoundIndex: boolean): void {\n const sortedAttrs = [...attributes].sort();\n const compoundKey = sortedAttrs.join('+');\n const stat = this.compoundStats.get(compoundKey);\n if (stat) {\n stat.hasCompoundIndex = hasCompoundIndex;\n }\n }\n\n /**\n * Get all query statistics.\n *\n * @returns Array of query statistics, sorted by query count descending\n */\n getStatistics(): QueryStatistics[] {\n this.pruneStale();\n return Array.from(this.stats.values()).sort((a, b) => b.queryCount - a.queryCount);\n }\n\n /**\n * Get statistics for a specific attribute.\n *\n * @param attribute - The attribute name\n * @returns Array of query statistics for this attribute\n */\n getAttributeStats(attribute: string): QueryStatistics[] {\n return Array.from(this.stats.values()).filter((s) => s.attribute === attribute);\n }\n\n /**\n * Get statistics for a specific attribute and query type.\n *\n * @param attribute - The attribute name\n * @param queryType - The query type\n * @returns Query statistics or undefined\n */\n getStats(attribute: string, queryType: TrackedQueryType): QueryStatistics | undefined {\n const key = makeStatsKey(attribute, queryType);\n return this.stats.get(key);\n }\n\n /**\n * Check if an attribute has been queried.\n *\n * @param attribute - The attribute name\n * @returns True if the attribute has query statistics\n */\n hasStats(attribute: string): boolean {\n for (const key of this.stats.keys()) {\n if (key.startsWith(attribute + ':')) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get the total number of queries recorded.\n *\n * @returns Total query count across all patterns\n */\n getTotalQueryCount(): number {\n let total = 0;\n for (const stat of this.stats.values()) {\n total += stat.queryCount;\n }\n return total;\n }\n\n /**\n * Get the number of unique attribute+queryType patterns tracked.\n *\n * @returns Number of unique patterns\n */\n getPatternCount(): number {\n return this.stats.size;\n }\n\n /**\n * Update index status for an attribute.\n * Called when an index is added or removed.\n *\n * @param attribute - The attribute name\n * @param hasIndex - Whether an index now exists\n */\n updateIndexStatus(attribute: string, hasIndex: boolean): void {\n for (const [key, stat] of this.stats.entries()) {\n const parsed = parseStatsKey(key);\n if (parsed.attribute === attribute) {\n stat.hasIndex = hasIndex;\n }\n }\n }\n\n /**\n * Reset query count for an attribute after index creation.\n * This prevents immediate re-suggestion of the same index.\n *\n * @param attribute - The attribute name\n */\n resetAttributeStats(attribute: string): void {\n for (const key of Array.from(this.stats.keys())) {\n const parsed = parseStatsKey(key);\n if (parsed.attribute === attribute) {\n this.stats.delete(key);\n }\n }\n }\n\n /**\n * Clear all statistics.\n */\n clear(): void {\n this.stats.clear();\n this.compoundStats.clear();\n this.queryCounter = 0;\n }\n\n /**\n * Get a summary of tracking overhead.\n *\n * @returns Tracking overhead info\n */\n getTrackingInfo(): {\n patternsTracked: number;\n compoundPatternsTracked: number;\n totalQueries: number;\n samplingRate: number;\n memoryEstimate: number;\n } {\n // Rough memory estimate: ~200 bytes per stats entry, ~300 for compound (larger attribute arrays)\n const memoryEstimate = this.stats.size * 200 + this.compoundStats.size * 300;\n\n return {\n patternsTracked: this.stats.size,\n compoundPatternsTracked: this.compoundStats.size,\n totalQueries: this.queryCounter,\n samplingRate: this.samplingRate,\n memoryEstimate,\n };\n }\n\n /**\n * Evict the oldest (least recently queried) entry.\n */\n private evictOldest(): void {\n let oldestKey: StatsKey | null = null;\n let oldestTime = Infinity;\n\n for (const [key, stat] of this.stats.entries()) {\n if (stat.lastQueried < oldestTime) {\n oldestTime = stat.lastQueried;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n this.stats.delete(oldestKey);\n }\n }\n\n /**\n * Prune stale statistics older than TTL.\n */\n private pruneStale(): void {\n const cutoff = Date.now() - this.statsTtl;\n\n for (const [key, stat] of this.stats.entries()) {\n if (stat.lastQueried < cutoff) {\n this.stats.delete(key);\n }\n }\n }\n\n /**\n * Evict the oldest compound query entry (Phase 9.03).\n */\n private evictOldestCompound(): void {\n let oldestKey: string | null = null;\n let oldestTime = Infinity;\n\n for (const [key, stat] of this.compoundStats.entries()) {\n if (stat.lastQueried < oldestTime) {\n oldestTime = stat.lastQueried;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n this.compoundStats.delete(oldestKey);\n }\n }\n\n /**\n * Prune stale compound statistics (Phase 9.03).\n */\n private pruneStaleCompound(): void {\n const cutoff = Date.now() - this.statsTtl;\n\n for (const [key, stat] of this.compoundStats.entries()) {\n if (stat.lastQueried < cutoff) {\n this.compoundStats.delete(key);\n }\n }\n }\n}\n","/**\n * IndexAdvisor (Phase 8.02.2)\n *\n * Analyzes query patterns and generates index suggestions.\n * Used in production mode to help developers optimize their indexes.\n *\n * Features:\n * - Cost/benefit analysis for index suggestions\n * - Automatic index type selection based on query type\n * - Priority-based ranking of suggestions\n * - Memory cost estimation\n *\n * @module query/adaptive/IndexAdvisor\n */\n\nimport type { QueryPatternTracker } from './QueryPatternTracker';\nimport type {\n CompoundQueryStatistics,\n IndexSuggestion,\n IndexSuggestionOptions,\n QueryStatistics,\n RecommendedIndexType,\n SuggestionPriority,\n TrackedQueryType,\n} from './types';\nimport { ADAPTIVE_INDEXING_DEFAULTS, MEMORY_OVERHEAD_ESTIMATES } from './types';\n\n/**\n * IndexAdvisor analyzes query patterns and generates index suggestions.\n *\n * @example\n * ```typescript\n * const tracker = new QueryPatternTracker();\n * const advisor = new IndexAdvisor(tracker);\n *\n * // After application runs...\n * const suggestions = advisor.getSuggestions();\n * // [\n * // {\n * // attribute: 'category',\n * // indexType: 'hash',\n * // reason: 'Queried 1000× with average cost 5.2ms. Expected 500× speedup.',\n * // priority: 'high'\n * // }\n * // ]\n * ```\n */\nexport class IndexAdvisor {\n constructor(private readonly tracker: QueryPatternTracker) {}\n\n /**\n * Get index suggestions based on query patterns.\n *\n * @param options - Suggestion options\n * @returns Array of index suggestions sorted by priority\n */\n getSuggestions(options: IndexSuggestionOptions = {}): IndexSuggestion[] {\n const {\n minQueryCount = ADAPTIVE_INDEXING_DEFAULTS.advisor.minQueryCount,\n minAverageCost = ADAPTIVE_INDEXING_DEFAULTS.advisor.minAverageCost,\n excludeExistingIndexes = true,\n maxSuggestions,\n } = options;\n\n const stats = this.tracker.getStatistics();\n const suggestions: IndexSuggestion[] = [];\n\n // Group stats by attribute to avoid duplicate suggestions\n const attributeStats = this.groupByAttribute(stats);\n\n for (const [attribute, attrStats] of attributeStats.entries()) {\n // Find the best (most queried) pattern for this attribute\n const bestStat = this.findBestPattern(attrStats, excludeExistingIndexes);\n if (!bestStat) continue;\n\n // Skip if below thresholds\n if (bestStat.queryCount < minQueryCount) continue;\n if (bestStat.averageCost < minAverageCost) continue;\n\n // Generate suggestion\n const suggestion = this.generateSuggestion(bestStat, attrStats);\n if (suggestion) {\n suggestions.push(suggestion);\n }\n }\n\n // Phase 9.03: Add compound index suggestions\n const compoundSuggestions = this.getCompoundSuggestions({\n minQueryCount,\n minAverageCost,\n excludeExistingIndexes,\n });\n suggestions.push(...compoundSuggestions);\n\n // Sort by priority and benefit\n suggestions.sort((a, b) => {\n const priorityOrder = { high: 3, medium: 2, low: 1 };\n const priorityDiff = priorityOrder[b.priority] - priorityOrder[a.priority];\n if (priorityDiff !== 0) return priorityDiff;\n return b.estimatedBenefit - a.estimatedBenefit;\n });\n\n // Apply max suggestions limit\n if (maxSuggestions !== undefined && suggestions.length > maxSuggestions) {\n return suggestions.slice(0, maxSuggestions);\n }\n\n return suggestions;\n }\n\n /**\n * Get a suggestion for a specific attribute.\n *\n * @param attribute - The attribute name\n * @returns Index suggestion or null if not recommended\n */\n getSuggestionForAttribute(attribute: string): IndexSuggestion | null {\n const attrStats = this.tracker.getAttributeStats(attribute);\n if (attrStats.length === 0) return null;\n\n const bestStat = this.findBestPattern(attrStats, true);\n if (!bestStat) return null;\n\n return this.generateSuggestion(bestStat, attrStats);\n }\n\n /**\n * Check if an attribute should be indexed based on patterns.\n *\n * @param attribute - The attribute name\n * @param threshold - Minimum query count threshold\n * @returns True if attribute should be indexed\n */\n shouldIndex(attribute: string, threshold: number = ADAPTIVE_INDEXING_DEFAULTS.autoIndex.threshold!): boolean {\n const attrStats = this.tracker.getAttributeStats(attribute);\n if (attrStats.length === 0) return false;\n\n // Check if any pattern exceeds threshold\n for (const stat of attrStats) {\n if (!stat.hasIndex && stat.queryCount >= threshold) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Get recommended index type for a query type.\n *\n * @param queryType - The query type\n * @returns Recommended index type or null if not indexable\n */\n getRecommendedIndexType(queryType: TrackedQueryType): RecommendedIndexType | null {\n return this.selectIndexType(queryType);\n }\n\n /**\n * Group statistics by attribute.\n */\n private groupByAttribute(stats: QueryStatistics[]): Map<string, QueryStatistics[]> {\n const grouped = new Map<string, QueryStatistics[]>();\n\n for (const stat of stats) {\n const existing = grouped.get(stat.attribute);\n if (existing) {\n existing.push(stat);\n } else {\n grouped.set(stat.attribute, [stat]);\n }\n }\n\n return grouped;\n }\n\n /**\n * Find the best (most beneficial) pattern for an attribute.\n */\n private findBestPattern(\n stats: QueryStatistics[],\n excludeExistingIndexes: boolean\n ): QueryStatistics | null {\n let best: QueryStatistics | null = null;\n let bestScore = -1;\n\n for (const stat of stats) {\n // Skip if already indexed\n if (excludeExistingIndexes && stat.hasIndex) continue;\n\n // Skip if query type is not indexable\n if (!this.selectIndexType(stat.queryType)) continue;\n\n // Score: queryCount × averageCost (total potential savings)\n const score = stat.queryCount * stat.averageCost;\n if (score > bestScore) {\n bestScore = score;\n best = stat;\n }\n }\n\n return best;\n }\n\n /**\n * Generate a suggestion for a query pattern.\n */\n private generateSuggestion(\n stat: QueryStatistics,\n allAttrStats: QueryStatistics[]\n ): IndexSuggestion | null {\n const indexType = this.selectIndexType(stat.queryType);\n if (!indexType) return null;\n\n // Check if this index type would help other query patterns too\n const benefitingPatterns = this.countBenefitingPatterns(allAttrStats, indexType);\n\n const estimatedBenefit = this.estimateBenefit(stat, benefitingPatterns);\n const estimatedCost = this.estimateMemoryCost(stat, indexType);\n const priority = this.calculatePriority(stat, estimatedBenefit);\n\n // Calculate total query count across all patterns for this attribute\n const totalQueryCount = allAttrStats.reduce((sum, s) => sum + s.queryCount, 0);\n\n return {\n attribute: stat.attribute,\n indexType,\n reason: this.generateReason(stat, estimatedBenefit, benefitingPatterns),\n estimatedBenefit,\n estimatedCost,\n priority,\n queryCount: totalQueryCount,\n averageCost: stat.averageCost,\n };\n }\n\n /**\n * Select appropriate index type based on query type.\n */\n private selectIndexType(queryType: TrackedQueryType): RecommendedIndexType | null {\n switch (queryType) {\n case 'eq':\n case 'neq':\n case 'in':\n case 'has':\n return 'hash';\n\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte':\n case 'between':\n return 'navigable';\n\n case 'contains':\n case 'containsAll':\n case 'containsAny':\n return 'inverted';\n\n default:\n return null;\n }\n }\n\n /**\n * Count how many query patterns would benefit from an index type.\n */\n private countBenefitingPatterns(\n stats: QueryStatistics[],\n indexType: RecommendedIndexType\n ): number {\n let count = 0;\n\n for (const stat of stats) {\n if (stat.hasIndex) continue;\n const recommended = this.selectIndexType(stat.queryType);\n if (recommended === indexType) {\n count++;\n }\n }\n\n return count;\n }\n\n /**\n * Estimate performance benefit of adding an index.\n *\n * Heuristic based on:\n * - Full scan vs indexed: typically 100-1000× speedup\n * - Query frequency amplifies benefit\n */\n private estimateBenefit(stat: QueryStatistics, benefitingPatterns: number): number {\n // Base benefit depends on query cost (higher cost = more benefit)\n let baseBenefit: number;\n if (stat.averageCost > 10) {\n baseBenefit = 1000; // 1000× speedup for expensive queries\n } else if (stat.averageCost > 1) {\n baseBenefit = 100; // 100× speedup for medium queries\n } else {\n baseBenefit = 10; // 10× speedup for fast queries\n }\n\n // Scale by query frequency (more queries = more cumulative benefit)\n const frequencyMultiplier = Math.min(stat.queryCount / 10, 100);\n\n // Bonus for benefiting multiple patterns\n const patternBonus = benefitingPatterns > 1 ? benefitingPatterns : 1;\n\n return Math.floor(baseBenefit * frequencyMultiplier * patternBonus);\n }\n\n /**\n * Estimate memory cost of adding an index.\n */\n private estimateMemoryCost(stat: QueryStatistics, indexType: RecommendedIndexType): number {\n const bytesPerRecord = MEMORY_OVERHEAD_ESTIMATES[indexType];\n\n // Use estimated cardinality as record count estimate\n // Add 50% buffer for index structure overhead\n return Math.floor(stat.estimatedCardinality * bytesPerRecord * 1.5);\n }\n\n /**\n * Calculate priority based on query patterns and benefit.\n */\n private calculatePriority(stat: QueryStatistics, estimatedBenefit: number): SuggestionPriority {\n // High priority: frequently queried AND expensive\n if (stat.queryCount > 100 && stat.averageCost > 10) {\n return 'high';\n }\n\n // High priority: very frequently queried\n if (stat.queryCount > 500) {\n return 'high';\n }\n\n // Medium priority: moderate frequency OR cost\n if (stat.queryCount > 50 || stat.averageCost > 5) {\n return 'medium';\n }\n\n // Medium priority: high estimated benefit\n if (estimatedBenefit > 1000) {\n return 'medium';\n }\n\n return 'low';\n }\n\n /**\n * Generate human-readable reason for the suggestion.\n */\n private generateReason(\n stat: QueryStatistics,\n benefit: number,\n benefitingPatterns: number\n ): string {\n const costStr = stat.averageCost.toFixed(2);\n let reason = `Queried ${stat.queryCount}× with average cost ${costStr}ms. `;\n reason += `Expected ~${benefit}× cumulative speedup with index.`;\n\n if (benefitingPatterns > 1) {\n reason += ` Would benefit ${benefitingPatterns} query patterns.`;\n }\n\n return reason;\n }\n\n // ========================================\n // Phase 9.03: Compound Index Suggestions\n // ========================================\n\n /**\n * Get compound index suggestions based on AND query patterns.\n *\n * @param options - Suggestion options\n * @returns Array of compound index suggestions\n */\n getCompoundSuggestions(options: IndexSuggestionOptions = {}): IndexSuggestion[] {\n const {\n minQueryCount = ADAPTIVE_INDEXING_DEFAULTS.advisor.minQueryCount,\n minAverageCost = ADAPTIVE_INDEXING_DEFAULTS.advisor.minAverageCost,\n excludeExistingIndexes = true,\n } = options;\n\n const compoundStats = this.tracker.getCompoundStatistics();\n const suggestions: IndexSuggestion[] = [];\n\n for (const stat of compoundStats) {\n // Skip if already has compound index\n if (excludeExistingIndexes && stat.hasCompoundIndex) continue;\n\n // Skip if below thresholds\n if (stat.queryCount < minQueryCount) continue;\n if (stat.averageCost < minAverageCost) continue;\n\n const suggestion = this.generateCompoundSuggestion(stat);\n if (suggestion) {\n suggestions.push(suggestion);\n }\n }\n\n return suggestions;\n }\n\n /**\n * Get a suggestion for a specific compound attribute combination.\n *\n * @param attributes - Array of attribute names\n * @returns Compound index suggestion or null if not recommended\n */\n getCompoundSuggestionFor(attributes: string[]): IndexSuggestion | null {\n const stat = this.tracker.getCompoundStats(attributes);\n if (!stat) return null;\n\n return this.generateCompoundSuggestion(stat);\n }\n\n /**\n * Check if a compound index should be created for the given attributes.\n *\n * @param attributes - Array of attribute names\n * @param threshold - Minimum query count threshold\n * @returns True if compound index should be created\n */\n shouldCreateCompoundIndex(\n attributes: string[],\n threshold: number = ADAPTIVE_INDEXING_DEFAULTS.autoIndex.threshold!\n ): boolean {\n const stat = this.tracker.getCompoundStats(attributes);\n if (!stat) return false;\n\n return !stat.hasCompoundIndex && stat.queryCount >= threshold;\n }\n\n /**\n * Generate a suggestion for a compound query pattern.\n */\n private generateCompoundSuggestion(stat: CompoundQueryStatistics): IndexSuggestion | null {\n const estimatedBenefit = this.estimateCompoundBenefit(stat);\n const estimatedCost = this.estimateCompoundMemoryCost(stat);\n const priority = this.calculateCompoundPriority(stat, estimatedBenefit);\n\n return {\n attribute: stat.compoundKey,\n indexType: 'compound',\n reason: this.generateCompoundReason(stat, estimatedBenefit),\n estimatedBenefit,\n estimatedCost,\n priority,\n queryCount: stat.queryCount,\n averageCost: stat.averageCost,\n compoundAttributes: stat.attributes,\n };\n }\n\n /**\n * Estimate performance benefit of adding a compound index.\n *\n * Compound indexes provide significant speedup for AND queries:\n * - Eliminates intersection operations (100-1000× for each attribute)\n * - Single O(1) lookup instead of multiple index scans\n */\n private estimateCompoundBenefit(stat: CompoundQueryStatistics): number {\n // Base benefit: compound indexes are more powerful than individual indexes combined\n // Each additional attribute in the compound key roughly doubles the benefit\n const attributeMultiplier = Math.pow(2, stat.attributes.length - 1);\n\n // Cost-based benefit (higher cost = more benefit from indexing)\n let baseBenefit: number;\n if (stat.averageCost > 20) {\n baseBenefit = 1000; // Very expensive AND queries benefit most\n } else if (stat.averageCost > 5) {\n baseBenefit = 500;\n } else if (stat.averageCost > 1) {\n baseBenefit = 100;\n } else {\n baseBenefit = 50;\n }\n\n // Scale by query frequency\n const frequencyMultiplier = Math.min(stat.queryCount / 10, 100);\n\n return Math.floor(baseBenefit * attributeMultiplier * frequencyMultiplier);\n }\n\n /**\n * Estimate memory cost of adding a compound index.\n */\n private estimateCompoundMemoryCost(stat: CompoundQueryStatistics): number {\n const bytesPerRecord = MEMORY_OVERHEAD_ESTIMATES.compound;\n\n // Compound indexes have slightly higher overhead per attribute\n const attributeOverhead = stat.attributes.length * 8; // ~8 bytes per attr in composite key\n\n // Assume ~1000 records as baseline estimate\n const estimatedRecords = 1000;\n\n return Math.floor(estimatedRecords * (bytesPerRecord + attributeOverhead) * 1.5);\n }\n\n /**\n * Calculate priority for compound index suggestion.\n */\n private calculateCompoundPriority(\n stat: CompoundQueryStatistics,\n estimatedBenefit: number\n ): SuggestionPriority {\n // High priority: frequently queried compound patterns with high cost\n if (stat.queryCount > 100 && stat.averageCost > 10) {\n return 'high';\n }\n\n // High priority: very frequently queried\n if (stat.queryCount > 500) {\n return 'high';\n }\n\n // Medium priority: moderate frequency or cost\n if (stat.queryCount > 50 || stat.averageCost > 5) {\n return 'medium';\n }\n\n // Medium priority: high estimated benefit\n if (estimatedBenefit > 2000) {\n return 'medium';\n }\n\n return 'low';\n }\n\n /**\n * Generate human-readable reason for compound index suggestion.\n */\n private generateCompoundReason(stat: CompoundQueryStatistics, benefit: number): string {\n const costStr = stat.averageCost.toFixed(2);\n const attrList = stat.attributes.join(', ');\n let reason = `Compound AND query on [${attrList}] executed ${stat.queryCount}× with average cost ${costStr}ms. `;\n reason += `Expected ~${benefit}× cumulative speedup with compound index. `;\n reason += `Eliminates ${stat.attributes.length - 1} ResultSet intersection(s).`;\n\n return reason;\n }\n}\n","/**\n * AutoIndexManager (Phase 8.02.3)\n *\n * Automatically creates indexes based on query patterns.\n * Intended for development mode to simplify index management.\n *\n * Features:\n * - Automatic index creation after threshold queries\n * - Safety limits to prevent memory exhaustion\n * - Callback notifications for index creation events\n * - Integration with IndexAdvisor for type selection\n *\n * @module query/adaptive/AutoIndexManager\n */\n\nimport type { IndexAdvisor } from './IndexAdvisor';\nimport type { QueryPatternTracker } from './QueryPatternTracker';\nimport type {\n AutoIndexConfig,\n RecommendedIndexType,\n TrackedQueryType,\n} from './types';\nimport { ADAPTIVE_INDEXING_DEFAULTS } from './types';\nimport type { Attribute } from '../Attribute';\n\n/**\n * Interface for indexed map operations.\n * Used to decouple AutoIndexManager from IndexedLWWMap/IndexedORMap.\n */\nexport interface IndexableMap<K, V> {\n /** Get all current indexes */\n getIndexes(): { attribute: { name: string }; type: string }[];\n\n /** Check if attribute has an index */\n hasIndexOn(attributeName: string): boolean;\n\n /** Add a hash index */\n addHashIndex<A>(attribute: Attribute<V, A>): void;\n\n /** Add a navigable index */\n addNavigableIndex<A extends string | number>(attribute: Attribute<V, A>): void;\n\n /** Add an inverted index */\n addInvertedIndex<A extends string>(attribute: Attribute<V, A>): void;\n}\n\n/**\n * Registered attribute info for auto-indexing.\n */\ninterface RegisteredAttribute<V, A> {\n attribute: Attribute<V, A>;\n allowedIndexTypes?: RecommendedIndexType[];\n}\n\n/**\n * AutoIndexManager automatically creates indexes based on query patterns.\n *\n * @example\n * ```typescript\n * const manager = new AutoIndexManager(tracker, advisor, {\n * enabled: true,\n * threshold: 10,\n * maxIndexes: 20,\n * onIndexCreated: (attr, type) => console.log(`Created ${type} on ${attr}`)\n * });\n *\n * manager.registerAttribute(simpleAttribute('category', p => p.category));\n * manager.setMap(indexedMap);\n *\n * // After 10 queries on 'category', index is auto-created\n * ```\n */\nexport class AutoIndexManager<K, V> {\n private readonly config: Required<AutoIndexConfig>;\n private readonly attributeQueryCounts = new Map<string, number>();\n private readonly registeredAttributes = new Map<string, RegisteredAttribute<V, unknown>>();\n private readonly createdIndexes = new Set<string>();\n private map: IndexableMap<K, V> | null = null;\n\n constructor(\n private readonly tracker: QueryPatternTracker,\n private readonly advisor: IndexAdvisor,\n config: AutoIndexConfig\n ) {\n this.config = {\n enabled: config.enabled,\n threshold: config.threshold ?? ADAPTIVE_INDEXING_DEFAULTS.autoIndex.threshold!,\n maxIndexes: config.maxIndexes ?? ADAPTIVE_INDEXING_DEFAULTS.autoIndex.maxIndexes!,\n onIndexCreated: config.onIndexCreated ?? (() => {}),\n };\n }\n\n /**\n * Set the indexed map to create indexes on.\n */\n setMap(map: IndexableMap<K, V>): void {\n this.map = map;\n // Count existing indexes\n for (const index of map.getIndexes()) {\n this.createdIndexes.add(index.attribute.name);\n }\n }\n\n /**\n * Register an attribute that can be auto-indexed.\n *\n * @param attribute - The attribute to register\n * @param allowedIndexTypes - Optional list of allowed index types\n */\n registerAttribute<A>(\n attribute: Attribute<V, A>,\n allowedIndexTypes?: RecommendedIndexType[]\n ): void {\n this.registeredAttributes.set(attribute.name, {\n attribute: attribute as unknown as Attribute<V, unknown>,\n allowedIndexTypes,\n });\n }\n\n /**\n * Unregister an attribute.\n *\n * @param attributeName - Name of attribute to unregister\n */\n unregisterAttribute(attributeName: string): void {\n this.registeredAttributes.delete(attributeName);\n }\n\n /**\n * Check if an attribute is registered.\n *\n * @param attributeName - Name of attribute to check\n * @returns True if attribute is registered\n */\n hasAttribute(attributeName: string): boolean {\n return this.registeredAttributes.has(attributeName);\n }\n\n /**\n * Get a registered attribute.\n *\n * @param attributeName - Name of attribute\n * @returns The attribute or undefined\n */\n getAttribute(attributeName: string): Attribute<V, unknown> | undefined {\n return this.registeredAttributes.get(attributeName)?.attribute;\n }\n\n /**\n * Get all registered attribute names.\n *\n * @returns Array of registered attribute names\n */\n getRegisteredAttributeNames(): string[] {\n return Array.from(this.registeredAttributes.keys());\n }\n\n /**\n * Called when a query is executed. Tracks patterns and triggers auto-indexing.\n *\n * @param attribute - The attribute being queried\n * @param queryType - The type of query\n */\n onQueryExecuted(attribute: string, queryType: TrackedQueryType): void {\n if (!this.config.enabled) return;\n if (!this.map) return;\n\n // Skip if already indexed\n if (this.createdIndexes.has(attribute)) return;\n if (this.map.hasIndexOn(attribute)) {\n this.createdIndexes.add(attribute);\n return;\n }\n\n // Increment query count for this attribute\n const key = `${attribute}:${queryType}`;\n const count = (this.attributeQueryCounts.get(key) || 0) + 1;\n this.attributeQueryCounts.set(key, count);\n\n // Check if threshold reached\n if (count === this.config.threshold) {\n this.tryCreateIndex(attribute, queryType);\n }\n }\n\n /**\n * Check if we're at the index limit.\n *\n * @returns True if max indexes reached\n */\n isAtLimit(): boolean {\n if (!this.map) return false;\n return this.map.getIndexes().length >= this.config.maxIndexes;\n }\n\n /**\n * Get number of auto-created indexes.\n *\n * @returns Number of indexes created by this manager\n */\n getAutoCreatedIndexCount(): number {\n return this.createdIndexes.size;\n }\n\n /**\n * Get remaining index capacity.\n *\n * @returns Number of indexes that can still be created\n */\n getRemainingCapacity(): number {\n if (!this.map) return this.config.maxIndexes;\n return Math.max(0, this.config.maxIndexes - this.map.getIndexes().length);\n }\n\n /**\n * Reset query counts (e.g., after clearing data).\n */\n resetCounts(): void {\n this.attributeQueryCounts.clear();\n }\n\n /**\n * Get current configuration.\n */\n getConfig(): Readonly<AutoIndexConfig> {\n return this.config;\n }\n\n /**\n * Update configuration at runtime.\n *\n * @param updates - Partial config updates\n */\n updateConfig(updates: Partial<AutoIndexConfig>): void {\n if (updates.enabled !== undefined) {\n this.config.enabled = updates.enabled;\n }\n if (updates.threshold !== undefined) {\n this.config.threshold = updates.threshold;\n }\n if (updates.maxIndexes !== undefined) {\n this.config.maxIndexes = updates.maxIndexes;\n }\n if (updates.onIndexCreated !== undefined) {\n this.config.onIndexCreated = updates.onIndexCreated;\n }\n }\n\n /**\n * Try to create an index for the attribute.\n */\n private tryCreateIndex(attribute: string, queryType: TrackedQueryType): void {\n if (!this.map) return;\n\n // Safety check: don't exceed max indexes\n if (this.isAtLimit()) {\n // Optionally log warning\n return;\n }\n\n // Check if attribute is registered\n const registered = this.registeredAttributes.get(attribute);\n if (!registered) {\n // Attribute not registered - cannot create index\n return;\n }\n\n // Determine index type\n const indexType = this.advisor.getRecommendedIndexType(queryType);\n if (!indexType) return;\n\n // Check if index type is allowed for this attribute\n if (\n registered.allowedIndexTypes &&\n !registered.allowedIndexTypes.includes(indexType)\n ) {\n return;\n }\n\n // Create the index\n this.createIndex(attribute, indexType, registered.attribute);\n }\n\n /**\n * Create an index on the map.\n */\n private createIndex(\n attributeName: string,\n indexType: RecommendedIndexType,\n attribute: Attribute<V, unknown>\n ): void {\n if (!this.map) return;\n\n try {\n switch (indexType) {\n case 'hash':\n this.map.addHashIndex(attribute);\n break;\n case 'navigable':\n this.map.addNavigableIndex(attribute as Attribute<V, string | number>);\n break;\n case 'inverted':\n this.map.addInvertedIndex(attribute as Attribute<V, string>);\n break;\n }\n\n // Track creation\n this.createdIndexes.add(attributeName);\n\n // Update tracker - mark as indexed\n this.tracker.updateIndexStatus(attributeName, true);\n\n // Notify callback\n this.config.onIndexCreated(attributeName, indexType);\n } catch (error) {\n // Index creation failed - log but don't throw\n console.error(`AutoIndexManager: Failed to create ${indexType} index on '${attributeName}':`, error);\n }\n }\n}\n","/**\n * DefaultIndexingStrategy (Phase 8.02.4)\n *\n * Automatically indexes fields based on data structure analysis.\n * Applied on first record insertion to index scalar fields.\n *\n * Features:\n * - Runtime type introspection\n * - Heuristic-based index type selection\n * - Support for 'scalar' and 'all' strategies\n *\n * @module query/adaptive/DefaultIndexingStrategy\n */\n\nimport type { Attribute } from '../Attribute';\nimport { simpleAttribute } from '../Attribute';\nimport type { DefaultIndexingStrategy as StrategyType } from './types';\n\n/**\n * Field info extracted from a sample record.\n */\nexport interface FieldInfo {\n /** Field name (path for nested: 'address.city') */\n name: string;\n /** JavaScript type */\n type: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'null' | 'undefined';\n /** Whether this is a scalar (primitive) value */\n isScalar: boolean;\n /** Nested depth (0 = top-level) */\n depth: number;\n /** Sample value for heuristics */\n sampleValue: unknown;\n}\n\n/**\n * Index recommendation for a field.\n */\nexport interface FieldIndexRecommendation {\n /** Field name */\n field: string;\n /** Recommended index type */\n indexType: 'hash' | 'navigable';\n /** Reason for recommendation */\n reason: string;\n}\n\n/**\n * Interface for indexed map operations used by DefaultIndexingStrategy.\n */\nexport interface DefaultIndexableMap<V> {\n /** Add a hash index */\n addHashIndex<A>(attribute: Attribute<V, A>): void;\n\n /** Add a navigable index */\n addNavigableIndex<A extends string | number>(attribute: Attribute<V, A>): void;\n\n /** Check if attribute has an index */\n hasIndexOn(attributeName: string): boolean;\n}\n\n/**\n * DefaultIndexingStrategy analyzes record structure and creates indexes.\n *\n * @example\n * ```typescript\n * const strategy = new DefaultIndexingStrategy<Product>('scalar');\n *\n * // On first record insertion\n * strategy.applyToMap(indexedMap, {\n * id: '1',\n * name: 'Widget',\n * price: 29.99,\n * inStock: true\n * });\n *\n * // Creates:\n * // - HashIndex on 'id'\n * // - HashIndex on 'name'\n * // - NavigableIndex on 'price'\n * // - HashIndex on 'inStock'\n * ```\n */\nexport class DefaultIndexingStrategy<V> {\n private applied = false;\n\n constructor(private readonly strategy: StrategyType) {}\n\n /**\n * Check if strategy has been applied.\n */\n isApplied(): boolean {\n return this.applied;\n }\n\n /**\n * Analyze a sample record and apply indexes to the map.\n *\n * @param map - The indexed map to add indexes to\n * @param sample - A sample record to analyze\n */\n applyToMap(map: DefaultIndexableMap<V>, sample: V): void {\n if (this.strategy === 'none') return;\n if (this.applied) return;\n\n const recommendations = this.analyzeAndRecommend(sample);\n\n for (const rec of recommendations) {\n if (map.hasIndexOn(rec.field)) continue;\n\n const attribute = this.createAttribute(rec.field);\n\n try {\n if (rec.indexType === 'hash') {\n map.addHashIndex(attribute);\n } else {\n map.addNavigableIndex(attribute as Attribute<V, string | number>);\n }\n } catch (error) {\n // Log but don't fail if index creation fails\n console.warn(`DefaultIndexing: Failed to create ${rec.indexType} index on '${rec.field}':`, error);\n }\n }\n\n this.applied = true;\n }\n\n /**\n * Analyze a sample record and return index recommendations.\n *\n * @param sample - A sample record to analyze\n * @returns Array of field index recommendations\n */\n analyzeAndRecommend(sample: V): FieldIndexRecommendation[] {\n const fields = this.extractFields(sample, '', 0);\n const recommendations: FieldIndexRecommendation[] = [];\n\n for (const field of fields) {\n const rec = this.recommendIndex(field);\n if (rec) {\n recommendations.push(rec);\n }\n }\n\n return recommendations;\n }\n\n /**\n * Extract field info from a record recursively.\n */\n private extractFields(value: unknown, prefix: string, depth: number): FieldInfo[] {\n const fields: FieldInfo[] = [];\n\n if (value === null || value === undefined) {\n return fields;\n }\n\n if (typeof value !== 'object') {\n return fields;\n }\n\n // Handle arrays (skip for now - need MultiValueAttribute)\n if (Array.isArray(value)) {\n return fields;\n }\n\n for (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n const fieldName = prefix ? `${prefix}.${key}` : key;\n const fieldType = this.getType(val);\n\n fields.push({\n name: fieldName,\n type: fieldType,\n isScalar: this.isScalar(fieldType),\n depth,\n sampleValue: val,\n });\n\n // Recurse into nested objects if strategy is 'all'\n if (this.strategy === 'all' && fieldType === 'object' && val !== null) {\n fields.push(...this.extractFields(val, fieldName, depth + 1));\n }\n }\n\n return fields;\n }\n\n /**\n * Get JavaScript type of a value.\n */\n private getType(value: unknown): FieldInfo['type'] {\n if (value === null) return 'null';\n if (value === undefined) return 'undefined';\n if (Array.isArray(value)) return 'array';\n\n const type = typeof value;\n if (type === 'string') return 'string';\n if (type === 'number') return 'number';\n if (type === 'boolean') return 'boolean';\n if (type === 'object') return 'object';\n\n return 'undefined';\n }\n\n /**\n * Check if a type is scalar (primitive).\n */\n private isScalar(type: FieldInfo['type']): boolean {\n return type === 'string' || type === 'number' || type === 'boolean';\n }\n\n /**\n * Recommend an index for a field.\n */\n private recommendIndex(field: FieldInfo): FieldIndexRecommendation | null {\n // Only index scalars\n if (!field.isScalar) return null;\n\n // Only index top-level for 'scalar' strategy\n if (this.strategy === 'scalar' && field.depth > 0) {\n return null;\n }\n\n // Skip fields that look like high-cardinality text (descriptions, etc.)\n if (field.type === 'string' && this.looksLikeDescription(field)) {\n return null;\n }\n\n // Determine index type\n const indexType = this.selectIndexType(field);\n const reason = this.generateReason(field, indexType);\n\n return {\n field: field.name,\n indexType,\n reason,\n };\n }\n\n /**\n * Check if a string field looks like a description (high-cardinality text).\n */\n private looksLikeDescription(field: FieldInfo): boolean {\n if (field.type !== 'string') return false;\n\n // Heuristic: skip if name contains common description-like words\n const descriptionPatterns = [\n 'description',\n 'desc',\n 'content',\n 'body',\n 'text',\n 'message',\n 'comment',\n 'note',\n 'bio',\n 'summary',\n 'abstract',\n ];\n\n const lowerName = field.name.toLowerCase();\n for (const pattern of descriptionPatterns) {\n if (lowerName.includes(pattern)) {\n return true;\n }\n }\n\n // Heuristic: skip if sample value is long (> 100 chars)\n if (typeof field.sampleValue === 'string' && field.sampleValue.length > 100) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Select appropriate index type for a field.\n */\n private selectIndexType(field: FieldInfo): 'hash' | 'navigable' {\n // Numbers are usually range-queried\n if (field.type === 'number') {\n // Exception: fields ending in 'Id' are usually equality\n if (field.name.toLowerCase().endsWith('id')) {\n return 'hash';\n }\n return 'navigable';\n }\n\n // Booleans are always equality\n if (field.type === 'boolean') {\n return 'hash';\n }\n\n // Strings: check for common patterns\n if (field.type === 'string') {\n // IDs are equality\n if (field.name.toLowerCase().endsWith('id') || field.name.toLowerCase() === 'id') {\n return 'hash';\n }\n\n // Dates/timestamps might benefit from range queries\n if (this.looksLikeDate(field)) {\n return 'navigable';\n }\n\n // Default: hash for strings\n return 'hash';\n }\n\n return 'hash';\n }\n\n /**\n * Check if a field looks like a date/timestamp.\n */\n private looksLikeDate(field: FieldInfo): boolean {\n const lowerName = field.name.toLowerCase();\n\n // Check for explicit date/time patterns\n const datePatterns = ['date', 'time', 'timestamp'];\n for (const pattern of datePatterns) {\n if (lowerName.includes(pattern)) {\n return true;\n }\n }\n\n // Check for common date-related suffixes (must end with these)\n const dateSuffixes = ['_at', 'At', 'created', 'updated'];\n for (const suffix of dateSuffixes) {\n if (field.name.endsWith(suffix)) {\n return true;\n }\n }\n\n // Check if sample value looks like ISO date\n if (typeof field.sampleValue === 'string') {\n const isoDatePattern = /^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2})?/;\n if (isoDatePattern.test(field.sampleValue)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Generate reason for the recommendation.\n */\n private generateReason(field: FieldInfo, indexType: 'hash' | 'navigable'): string {\n if (indexType === 'navigable') {\n if (field.type === 'number') {\n return `Numeric field '${field.name}' likely used for range queries`;\n }\n if (this.looksLikeDate(field)) {\n return `Date-like field '${field.name}' likely used for range queries`;\n }\n }\n\n if (field.name.toLowerCase().endsWith('id') || field.name.toLowerCase() === 'id') {\n return `ID field '${field.name}' typically used for equality lookups`;\n }\n\n if (field.type === 'boolean') {\n return `Boolean field '${field.name}' used for equality filtering`;\n }\n\n return `Scalar field '${field.name}' of type ${field.type}`;\n }\n\n /**\n * Create an attribute for a field path.\n */\n private createAttribute(fieldPath: string): Attribute<V, unknown> {\n const parts = fieldPath.split('.');\n\n if (parts.length === 1) {\n // Simple top-level field\n return simpleAttribute(fieldPath, (record: V) => {\n return (record as Record<string, unknown>)[fieldPath];\n });\n }\n\n // Nested field (e.g., 'address.city')\n return simpleAttribute(fieldPath, (record: V) => {\n let current: unknown = record;\n for (const part of parts) {\n if (current === null || current === undefined) return undefined;\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n });\n }\n}\n","/**\n * Reciprocal Rank Fusion (RRF)\n *\n * Implements RRF algorithm for merging ranked results from multiple search methods.\n * Used in hybrid queries that combine exact matches, range queries, and full-text search.\n *\n * Formula: RRF_score(d) = Σ 1 / (k + rank_i(d))\n *\n * Reference: Cormack, Clarke, Buettcher (2009) - \"Reciprocal Rank Fusion outperforms\n * Condorcet and individual Rank Learning Methods\"\n *\n * @module search/ReciprocalRankFusion\n */\n\n/**\n * A ranked result from a single search method.\n */\nexport interface RankedResult {\n /** Unique document identifier */\n docId: string;\n /** Original score from the search method (e.g., BM25 score) */\n score: number;\n /** Source of this result: 'exact' | 'fulltext' | 'range' | custom */\n source: string;\n}\n\n/**\n * Configuration for RRF algorithm.\n */\nexport interface RRFConfig {\n /**\n * Ranking constant k.\n * Higher values reduce the impact of high rankings.\n * Default: 60 (standard value from literature)\n */\n k?: number;\n}\n\n/**\n * Merged result with combined RRF score.\n */\nexport interface MergedResult {\n /** Unique document identifier */\n docId: string;\n /** Combined RRF score */\n score: number;\n /** Combined sources (e.g., \"exact+fulltext\") */\n source: string;\n /** Original scores from each source */\n originalScores: Record<string, number>;\n}\n\n/**\n * Reciprocal Rank Fusion implementation.\n *\n * Merges results from multiple ranked lists using the RRF formula.\n * Documents appearing in multiple result sets get boosted scores.\n *\n * @example\n * ```typescript\n * const rrf = new ReciprocalRankFusion({ k: 60 });\n *\n * const exactResults = [\n * { docId: 'doc1', score: 1.0, source: 'exact' },\n * { docId: 'doc2', score: 1.0, source: 'exact' },\n * ];\n *\n * const ftsResults = [\n * { docId: 'doc2', score: 2.5, source: 'fulltext' },\n * { docId: 'doc3', score: 1.8, source: 'fulltext' },\n * ];\n *\n * const merged = rrf.merge([exactResults, ftsResults]);\n * // doc2 ranks highest (appears in both sets)\n * ```\n */\nexport class ReciprocalRankFusion {\n private readonly k: number;\n\n constructor(config?: RRFConfig) {\n this.k = config?.k ?? 60;\n }\n\n /**\n * Merge multiple ranked result lists using RRF.\n *\n * Formula: RRF_score(d) = Σ 1 / (k + rank_i(d))\n *\n * @param resultSets - Array of ranked result lists from different search methods\n * @returns Merged results sorted by RRF score (descending)\n */\n merge(resultSets: RankedResult[][]): MergedResult[] {\n // Filter out empty sets\n const nonEmptySets = resultSets.filter((set) => set.length > 0);\n\n if (nonEmptySets.length === 0) {\n return [];\n }\n\n // Map to accumulate RRF scores and track sources\n const scoreMap = new Map<\n string,\n {\n rrfScore: number;\n sources: Set<string>;\n originalScores: Record<string, number>;\n }\n >();\n\n // Process each result set\n for (const resultSet of nonEmptySets) {\n for (let rank = 0; rank < resultSet.length; rank++) {\n const result = resultSet[rank];\n const { docId, score, source } = result;\n\n // RRF formula: 1 / (k + rank)\n // Note: rank is 0-indexed, but RRF typically uses 1-indexed ranks\n const rrfContribution = 1 / (this.k + rank + 1);\n\n const existing = scoreMap.get(docId);\n if (existing) {\n existing.rrfScore += rrfContribution;\n existing.sources.add(source);\n existing.originalScores[source] = score;\n } else {\n scoreMap.set(docId, {\n rrfScore: rrfContribution,\n sources: new Set([source]),\n originalScores: { [source]: score },\n });\n }\n }\n }\n\n // Convert to array and sort by RRF score\n const merged: MergedResult[] = [];\n for (const [docId, data] of scoreMap) {\n merged.push({\n docId,\n score: data.rrfScore,\n source: Array.from(data.sources).sort().join('+'),\n originalScores: data.originalScores,\n });\n }\n\n // Sort by score descending\n merged.sort((a, b) => b.score - a.score);\n\n return merged;\n }\n\n /**\n * Merge with weighted RRF for different method priorities.\n *\n * Weighted formula: RRF_score(d) = Σ weight_i * (1 / (k + rank_i(d)))\n *\n * @param resultSets - Array of ranked result lists\n * @param weights - Weights for each result set (same order as resultSets)\n * @returns Merged results sorted by weighted RRF score (descending)\n *\n * @example\n * ```typescript\n * const rrf = new ReciprocalRankFusion();\n *\n * // Prioritize exact matches (weight 2.0) over FTS (weight 1.0)\n * const merged = rrf.mergeWeighted(\n * [exactResults, ftsResults],\n * [2.0, 1.0]\n * );\n * ```\n */\n mergeWeighted(resultSets: RankedResult[][], weights: number[]): MergedResult[] {\n // Validate weights array length\n if (weights.length !== resultSets.length) {\n throw new Error(\n `Weights array length (${weights.length}) must match resultSets length (${resultSets.length})`\n );\n }\n\n // Filter out empty sets (and their corresponding weights)\n const nonEmptyPairs: Array<{ resultSet: RankedResult[]; weight: number }> = [];\n for (let i = 0; i < resultSets.length; i++) {\n if (resultSets[i].length > 0) {\n nonEmptyPairs.push({ resultSet: resultSets[i], weight: weights[i] });\n }\n }\n\n if (nonEmptyPairs.length === 0) {\n return [];\n }\n\n // Map to accumulate weighted RRF scores\n const scoreMap = new Map<\n string,\n {\n rrfScore: number;\n sources: Set<string>;\n originalScores: Record<string, number>;\n }\n >();\n\n // Process each result set with its weight\n for (const { resultSet, weight } of nonEmptyPairs) {\n for (let rank = 0; rank < resultSet.length; rank++) {\n const result = resultSet[rank];\n const { docId, score, source } = result;\n\n // Weighted RRF formula: weight * (1 / (k + rank))\n const rrfContribution = weight * (1 / (this.k + rank + 1));\n\n const existing = scoreMap.get(docId);\n if (existing) {\n existing.rrfScore += rrfContribution;\n existing.sources.add(source);\n existing.originalScores[source] = score;\n } else {\n scoreMap.set(docId, {\n rrfScore: rrfContribution,\n sources: new Set([source]),\n originalScores: { [source]: score },\n });\n }\n }\n }\n\n // Convert to array and sort by RRF score\n const merged: MergedResult[] = [];\n for (const [docId, data] of scoreMap) {\n merged.push({\n docId,\n score: data.rrfScore,\n source: Array.from(data.sources).sort().join('+'),\n originalScores: data.originalScores,\n });\n }\n\n // Sort by score descending\n merged.sort((a, b) => b.score - a.score);\n\n return merged;\n }\n\n /**\n * Get the k constant used for RRF calculation.\n */\n getK(): number {\n return this.k;\n }\n}\n","/**\n * Universal Base64URL encoding/decoding utilities.\n *\n * Works in both Node.js and browser environments.\n * Used by QueryCursor and SearchCursor for opaque cursor encoding.\n *\n * @module utils/base64url\n */\n\n/**\n * Encode a string to base64url format.\n * URL-safe, no padding characters.\n *\n * @param str - UTF-8 string to encode\n * @returns Base64url encoded string\n */\nexport function encodeBase64Url(str: string): string {\n // Node.js environment\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'utf8').toString('base64url');\n }\n\n // Browser environment\n const base64 = btoa(unescape(encodeURIComponent(str)));\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/**\n * Decode a base64url string back to UTF-8.\n *\n * @param encoded - Base64url encoded string\n * @returns Decoded UTF-8 string\n * @throws Error if decoding fails\n */\nexport function decodeBase64Url(encoded: string): string {\n // Node.js environment\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(encoded, 'base64url').toString('utf8');\n }\n\n // Browser environment\n let base64 = encoded.replace(/-/g, '+').replace(/_/g, '/');\n\n // Add padding if needed\n const pad = base64.length % 4;\n if (pad) {\n base64 += '='.repeat(4 - pad);\n }\n\n return decodeURIComponent(escape(atob(base64)));\n}\n","/**\n * Universal value comparison utilities.\n *\n * Provides type-aware comparison for sorting and cursor-based pagination.\n * Used by QueryCursor, QueryExecutor, and other components that need\n * consistent value ordering.\n *\n * @module utils/compare\n */\n\n/**\n * Compare two values with type-aware comparison.\n *\n * Comparison order:\n * 1. null/undefined (always less than defined values)\n * 2. Numbers (numeric comparison)\n * 3. Date objects (by timestamp)\n * 4. Strings (ISO date parsing attempted, then localeCompare)\n * 5. Booleans (false < true)\n * 6. Fallback: string conversion and localeCompare\n *\n * @param a - First value\n * @param b - Second value\n * @returns Negative if a < b, 0 if equal, positive if a > b\n *\n * @example\n * ```typescript\n * compareValues(1, 2); // -1\n * compareValues('b', 'a'); // 1\n * compareValues(null, 1); // -1\n * compareValues(new Date('2024-01-01'), new Date('2024-01-02')); // -86400000\n * ```\n */\nexport function compareValues(a: unknown, b: unknown): number {\n // Handle null/undefined\n if (a == null && b == null) return 0;\n if (a == null) return -1;\n if (b == null) return 1;\n\n // Numbers\n if (typeof a === 'number' && typeof b === 'number') {\n return a - b;\n }\n\n // Dates (as Date objects)\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() - b.getTime();\n }\n\n // Strings - try ISO date parsing first, then regular comparison\n if (typeof a === 'string' && typeof b === 'string') {\n const dateA = Date.parse(a);\n const dateB = Date.parse(b);\n // Only use date comparison if BOTH are valid ISO dates\n if (!isNaN(dateA) && !isNaN(dateB)) {\n return dateA - dateB;\n }\n // Regular string comparison\n return a.localeCompare(b);\n }\n\n // Booleans\n if (typeof a === 'boolean' && typeof b === 'boolean') {\n return a === b ? 0 : a ? 1 : -1;\n }\n\n // Fallback: string comparison\n return String(a).localeCompare(String(b));\n}\n\n/**\n * Create a comparator function for sorting by a specific field.\n *\n * @param field - Field name to sort by\n * @param direction - Sort direction ('asc' or 'desc')\n * @returns Comparator function for Array.sort()\n *\n * @example\n * ```typescript\n * const items = [{ name: 'Bob' }, { name: 'Alice' }];\n * items.sort(createFieldComparator('name', 'asc'));\n * // [{ name: 'Alice' }, { name: 'Bob' }]\n * ```\n */\nexport function createFieldComparator<T extends Record<string, unknown>>(\n field: string,\n direction: 'asc' | 'desc' = 'asc'\n): (a: T, b: T) => number {\n return (a: T, b: T) => {\n const comparison = compareValues(a[field], b[field]);\n return direction === 'desc' ? -comparison : comparison;\n };\n}\n","/**\n * QueryCursor - Cursor-based pagination for distributed queries (Phase 14.1)\n *\n * Implements opaque cursor encoding for efficient deep pagination in distributed\n * predicate-based queries. Cursors encode the last seen position per node, enabling\n * each node to resume from where it left off.\n *\n * Problem solved: With offset-based pagination in a distributed system, each node\n * must return offset+limit results, causing O(N*offset) network overhead.\n * Cursor-based pagination reduces this to O(N*limit).\n *\n * Related: SearchCursor (search/SearchCursor.ts) provides similar functionality for\n * FTS queries using BM25 scores. Both use shared base64url encoding utilities.\n *\n * Future consideration: A shared base class could extract common encode/decode\n * and timestamp validation logic, but the semantic differences (sortValue vs score,\n * configurable direction vs fixed DESC) make this a low-priority refactor.\n *\n * @module query/QueryCursor\n */\n\nimport { encodeBase64Url, decodeBase64Url } from '../utils/base64url';\nimport { hashObject } from '../utils/hash';\nimport { compareValues } from '../utils/compare';\n\n/**\n * Internal cursor data structure for query pagination.\n * Encoded as base64url for wire transfer.\n */\nexport interface QueryCursorData {\n /**\n * Last seen sort values per node.\n * For single-field sort only (multi-field sort is out of scope for v1).\n */\n nodeValues: Record<string, unknown>;\n\n /**\n * Last seen keys per node (for tie-breaking).\n */\n nodeKeys: Record<string, string>;\n\n /**\n * Sort field name (must match query sort).\n */\n sortField: string;\n\n /**\n * Sort direction.\n */\n sortDirection: 'asc' | 'desc';\n\n /**\n * Hash of query predicate (for validation).\n */\n predicateHash: number;\n\n /**\n * Hash of sort configuration (for validation).\n */\n sortHash: number;\n\n /**\n * Timestamp when cursor was created (for expiration).\n */\n timestamp: number;\n}\n\n/**\n * Result item with node tracking for cursor generation.\n */\nexport interface CursorableQueryResult {\n key: string;\n sortValue: unknown;\n nodeId?: string;\n}\n\n/**\n * Options for cursor validation.\n */\nexport interface QueryCursorOptions {\n /**\n * Maximum cursor age in milliseconds.\n * Default: 10 minutes (600,000 ms)\n */\n maxAgeMs?: number;\n}\n\n/**\n * Default cursor expiration time (10 minutes).\n */\nexport const DEFAULT_QUERY_CURSOR_MAX_AGE_MS = 10 * 60 * 1000;\n\n/**\n * QueryCursor provides cursor-based pagination for distributed queries.\n *\n * @example\n * ```typescript\n * // Create cursor from query results\n * const cursor = QueryCursor.fromResults(\n * results,\n * { createdAt: 'desc' },\n * predicate\n * );\n *\n * // Use cursor in next query request\n * const cursorData = QueryCursor.decode(cursor);\n * if (cursorData && QueryCursor.isValid(cursorData, predicate, sort)) {\n * // Filter results using cursor position\n * const filtered = results.filter(r =>\n * QueryCursor.isAfterCursor(r, cursorData)\n * );\n * }\n * ```\n */\nexport class QueryCursor {\n /**\n * Encode cursor data to an opaque base64url string.\n *\n * @param data - Cursor data to encode\n * @returns Opaque cursor string\n */\n static encode(data: QueryCursorData): string {\n const json = JSON.stringify(data);\n return encodeBase64Url(json);\n }\n\n /**\n * Decode cursor string back to data.\n *\n * @param cursor - Opaque cursor string\n * @returns Decoded cursor data, or null if invalid\n */\n static decode(cursor: string): QueryCursorData | null {\n try {\n const json = decodeBase64Url(cursor);\n const data = JSON.parse(json);\n\n // Validate structure\n if (\n typeof data !== 'object' ||\n typeof data.nodeValues !== 'object' ||\n typeof data.nodeKeys !== 'object' ||\n typeof data.sortField !== 'string' ||\n (data.sortDirection !== 'asc' && data.sortDirection !== 'desc') ||\n typeof data.predicateHash !== 'number' ||\n typeof data.sortHash !== 'number' ||\n typeof data.timestamp !== 'number'\n ) {\n return null;\n }\n\n return data as QueryCursorData;\n } catch {\n return null;\n }\n }\n\n /**\n * Create a cursor from query results.\n *\n * The cursor captures the last seen position for each node that contributed\n * results, enabling efficient resumption in the next page request.\n *\n * @param results - Array of results with sort values and optional node tracking\n * @param sort - Sort configuration (single field only for v1)\n * @param predicate - Query predicate (for validation)\n * @returns Encoded cursor string\n */\n static fromResults(\n results: CursorableQueryResult[],\n sort: Record<string, 'asc' | 'desc'>,\n predicate?: unknown\n ): string {\n const nodeValues: Record<string, unknown> = {};\n const nodeKeys: Record<string, string> = {};\n\n // Get sort field and direction (single-field only for v1)\n const sortEntries = Object.entries(sort);\n if (sortEntries.length === 0) {\n throw new Error('Sort configuration required for cursor pagination');\n }\n const [sortField, sortDirection] = sortEntries[0];\n\n // Track last result per node\n // Results should be in sorted order, so we just take the last per node\n for (const result of results) {\n const nodeId = result.nodeId ?? 'local';\n // Always update to get the last (furthest position) for each node\n nodeValues[nodeId] = result.sortValue;\n nodeKeys[nodeId] = result.key;\n }\n\n const data: QueryCursorData = {\n nodeValues,\n nodeKeys,\n sortField,\n sortDirection,\n predicateHash: hashObject(predicate ?? null),\n sortHash: hashObject(sort),\n timestamp: Date.now(),\n };\n\n return this.encode(data);\n }\n\n /**\n * Create a cursor from the last result only.\n * Useful for local-only queries.\n *\n * @param lastResult - The last result in the current page\n * @param sort - Sort configuration\n * @param predicate - Query predicate\n * @returns Encoded cursor string\n */\n static fromLastResult(\n lastResult: CursorableQueryResult,\n sort: Record<string, 'asc' | 'desc'>,\n predicate?: unknown\n ): string {\n return this.fromResults([lastResult], sort, predicate);\n }\n\n /**\n * Validate that a cursor is valid for the given query.\n *\n * Checks:\n * 1. Predicate hash matches (cursor was created for this query)\n * 2. Sort hash matches (sort configuration unchanged)\n * 3. Cursor is not expired\n *\n * @param cursor - Decoded cursor data\n * @param predicate - Query predicate to validate against\n * @param sort - Sort configuration to validate against\n * @param options - Validation options\n * @returns true if cursor is valid\n */\n static isValid(\n cursor: QueryCursorData,\n predicate: unknown,\n sort: Record<string, 'asc' | 'desc'>,\n options?: QueryCursorOptions\n ): boolean {\n const maxAge = options?.maxAgeMs ?? DEFAULT_QUERY_CURSOR_MAX_AGE_MS;\n\n // Check predicate hash matches\n if (cursor.predicateHash !== hashObject(predicate ?? null)) {\n return false;\n }\n\n // Check sort hash matches\n if (cursor.sortHash !== hashObject(sort)) {\n return false;\n }\n\n // Check not expired\n if (Date.now() - cursor.timestamp > maxAge) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Get the cursor position for a specific node.\n *\n * @param cursor - Decoded cursor data\n * @param nodeId - Node ID to get position for (defaults to 'local')\n * @returns Position info or null if node not in cursor\n */\n static getNodePosition(\n cursor: QueryCursorData,\n nodeId: string = 'local'\n ): { afterValue: unknown; afterKey: string } | null {\n if (!(nodeId in cursor.nodeValues)) {\n return null;\n }\n\n return {\n afterValue: cursor.nodeValues[nodeId],\n afterKey: cursor.nodeKeys[nodeId],\n };\n }\n\n /**\n * Check if a result should be included based on cursor position.\n *\n * For ASC sort: value > cursorValue OR (value === cursorValue AND key > cursorKey)\n * For DESC sort: value < cursorValue OR (value === cursorValue AND key > cursorKey)\n *\n * @param result - Result to check\n * @param cursor - Decoded cursor data\n * @returns true if result should be included (is after cursor)\n */\n static isAfterCursor(\n result: CursorableQueryResult,\n cursor: QueryCursorData\n ): boolean {\n const nodeId = result.nodeId ?? 'local';\n const position = this.getNodePosition(cursor, nodeId);\n\n // Node not in cursor - include all results from that node\n if (!position) {\n return true;\n }\n\n const cmp = this.compareValues(result.sortValue, position.afterValue);\n\n if (cursor.sortDirection === 'asc') {\n // ASC: higher values come after\n if (cmp > 0) return true;\n if (cmp === 0 && result.key > position.afterKey) return true;\n } else {\n // DESC: lower values come after\n if (cmp < 0) return true;\n if (cmp === 0 && result.key > position.afterKey) return true;\n }\n\n return false;\n }\n\n /**\n * Compare two values with type-aware comparison.\n * Delegates to shared compareValues utility.\n *\n * @param a - First value\n * @param b - Second value\n * @returns Negative if a < b, 0 if equal, positive if a > b\n */\n static compareValues(a: unknown, b: unknown): number {\n return compareValues(a, b);\n }\n\n /**\n * Merge multiple cursors into one.\n * Useful when combining results from multiple sub-queries or nodes.\n *\n * Keeps the furthest position for each node.\n *\n * @param cursors - Array of decoded cursor data\n * @param sort - Sort configuration\n * @param predicate - Query predicate\n * @returns New merged cursor\n */\n static merge(\n cursors: QueryCursorData[],\n sort: Record<string, 'asc' | 'desc'>,\n predicate?: unknown\n ): QueryCursorData {\n const nodeValues: Record<string, unknown> = {};\n const nodeKeys: Record<string, string> = {};\n\n // Get sort field and direction\n const sortEntries = Object.entries(sort);\n const [sortField, sortDirection] = sortEntries[0];\n\n for (const cursor of cursors) {\n for (const nodeId of Object.keys(cursor.nodeValues)) {\n const existingValue = nodeValues[nodeId];\n const newValue = cursor.nodeValues[nodeId];\n\n if (existingValue === undefined) {\n // First value for this node\n nodeValues[nodeId] = newValue;\n nodeKeys[nodeId] = cursor.nodeKeys[nodeId];\n } else {\n // Compare values to keep furthest position\n const cmp = this.compareValues(newValue, existingValue);\n const isFurther =\n sortDirection === 'asc'\n ? cmp > 0 || (cmp === 0 && cursor.nodeKeys[nodeId] > nodeKeys[nodeId])\n : cmp < 0 || (cmp === 0 && cursor.nodeKeys[nodeId] > nodeKeys[nodeId]);\n\n if (isFurther) {\n nodeValues[nodeId] = newValue;\n nodeKeys[nodeId] = cursor.nodeKeys[nodeId];\n }\n }\n }\n }\n\n return {\n nodeValues,\n nodeKeys,\n sortField,\n sortDirection,\n predicateHash: hashObject(predicate ?? null),\n sortHash: hashObject(sort),\n timestamp: Date.now(),\n };\n }\n\n /**\n * Extract sort value from a record for cursor generation.\n *\n * @param record - Record to extract sort value from\n * @param sortField - Field to extract\n * @returns Sort value\n */\n static extractSortValue(record: Record<string, unknown>, sortField: string): unknown {\n return record[sortField];\n }\n}\n","/**\n * IndexedLWWMap Implementation\n *\n * LWWMap with index support for O(1) to O(log N) queries.\n * Wraps LWWMap with indexing capabilities using the Wrapper Pattern.\n *\n * Features:\n * - Hash and Navigable indexes for efficient queries\n * - Live queries with StandingQueryIndex\n * - Automatic index updates on CRDT operations\n * - Cost-based query optimization\n * - Adaptive indexing with query pattern tracking (Phase 8.02)\n *\n * @module IndexedLWWMap\n */\n\nimport { LWWMap, LWWRecord } from './LWWMap';\nimport { HLC } from './HLC';\nimport { IndexRegistry, IndexRegistryStats } from './query/IndexRegistry';\nimport { QueryOptimizer } from './query/QueryOptimizer';\nimport { StandingQueryRegistry } from './query/StandingQueryRegistry';\nimport {\n LiveQueryManager,\n LiveQueryCallback,\n LiveQueryEvent,\n} from './query/LiveQueryManager';\nimport type { Index, IndexStats, IndexQuery } from './query/indexes/types';\nimport { HashIndex } from './query/indexes/HashIndex';\nimport { NavigableIndex } from './query/indexes/NavigableIndex';\nimport { FallbackIndex } from './query/indexes/FallbackIndex';\nimport { InvertedIndex } from './query/indexes/InvertedIndex';\nimport { TokenizationPipeline } from './query/tokenization';\nimport {\n LazyHashIndex,\n LazyNavigableIndex,\n LazyInvertedIndex,\n} from './query/indexes/lazy';\nimport { Attribute, simpleAttribute } from './query/Attribute';\nimport type { Query, QueryPlan, PlanStep, SimpleQueryNode } from './query/QueryTypes';\nimport { isSimpleQuery } from './query/QueryTypes';\nimport type { ResultSet } from './query/resultset/ResultSet';\nimport { SetResultSet } from './query/resultset/SetResultSet';\nimport { IntersectionResultSet } from './query/resultset/IntersectionResultSet';\nimport { UnionResultSet } from './query/resultset/UnionResultSet';\nimport { FilteringResultSet } from './query/resultset/FilteringResultSet';\nimport { evaluatePredicate, PredicateNode } from './predicate';\n\n// Adaptive indexing imports (Phase 8.02)\nimport {\n QueryPatternTracker,\n IndexAdvisor,\n AutoIndexManager,\n DefaultIndexingStrategy,\n} from './query/adaptive';\nimport type {\n IndexedMapOptions,\n IndexSuggestion,\n IndexSuggestionOptions,\n QueryStatistics,\n TrackedQueryType,\n RecommendedIndexType,\n IndexBuildProgressCallback,\n} from './query/adaptive/types';\nimport { ADAPTIVE_INDEXING_DEFAULTS } from './query/adaptive/types';\nimport type { LazyIndex } from './query/indexes/lazy';\n\n/**\n * LWWMap with index support for O(1) to O(log N) queries.\n *\n * K = key type (extends string for compatibility)\n * V = value type\n */\nexport class IndexedLWWMap<K extends string, V> extends LWWMap<K, V> {\n private indexRegistry: IndexRegistry<K, V>;\n private standingQueryRegistry: StandingQueryRegistry<K, V>;\n private liveQueryManager: LiveQueryManager<K, V>;\n private queryOptimizer: QueryOptimizer<K, V>;\n\n // Adaptive indexing (Phase 8.02)\n private readonly queryTracker: QueryPatternTracker;\n private readonly indexAdvisor: IndexAdvisor;\n private readonly autoIndexManager: AutoIndexManager<K, V> | null;\n private readonly defaultIndexingStrategy: DefaultIndexingStrategy<V> | null;\n private readonly options: IndexedMapOptions;\n\n constructor(hlc: HLC, options: IndexedMapOptions = {}) {\n super(hlc);\n this.options = options;\n\n this.indexRegistry = new IndexRegistry();\n this.standingQueryRegistry = new StandingQueryRegistry({\n getRecord: (key) => this.get(key),\n getAllEntries: () => this.entries(),\n });\n this.liveQueryManager = new LiveQueryManager({\n getRecord: (key) => this.get(key),\n getAllEntries: () => this.entries(),\n });\n this.queryOptimizer = new QueryOptimizer({\n indexRegistry: this.indexRegistry,\n standingQueryRegistry: this.standingQueryRegistry,\n });\n\n // Set up fallback index for full scans\n this.indexRegistry.setFallbackIndex(\n new FallbackIndex<K, V>(\n () => this.keys(),\n (key) => this.get(key),\n (record, query) => this.matchesIndexQuery(record, query)\n )\n );\n\n // Initialize adaptive indexing (Phase 8.02)\n this.queryTracker = new QueryPatternTracker();\n this.indexAdvisor = new IndexAdvisor(this.queryTracker);\n\n // Initialize auto-index manager if enabled\n if (options.adaptiveIndexing?.autoIndex?.enabled) {\n this.autoIndexManager = new AutoIndexManager(\n this.queryTracker,\n this.indexAdvisor,\n options.adaptiveIndexing.autoIndex\n );\n this.autoIndexManager.setMap(this);\n } else {\n this.autoIndexManager = null;\n }\n\n // Initialize default indexing strategy\n if (options.defaultIndexing && options.defaultIndexing !== 'none') {\n this.defaultIndexingStrategy = new DefaultIndexingStrategy<V>(options.defaultIndexing);\n } else {\n this.defaultIndexingStrategy = null;\n }\n }\n\n // ==================== Index Management ====================\n\n /**\n * Add a hash index on an attribute.\n * If lazyIndexBuilding is enabled, creates a LazyHashIndex instead.\n *\n * @param attribute - Attribute to index\n * @returns Created HashIndex (or LazyHashIndex)\n */\n addHashIndex<A>(attribute: Attribute<V, A>): HashIndex<K, V, A> | LazyHashIndex<K, V, A> {\n if (this.options.lazyIndexBuilding) {\n const index = new LazyHashIndex<K, V, A>(attribute, {\n onProgress: this.options.onIndexBuilding,\n });\n this.indexRegistry.addIndex(index);\n this.buildIndex(index);\n return index;\n }\n\n const index = new HashIndex<K, V, A>(attribute);\n this.indexRegistry.addIndex(index);\n this.buildIndex(index);\n return index;\n }\n\n /**\n * Add a navigable index on an attribute.\n * Navigable indexes support range queries (gt, gte, lt, lte, between).\n * If lazyIndexBuilding is enabled, creates a LazyNavigableIndex instead.\n *\n * @param attribute - Attribute to index\n * @param comparator - Optional custom comparator\n * @returns Created NavigableIndex (or LazyNavigableIndex)\n */\n addNavigableIndex<A extends string | number>(\n attribute: Attribute<V, A>,\n comparator?: (a: A, b: A) => number\n ): NavigableIndex<K, V, A> | LazyNavigableIndex<K, V, A> {\n if (this.options.lazyIndexBuilding) {\n const index = new LazyNavigableIndex<K, V, A>(attribute, comparator, {\n onProgress: this.options.onIndexBuilding,\n });\n this.indexRegistry.addIndex(index);\n this.buildIndex(index);\n return index;\n }\n\n const index = new NavigableIndex<K, V, A>(attribute, comparator);\n this.indexRegistry.addIndex(index);\n this.buildIndex(index);\n return index;\n }\n\n /**\n * Add an inverted index for full-text search on an attribute.\n * Inverted indexes support text search queries (contains, containsAll, containsAny).\n * If lazyIndexBuilding is enabled, creates a LazyInvertedIndex instead.\n *\n * @param attribute - Text attribute to index\n * @param pipeline - Optional custom tokenization pipeline\n * @returns Created InvertedIndex (or LazyInvertedIndex)\n *\n * @example\n * ```typescript\n * const nameAttr = simpleAttribute<Product, string>('name', p => p.name);\n * products.addInvertedIndex(nameAttr);\n *\n * // Search for products containing \"wireless\"\n * products.query({ type: 'contains', attribute: 'name', value: 'wireless' });\n * ```\n */\n addInvertedIndex<A extends string = string>(\n attribute: Attribute<V, A>,\n pipeline?: TokenizationPipeline\n ): InvertedIndex<K, V, A> | LazyInvertedIndex<K, V, A> {\n if (this.options.lazyIndexBuilding) {\n const index = new LazyInvertedIndex<K, V, A>(attribute, pipeline, {\n onProgress: this.options.onIndexBuilding,\n });\n this.indexRegistry.addIndex(index);\n this.buildIndex(index);\n return index;\n }\n\n const index = new InvertedIndex<K, V, A>(attribute, pipeline);\n this.indexRegistry.addIndex(index);\n this.buildIndex(index);\n return index;\n }\n\n /**\n * Add a custom index.\n *\n * @param index - Index to add\n */\n addIndex<A>(index: Index<K, V, A>): void {\n this.indexRegistry.addIndex(index);\n this.buildIndex(index);\n }\n\n /**\n * Remove an index.\n *\n * @param index - Index to remove\n * @returns true if index was found and removed\n */\n removeIndex<A>(index: Index<K, V, A>): boolean {\n return this.indexRegistry.removeIndex(index);\n }\n\n /**\n * Get all indexes.\n *\n * @returns Array of all indexes\n */\n getIndexes(): Index<K, V, unknown>[] {\n return this.indexRegistry.getAllIndexes();\n }\n\n /**\n * Check if an attribute is indexed.\n *\n * @param attributeName - Attribute name\n * @returns true if attribute has indexes\n */\n hasIndexOn(attributeName: string): boolean {\n return this.indexRegistry.hasIndex(attributeName);\n }\n\n /**\n * Build index from existing data.\n */\n private buildIndex<A>(index: Index<K, V, A>): void {\n for (const [key, value] of this.entries()) {\n index.add(key, value);\n }\n }\n\n // ==================== Query Execution ====================\n\n /**\n * Execute a query using indexes.\n * Returns lazy ResultSet of matching keys.\n *\n * Also tracks query patterns for adaptive indexing (Phase 8.02).\n *\n * @param query - Query to execute\n * @returns ResultSet of matching keys\n */\n query(query: Query): ResultSet<K> {\n const start = performance.now();\n const plan = this.queryOptimizer.optimize(query);\n const resultSet = this.executePlan(plan.root);\n\n // Materialize for statistics (Phase 8.02)\n const results = resultSet.toArray();\n const duration = performance.now() - start;\n\n // Track query pattern for adaptive indexing\n this.trackQueryPattern(query, duration, results.length, plan.usesIndexes);\n\n // Return a new SetResultSet with the materialized results\n return new SetResultSet(new Set(results), resultSet.getRetrievalCost());\n }\n\n /**\n * Execute a query and return materialized results.\n * Returns array of [key, value] pairs.\n *\n * @param query - Query to execute\n * @returns Array of [key, value] pairs\n */\n queryEntries(query: Query): [K, V][] {\n const keys = this.query(query);\n const results: [K, V][] = [];\n\n for (const key of keys) {\n const value = this.get(key);\n if (value !== undefined) {\n results.push([key, value]);\n }\n }\n\n return results;\n }\n\n /**\n * Execute a query and return matching values.\n *\n * @param query - Query to execute\n * @returns Array of matching values\n */\n queryValues(query: Query): V[] {\n const keys = this.query(query);\n const results: V[] = [];\n\n for (const key of keys) {\n const value = this.get(key);\n if (value !== undefined) {\n results.push(value);\n }\n }\n\n return results;\n }\n\n /**\n * Count matching records without materializing results.\n *\n * @param query - Query to execute\n * @returns Number of matching records\n */\n count(query: Query): number {\n const resultSet = this.query(query);\n return resultSet.size();\n }\n\n /**\n * Execute plan and return result set.\n */\n private executePlan(step: PlanStep): ResultSet<K> {\n switch (step.type) {\n case 'index-scan':\n return step.index.retrieve(step.query) as ResultSet<K>;\n\n case 'full-scan': {\n const fallback = this.indexRegistry.getFallbackIndex();\n if (fallback) {\n // FallbackIndex uses predicate internally - cast through unknown for compatibility\n return fallback.retrieve(step.predicate as unknown as IndexQuery<unknown>) as ResultSet<K>;\n }\n // Manual full scan fallback\n return this.fullScan(step.predicate as Query);\n }\n\n case 'intersection':\n return new IntersectionResultSet(\n step.steps.map((s) => this.executePlan(s))\n );\n\n case 'union':\n return new UnionResultSet(step.steps.map((s) => this.executePlan(s)));\n\n case 'filter':\n return new FilteringResultSet(\n this.executePlan(step.source),\n (key) => this.get(key),\n (record) => {\n if (record === undefined) return false;\n return this.matchesPredicate(record, step.predicate as Query);\n }\n );\n\n case 'not': {\n const matching = new Set(this.executePlan(step.source).toArray());\n const allKeysSet = new Set(this.keys());\n for (const key of matching) {\n allKeysSet.delete(key);\n }\n return new SetResultSet(allKeysSet, 100);\n }\n\n default:\n throw new Error(`Unknown plan step type: ${(step as PlanStep).type}`);\n }\n }\n\n /**\n * Perform full scan with predicate evaluation.\n */\n private fullScan(query: Query): ResultSet<K> {\n const result = new Set<K>();\n for (const [key, value] of this.entries()) {\n if (this.matchesPredicate(value, query)) {\n result.add(key);\n }\n }\n return new SetResultSet(result, Number.MAX_SAFE_INTEGER);\n }\n\n /**\n * Check if record matches predicate.\n * Converts Query to PredicateNode format for evaluation.\n */\n private matchesPredicate(record: V, query: Query): boolean {\n try {\n const predicate = this.queryToPredicate(query);\n return evaluatePredicate(predicate, record);\n } catch {\n return false;\n }\n }\n\n /**\n * Check if record matches IndexQuery (used by FallbackIndex).\n * This is a simplified matcher for full scan fallback.\n */\n private matchesIndexQuery(record: V, query: IndexQuery<unknown>): boolean {\n // Full scan matcher - evaluates the stored predicate\n // FallbackIndex passes the original query predicate\n if ('attribute' in (query as unknown as Record<string, unknown>)) {\n // This is a Query-like object passed through\n return this.matchesPredicate(record, query as unknown as Query);\n }\n // For simple IndexQuery without attribute context, always match\n return true;\n }\n\n /**\n * Convert Query to PredicateNode format.\n */\n private queryToPredicate(query: Query): PredicateNode {\n if ('type' in query) {\n switch (query.type) {\n case 'eq':\n return {\n op: 'eq',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'neq':\n return {\n op: 'neq',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'gt':\n return {\n op: 'gt',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'gte':\n return {\n op: 'gte',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'lt':\n return {\n op: 'lt',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'lte':\n return {\n op: 'lte',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'and':\n return {\n op: 'and',\n children: ((query as { children: Query[] }).children || []).map(\n (c) => this.queryToPredicate(c)\n ),\n };\n case 'or':\n return {\n op: 'or',\n children: ((query as { children: Query[] }).children || []).map(\n (c) => this.queryToPredicate(c)\n ),\n };\n case 'not':\n return {\n op: 'not',\n children: [\n this.queryToPredicate((query as { child: Query }).child),\n ],\n };\n case 'contains':\n return {\n op: 'contains',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'containsAll':\n return {\n op: 'containsAll',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { values: unknown[] }).values,\n };\n case 'containsAny':\n return {\n op: 'containsAny',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { values: unknown[] }).values,\n };\n default:\n return { op: 'eq', value: null };\n }\n }\n return { op: 'eq', value: null };\n }\n\n // ==================== Live Queries ====================\n\n /**\n * Subscribe to a live query.\n * Callback receives initial results and delta updates.\n *\n * @param query - Query to subscribe to\n * @param callback - Callback for query events\n * @returns Unsubscribe function\n */\n subscribeLiveQuery(\n query: Query,\n callback: LiveQueryCallback<K, V>\n ): () => void {\n return this.liveQueryManager.subscribe(query, callback);\n }\n\n /**\n * Get current live query results (snapshot).\n *\n * @param query - Query to execute\n * @returns Array of matching keys\n */\n getLiveQueryResults(query: Query): K[] {\n return this.liveQueryManager.getResults(query);\n }\n\n /**\n * Check if a query has active subscribers.\n *\n * @param query - Query to check\n * @returns true if query has subscribers\n */\n hasLiveQuerySubscribers(query: Query): boolean {\n return this.liveQueryManager.hasSubscribers(query);\n }\n\n // ==================== Override CRDT Operations ====================\n\n /**\n * Set a value (with index updates).\n */\n public set(key: K, value: V, ttlMs?: number): LWWRecord<V> {\n const oldValue = this.get(key);\n const result = super.set(key, value, ttlMs);\n\n // Apply default indexing on first record (Phase 8.02)\n if (this.defaultIndexingStrategy && !this.defaultIndexingStrategy.isApplied()) {\n this.defaultIndexingStrategy.applyToMap(this, value);\n }\n\n if (oldValue !== undefined) {\n this.indexRegistry.onRecordUpdated(key, oldValue, value);\n this.liveQueryManager.onRecordUpdated(key, oldValue, value);\n } else {\n this.indexRegistry.onRecordAdded(key, value);\n this.liveQueryManager.onRecordAdded(key, value);\n }\n\n return result;\n }\n\n /**\n * Remove a value (with index updates).\n */\n public remove(key: K): LWWRecord<V> {\n const oldValue = this.get(key);\n const result = super.remove(key);\n\n if (oldValue !== undefined) {\n this.indexRegistry.onRecordRemoved(key, oldValue);\n this.liveQueryManager.onRecordRemoved(key, oldValue);\n }\n\n return result;\n }\n\n /**\n * Merge a remote record (with index updates).\n */\n public merge(key: K, remote: LWWRecord<V>): boolean {\n const oldValue = this.get(key);\n const merged = super.merge(key, remote);\n\n if (merged) {\n const newValue = this.get(key);\n\n if (oldValue === undefined && newValue !== undefined) {\n // New record\n this.indexRegistry.onRecordAdded(key, newValue);\n this.liveQueryManager.onRecordAdded(key, newValue);\n } else if (oldValue !== undefined && newValue === undefined) {\n // Deleted (tombstone)\n this.indexRegistry.onRecordRemoved(key, oldValue);\n this.liveQueryManager.onRecordRemoved(key, oldValue);\n } else if (oldValue !== undefined && newValue !== undefined) {\n // Updated\n this.indexRegistry.onRecordUpdated(key, oldValue, newValue);\n this.liveQueryManager.onRecordUpdated(key, oldValue, newValue);\n }\n }\n\n return merged;\n }\n\n /**\n * Clear all data (and indexes).\n */\n public clear(): void {\n super.clear();\n this.indexRegistry.clear();\n this.liveQueryManager.clear();\n }\n\n // ==================== Iterator Methods ====================\n\n /**\n * Returns all keys (non-tombstoned, non-expired).\n */\n public keys(): Iterable<K> {\n const self = this;\n return {\n *[Symbol.iterator]() {\n for (const [key] of self.entries()) {\n yield key;\n }\n },\n };\n }\n\n // ==================== Stats ====================\n\n /**\n * Get index statistics.\n */\n getIndexStats(): Map<string, IndexStats> {\n const stats = new Map<string, IndexStats>();\n for (const index of this.indexRegistry.getAllIndexes()) {\n stats.set(index.attribute.name, index.getStats());\n }\n return stats;\n }\n\n /**\n * Get index registry statistics.\n */\n getIndexRegistryStats(): IndexRegistryStats {\n return this.indexRegistry.getStats();\n }\n\n /**\n * Get query optimizer for plan inspection.\n */\n getQueryOptimizer(): QueryOptimizer<K, V> {\n return this.queryOptimizer;\n }\n\n /**\n * Get live query manager for direct access.\n */\n getLiveQueryManager(): LiveQueryManager<K, V> {\n return this.liveQueryManager;\n }\n\n /**\n * Get standing query registry for direct access.\n */\n getStandingQueryRegistry(): StandingQueryRegistry<K, V> {\n return this.standingQueryRegistry;\n }\n\n /**\n * Explain query execution plan.\n *\n * @param query - Query to explain\n * @returns Query execution plan\n */\n explainQuery(query: Query): QueryPlan {\n return this.queryOptimizer.optimize(query);\n }\n\n // ==================== Adaptive Indexing (Phase 8.02) ====================\n\n /**\n * Register an attribute for auto-indexing.\n * Required before auto-index can create indexes on this attribute.\n *\n * @param attribute - The attribute to register\n * @param allowedIndexTypes - Optional list of allowed index types\n */\n registerAttribute<A>(\n attribute: Attribute<V, A>,\n allowedIndexTypes?: RecommendedIndexType[]\n ): void {\n if (this.autoIndexManager) {\n this.autoIndexManager.registerAttribute(attribute, allowedIndexTypes);\n }\n }\n\n /**\n * Unregister an attribute from auto-indexing.\n *\n * @param attributeName - Name of attribute to unregister\n */\n unregisterAttribute(attributeName: string): void {\n if (this.autoIndexManager) {\n this.autoIndexManager.unregisterAttribute(attributeName);\n }\n }\n\n /**\n * Get index suggestions based on query patterns.\n * Use this in production to get recommendations for manual index creation.\n *\n * @param options - Suggestion options\n * @returns Array of index suggestions sorted by priority\n *\n * @example\n * ```typescript\n * const suggestions = products.getIndexSuggestions();\n * // [{ attribute: 'category', indexType: 'hash', priority: 'high', ... }]\n * ```\n */\n getIndexSuggestions(options?: IndexSuggestionOptions): IndexSuggestion[] {\n return this.indexAdvisor.getSuggestions(options);\n }\n\n /**\n * Get query pattern statistics.\n * Useful for debugging and understanding query patterns.\n *\n * @returns Array of query statistics\n */\n getQueryStatistics(): QueryStatistics[] {\n return this.queryTracker.getStatistics();\n }\n\n /**\n * Reset query statistics.\n * Call this to clear accumulated query patterns.\n */\n resetQueryStatistics(): void {\n this.queryTracker.clear();\n if (this.autoIndexManager) {\n this.autoIndexManager.resetCounts();\n }\n }\n\n /**\n * Get query pattern tracker for advanced usage.\n */\n getQueryTracker(): QueryPatternTracker {\n return this.queryTracker;\n }\n\n /**\n * Get index advisor for advanced usage.\n */\n getIndexAdvisor(): IndexAdvisor {\n return this.indexAdvisor;\n }\n\n /**\n * Get auto-index manager (if enabled).\n */\n getAutoIndexManager(): AutoIndexManager<K, V> | null {\n return this.autoIndexManager;\n }\n\n /**\n * Check if auto-indexing is enabled.\n */\n isAutoIndexingEnabled(): boolean {\n return this.autoIndexManager !== null;\n }\n\n // ==================== Lazy Indexing (Phase 9.01) ====================\n\n /**\n * Check if lazy index building is enabled.\n */\n isLazyIndexingEnabled(): boolean {\n return this.options.lazyIndexBuilding === true;\n }\n\n /**\n * Force materialization of all lazy indexes.\n * Useful to pre-warm indexes before critical operations.\n *\n * @param progressCallback - Optional progress callback\n */\n materializeAllIndexes(progressCallback?: IndexBuildProgressCallback): void {\n const callback = progressCallback ?? this.options.onIndexBuilding;\n\n for (const index of this.indexRegistry.getAllIndexes()) {\n if ('isLazy' in index && (index as LazyIndex<K, V, unknown>).isLazy) {\n const lazyIndex = index as LazyIndex<K, V, unknown>;\n if (!lazyIndex.isBuilt) {\n lazyIndex.materialize(callback);\n }\n }\n }\n }\n\n /**\n * Get count of pending records across all lazy indexes.\n * Returns 0 if no lazy indexes or all are materialized.\n */\n getPendingIndexCount(): number {\n let total = 0;\n for (const index of this.indexRegistry.getAllIndexes()) {\n if ('isLazy' in index && (index as LazyIndex<K, V, unknown>).isLazy) {\n const lazyIndex = index as LazyIndex<K, V, unknown>;\n total += lazyIndex.pendingCount;\n }\n }\n return total;\n }\n\n /**\n * Check if any lazy indexes are still pending (not built).\n */\n hasUnbuiltIndexes(): boolean {\n for (const index of this.indexRegistry.getAllIndexes()) {\n if ('isLazy' in index && (index as LazyIndex<K, V, unknown>).isLazy) {\n const lazyIndex = index as LazyIndex<K, V, unknown>;\n if (!lazyIndex.isBuilt) {\n return true;\n }\n }\n }\n return false;\n }\n\n /**\n * Track query pattern for adaptive indexing.\n */\n private trackQueryPattern(\n query: Query,\n duration: number,\n resultSize: number,\n usedIndex: boolean\n ): void {\n // Only track if advisor is enabled (default: true)\n const advisorEnabled = this.options.adaptiveIndexing?.advisor?.enabled ??\n ADAPTIVE_INDEXING_DEFAULTS.advisor.enabled;\n\n if (!advisorEnabled && !this.autoIndexManager) {\n return;\n }\n\n // Extract attribute from query\n const attribute = this.extractAttribute(query);\n if (!attribute) return;\n\n // Extract query type\n const queryType = this.extractQueryType(query);\n if (!queryType) return;\n\n // Check if this attribute has an index\n const hasIndex = this.indexRegistry.hasIndex(attribute);\n\n // Record query in tracker\n this.queryTracker.recordQuery(\n attribute,\n queryType,\n duration,\n resultSize,\n hasIndex\n );\n\n // Notify auto-index manager if enabled\n if (this.autoIndexManager) {\n this.autoIndexManager.onQueryExecuted(attribute, queryType);\n }\n }\n\n /**\n * Extract attribute name from query.\n */\n private extractAttribute(query: Query): string | null {\n if (isSimpleQuery(query)) {\n return (query as SimpleQueryNode).attribute;\n }\n\n // For compound queries, extract from first child\n if (query.type === 'and' || query.type === 'or') {\n const children = (query as { children?: Query[] }).children;\n if (children && children.length > 0) {\n return this.extractAttribute(children[0]);\n }\n }\n\n if (query.type === 'not') {\n const child = (query as { child?: Query }).child;\n if (child) {\n return this.extractAttribute(child);\n }\n }\n\n return null;\n }\n\n /**\n * Extract query type from query.\n */\n private extractQueryType(query: Query): TrackedQueryType | null {\n if (isSimpleQuery(query)) {\n const type = query.type;\n // Only track types that can be indexed\n const indexableTypes: TrackedQueryType[] = [\n 'eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'between', 'in', 'has',\n 'contains', 'containsAll', 'containsAny',\n ];\n if (indexableTypes.includes(type as TrackedQueryType)) {\n return type as TrackedQueryType;\n }\n }\n\n // For compound queries, extract from first child\n if (query.type === 'and' || query.type === 'or') {\n const children = (query as { children?: Query[] }).children;\n if (children && children.length > 0) {\n return this.extractQueryType(children[0]);\n }\n }\n\n if (query.type === 'not') {\n const child = (query as { child?: Query }).child;\n if (child) {\n return this.extractQueryType(child);\n }\n }\n\n return null;\n }\n}\n","/**\n * English stopwords list (174 common words).\n * These words are filtered out during tokenization as they\n * don't contribute to search relevance.\n */\nexport const ENGLISH_STOPWORDS = new Set([\n // Articles\n 'a',\n 'an',\n 'the',\n\n // Pronouns\n 'i',\n 'me',\n 'my',\n 'myself',\n 'we',\n 'our',\n 'ours',\n 'ourselves',\n 'you',\n 'your',\n 'yours',\n 'yourself',\n 'yourselves',\n 'he',\n 'him',\n 'his',\n 'himself',\n 'she',\n 'her',\n 'hers',\n 'herself',\n 'it',\n 'its',\n 'itself',\n 'they',\n 'them',\n 'their',\n 'theirs',\n 'themselves',\n 'what',\n 'which',\n 'who',\n 'whom',\n 'this',\n 'that',\n 'these',\n 'those',\n\n // Auxiliary verbs\n 'am',\n 'is',\n 'are',\n 'was',\n 'were',\n 'be',\n 'been',\n 'being',\n 'have',\n 'has',\n 'had',\n 'having',\n 'do',\n 'does',\n 'did',\n 'doing',\n 'will',\n 'would',\n 'shall',\n 'should',\n 'can',\n 'could',\n 'may',\n 'might',\n 'must',\n 'ought',\n\n // Prepositions\n 'about',\n 'above',\n 'across',\n 'after',\n 'against',\n 'along',\n 'among',\n 'around',\n 'at',\n 'before',\n 'behind',\n 'below',\n 'beneath',\n 'beside',\n 'between',\n 'beyond',\n 'by',\n 'down',\n 'during',\n 'except',\n 'for',\n 'from',\n 'in',\n 'inside',\n 'into',\n 'near',\n 'of',\n 'off',\n 'on',\n 'onto',\n 'out',\n 'outside',\n 'over',\n 'past',\n 'since',\n 'through',\n 'throughout',\n 'to',\n 'toward',\n 'towards',\n 'under',\n 'underneath',\n 'until',\n 'up',\n 'upon',\n 'with',\n 'within',\n 'without',\n\n // Conjunctions\n 'and',\n 'but',\n 'or',\n 'nor',\n 'so',\n 'yet',\n 'both',\n 'either',\n 'neither',\n 'not',\n 'only',\n 'as',\n 'if',\n 'than',\n 'when',\n 'while',\n 'although',\n 'because',\n 'unless',\n 'whether',\n\n // Adverbs\n 'here',\n 'there',\n 'where',\n 'when',\n 'how',\n 'why',\n 'all',\n 'each',\n 'every',\n 'any',\n 'some',\n 'no',\n 'none',\n 'more',\n 'most',\n 'other',\n 'such',\n 'own',\n 'same',\n 'too',\n 'very',\n 'just',\n 'also',\n 'now',\n 'then',\n 'again',\n 'ever',\n 'once',\n\n // Misc\n 'few',\n 'many',\n 'much',\n 'several',\n 's',\n 't',\n 'd',\n 'll',\n 'm',\n 've',\n 're',\n]);\n\n","/**\n * Porter Stemming Algorithm\n *\n * Reduces English words to their stem (root form).\n * Based on the algorithm by Martin Porter (1980).\n *\n * @see https://tartarus.org/martin/PorterStemmer/\n *\n * @param word - Word to stem (should be lowercase)\n * @returns Stemmed word\n */\nexport function porterStem(word: string): string {\n if (!word || word.length < 3) {\n return word;\n }\n\n // Work with the word\n let stem = word;\n\n // Step 1a: Plurals\n if (stem.endsWith('sses')) {\n stem = stem.slice(0, -2);\n } else if (stem.endsWith('ies')) {\n stem = stem.slice(0, -2);\n } else if (!stem.endsWith('ss') && stem.endsWith('s')) {\n stem = stem.slice(0, -1);\n }\n\n // Step 1b: -ed and -ing\n const step1bRegex = /^(.+?)(eed|ed|ing)$/;\n const step1bMatch = stem.match(step1bRegex);\n\n if (step1bMatch) {\n const [, base, suffix] = step1bMatch;\n\n if (suffix === 'eed') {\n // Only remove if stem has measure > 0\n if (getMeasure(base) > 0) {\n stem = base + 'ee';\n }\n } else if (hasVowel(base)) {\n stem = base;\n\n // Additional processing after -ed/-ing removal\n if (stem.endsWith('at') || stem.endsWith('bl') || stem.endsWith('iz')) {\n stem = stem + 'e';\n } else if (endsWithDoubleConsonant(stem) && !stem.match(/[lsz]$/)) {\n stem = stem.slice(0, -1);\n } else if (getMeasure(stem) === 1 && endsWithCVC(stem)) {\n stem = stem + 'e';\n }\n }\n }\n\n // Step 1c: Terminal y\n if (stem.endsWith('y') && hasVowel(stem.slice(0, -1))) {\n stem = stem.slice(0, -1) + 'i';\n }\n\n // Step 2: Double suffixes\n const step2Suffixes: Array<[RegExp, string, number]> = [\n [/ational$/, 'ate', 0],\n [/tional$/, 'tion', 0],\n [/enci$/, 'ence', 0],\n [/anci$/, 'ance', 0],\n [/izer$/, 'ize', 0],\n [/abli$/, 'able', 0],\n [/alli$/, 'al', 0],\n [/entli$/, 'ent', 0],\n [/eli$/, 'e', 0],\n [/ousli$/, 'ous', 0],\n [/ization$/, 'ize', 0],\n [/ation$/, 'ate', 0],\n [/ator$/, 'ate', 0],\n [/alism$/, 'al', 0],\n [/iveness$/, 'ive', 0],\n [/fulness$/, 'ful', 0],\n [/ousness$/, 'ous', 0],\n [/aliti$/, 'al', 0],\n [/iviti$/, 'ive', 0],\n [/biliti$/, 'ble', 0],\n ];\n\n for (const [regex, replacement, minMeasure] of step2Suffixes) {\n if (regex.test(stem)) {\n const base = stem.replace(regex, '');\n if (getMeasure(base) > minMeasure) {\n stem = base + replacement;\n break;\n }\n }\n }\n\n // Step 3: -icate, -ful, -ness, etc.\n const step3Suffixes: Array<[RegExp, string, number]> = [\n [/icate$/, 'ic', 0],\n [/ative$/, '', 0],\n [/alize$/, 'al', 0],\n [/iciti$/, 'ic', 0],\n [/ical$/, 'ic', 0],\n [/ful$/, '', 0],\n [/ness$/, '', 0],\n ];\n\n for (const [regex, replacement, minMeasure] of step3Suffixes) {\n if (regex.test(stem)) {\n const base = stem.replace(regex, '');\n if (getMeasure(base) > minMeasure) {\n stem = base + replacement;\n break;\n }\n }\n }\n\n // Step 4: Final suffixes\n const step4Suffixes: Array<[RegExp, number]> = [\n [/al$/, 1],\n [/ance$/, 1],\n [/ence$/, 1],\n [/er$/, 1],\n [/ic$/, 1],\n [/able$/, 1],\n [/ible$/, 1],\n [/ant$/, 1],\n [/ement$/, 1],\n [/ment$/, 1],\n [/ent$/, 1],\n [/ion$/, 1],\n [/ou$/, 1],\n [/ism$/, 1],\n [/ate$/, 1],\n [/iti$/, 1],\n [/ous$/, 1],\n [/ive$/, 1],\n [/ize$/, 1],\n ];\n\n for (const [regex, minMeasure] of step4Suffixes) {\n if (regex.test(stem)) {\n const base = stem.replace(regex, '');\n if (getMeasure(base) > minMeasure) {\n // Special case for -ion (must be preceded by s or t)\n if (regex.source === 'ion$') {\n if (base.match(/[st]$/)) {\n stem = base;\n }\n } else {\n stem = base;\n }\n break;\n }\n }\n }\n\n // Step 5a: Final -e\n if (stem.endsWith('e')) {\n const base = stem.slice(0, -1);\n const measure = getMeasure(base);\n if (measure > 1 || (measure === 1 && !endsWithCVC(base))) {\n stem = base;\n }\n }\n\n // Step 5b: Double consonant\n if (getMeasure(stem) > 1 && endsWithDoubleConsonant(stem) && stem.endsWith('l')) {\n stem = stem.slice(0, -1);\n }\n\n return stem;\n}\n\n/**\n * Check if a character is a vowel.\n */\nfunction isVowel(char: string, prevChar?: string): boolean {\n if ('aeiou'.includes(char)) {\n return true;\n }\n // Y is a vowel if preceded by a consonant\n if (char === 'y' && prevChar && !'aeiou'.includes(prevChar)) {\n return true;\n }\n return false;\n}\n\n/**\n * Check if a string contains a vowel.\n */\nfunction hasVowel(str: string): boolean {\n for (let i = 0; i < str.length; i++) {\n if (isVowel(str[i], i > 0 ? str[i - 1] : undefined)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Calculate the \"measure\" of a word (number of VC sequences).\n * [C](VC){m}[V] where m is the measure.\n */\nfunction getMeasure(str: string): number {\n // Convert to CV pattern\n let pattern = '';\n for (let i = 0; i < str.length; i++) {\n pattern += isVowel(str[i], i > 0 ? str[i - 1] : undefined) ? 'v' : 'c';\n }\n\n // Count VC sequences\n const matches = pattern.match(/vc/g);\n return matches ? matches.length : 0;\n}\n\n/**\n * Check if word ends with a double consonant (e.g., -ll, -ss, -zz).\n */\nfunction endsWithDoubleConsonant(str: string): boolean {\n if (str.length < 2) return false;\n const last = str[str.length - 1];\n const secondLast = str[str.length - 2];\n return last === secondLast && !'aeiou'.includes(last);\n}\n\n/**\n * Check if word ends with CVC pattern where last C is not w, x, or y.\n */\nfunction endsWithCVC(str: string): boolean {\n if (str.length < 3) return false;\n\n const last3 = str.slice(-3);\n const c1 = !'aeiou'.includes(last3[0]);\n const v = isVowel(last3[1], last3[0]);\n const c2 = !'aeiou'.includes(last3[2]) && !'wxy'.includes(last3[2]);\n\n return c1 && v && c2;\n}\n\n","/**\n * FTS Tokenizer with Porter Stemming and Stopwords\n *\n * Provides text tokenization for BM25 full-text search.\n * Features:\n * - Unicode-aware word boundary detection\n * - English stopwords filtering (174 words)\n * - Porter stemming algorithm for word normalization\n * - Configurable min/max token length\n *\n * @module fts/Tokenizer\n */\n\nimport type { Tokenizer as ITokenizer } from '../query/tokenization/Tokenizer';\nimport type { TokenizerOptions } from './types';\nimport { ENGLISH_STOPWORDS } from '../query/tokenization/stopwords';\nimport { porterStem } from '../query/tokenization/porter-stemmer';\n\nexport { ENGLISH_STOPWORDS, porterStem };\n\n/**\n * FTS Tokenizer\n *\n * Splits text into searchable tokens with normalization.\n *\n * @example\n * ```typescript\n * const tokenizer = new BM25Tokenizer();\n * const tokens = tokenizer.tokenize('The quick brown foxes');\n * // ['quick', 'brown', 'fox']\n * ```\n */\nexport class BM25Tokenizer implements ITokenizer {\n private readonly options: Required<TokenizerOptions>;\n\n /**\n * Create a new BM25Tokenizer.\n *\n * @param options - Configuration options\n */\n constructor(options?: TokenizerOptions) {\n this.options = {\n lowercase: true,\n stopwords: ENGLISH_STOPWORDS,\n stemmer: porterStem,\n minLength: 2,\n maxLength: 40,\n ...options,\n };\n }\n\n /**\n * Tokenize text into an array of normalized tokens.\n *\n * @param text - Text to tokenize\n * @returns Array of tokens\n */\n tokenize(text: string): string[] {\n // Handle null/undefined/empty\n if (!text || typeof text !== 'string') {\n return [];\n }\n\n // 1. Lowercase if enabled\n let processed = this.options.lowercase ? text.toLowerCase() : text;\n\n // 2. Split on non-alphanumeric characters (Unicode-aware)\n // This regex matches Unicode letters and numbers\n const words = processed.split(/[^\\p{L}\\p{N}]+/u).filter((w) => w.length > 0);\n\n // 3. Filter and process each word\n const tokens: string[] = [];\n\n for (const word of words) {\n // Skip if too short before any processing\n if (word.length < this.options.minLength) {\n continue;\n }\n\n // Skip stopwords (before stemming)\n if (this.options.stopwords.has(word)) {\n continue;\n }\n\n // Apply stemmer\n const stemmed = this.options.stemmer(word);\n\n // Skip if too short after stemming\n if (stemmed.length < this.options.minLength) {\n continue;\n }\n\n // Skip if too long\n if (stemmed.length > this.options.maxLength) {\n continue;\n }\n\n tokens.push(stemmed);\n }\n\n return tokens;\n }\n}\n","/**\n * FTS Inverted Index\n *\n * Data structure for full-text search that maps terms to documents.\n * Supports efficient term lookup, document frequency calculation,\n * and IDF (Inverse Document Frequency) for BM25 scoring.\n *\n * @module fts/BM25InvertedIndex\n */\n\nimport type { TermInfo } from './types';\n\n/**\n * Inverted Index for Full-Text Search (BM25)\n *\n * Maps terms to the documents containing them, along with term frequency\n * information needed for BM25 scoring.\n *\n * @example\n * ```typescript\n * const index = new BM25InvertedIndex();\n * index.addDocument('doc1', ['hello', 'world']);\n * index.addDocument('doc2', ['hello', 'there']);\n *\n * const docs = index.getDocumentsForTerm('hello');\n * // [{ docId: 'doc1', termFrequency: 1 }, { docId: 'doc2', termFrequency: 1 }]\n * ```\n */\nexport class BM25InvertedIndex {\n /** term → list of documents containing term */\n private index: Map<string, TermInfo[]>;\n\n /** document → total term count (for length normalization) */\n private docLengths: Map<string, number>;\n\n /** document → set of terms (for efficient removal) */\n private docTerms: Map<string, Set<string>>;\n\n /** Inverse Document Frequency cache */\n private idfCache: Map<string, number>;\n\n /** Total number of documents */\n private totalDocs: number;\n\n /** Average document length */\n private avgDocLength: number;\n\n constructor() {\n this.index = new Map();\n this.docLengths = new Map();\n this.docTerms = new Map();\n this.idfCache = new Map();\n this.totalDocs = 0;\n this.avgDocLength = 0;\n }\n\n /**\n * Add a document to the index.\n *\n * @param docId - Unique document identifier\n * @param tokens - Array of tokens (already tokenized/stemmed)\n */\n addDocument(docId: string, tokens: string[]): void {\n // Count term frequencies\n const termFreqs = new Map<string, number>();\n const uniqueTerms = new Set<string>();\n\n for (const token of tokens) {\n termFreqs.set(token, (termFreqs.get(token) || 0) + 1);\n uniqueTerms.add(token);\n }\n\n // Update inverted index\n for (const [term, freq] of termFreqs) {\n if (!this.index.has(term)) {\n this.index.set(term, []);\n }\n this.index.get(term)!.push({\n docId,\n termFrequency: freq,\n });\n }\n\n // Store document info\n this.docLengths.set(docId, tokens.length);\n this.docTerms.set(docId, uniqueTerms);\n\n // Update stats\n this.totalDocs++;\n this.updateAvgDocLength();\n\n // Invalidate IDF cache\n this.idfCache.clear();\n }\n\n /**\n * Remove a document from the index.\n *\n * @param docId - Document identifier to remove\n */\n removeDocument(docId: string): void {\n const terms = this.docTerms.get(docId);\n if (!terms) {\n return; // Document doesn't exist\n }\n\n // Remove from inverted index\n for (const term of terms) {\n const termInfos = this.index.get(term);\n if (termInfos) {\n const filtered = termInfos.filter((info) => info.docId !== docId);\n if (filtered.length === 0) {\n this.index.delete(term);\n } else {\n this.index.set(term, filtered);\n }\n }\n }\n\n // Remove document info\n this.docLengths.delete(docId);\n this.docTerms.delete(docId);\n\n // Update stats\n this.totalDocs--;\n this.updateAvgDocLength();\n\n // Invalidate IDF cache\n this.idfCache.clear();\n }\n\n /**\n * Get all documents containing a term.\n *\n * @param term - Term to look up\n * @returns Array of TermInfo objects\n */\n getDocumentsForTerm(term: string): TermInfo[] {\n return this.index.get(term) || [];\n }\n\n /**\n * Calculate IDF (Inverse Document Frequency) for a term.\n *\n * Uses BM25 IDF formula:\n * IDF = log((N - df + 0.5) / (df + 0.5) + 1)\n *\n * Where:\n * - N = total documents\n * - df = document frequency (docs containing term)\n *\n * @param term - Term to calculate IDF for\n * @returns IDF value (0 if term doesn't exist)\n */\n getIDF(term: string): number {\n // Check cache first\n if (this.idfCache.has(term)) {\n return this.idfCache.get(term)!;\n }\n\n const termInfos = this.index.get(term);\n if (!termInfos || termInfos.length === 0) {\n return 0;\n }\n\n const docFreq = termInfos.length;\n\n // BM25 IDF formula\n const idf = Math.log((this.totalDocs - docFreq + 0.5) / (docFreq + 0.5) + 1);\n\n // Cache the result\n this.idfCache.set(term, idf);\n\n return idf;\n }\n\n /**\n * Get the length of a document (number of tokens).\n *\n * @param docId - Document identifier\n * @returns Document length (0 if not found)\n */\n getDocLength(docId: string): number {\n return this.docLengths.get(docId) || 0;\n }\n\n /**\n * Get the average document length.\n *\n * @returns Average length across all documents\n */\n getAvgDocLength(): number {\n return this.avgDocLength;\n }\n\n /**\n * Get the total number of documents in the index.\n *\n * @returns Total document count\n */\n getTotalDocs(): number {\n return this.totalDocs;\n }\n\n /**\n * Get iterator for document lengths (useful for serialization).\n *\n * @returns Iterator of [docId, length] pairs\n */\n getDocLengths(): IterableIterator<[string, number]> {\n return this.docLengths.entries();\n }\n\n /**\n * Get the number of documents in the index (alias for getTotalDocs).\n *\n * @returns Number of indexed documents\n */\n getSize(): number {\n return this.totalDocs;\n }\n\n /**\n * Clear all data from the index.\n */\n clear(): void {\n this.index.clear();\n this.docLengths.clear();\n this.docTerms.clear();\n this.idfCache.clear();\n this.totalDocs = 0;\n this.avgDocLength = 0;\n }\n\n /**\n * Check if a document exists in the index.\n *\n * @param docId - Document identifier\n * @returns True if document exists\n */\n hasDocument(docId: string): boolean {\n return this.docTerms.has(docId);\n }\n\n /**\n * Get all unique terms in the index.\n *\n * @returns Iterator of all terms\n */\n getTerms(): IterableIterator<string> {\n return this.index.keys();\n }\n\n /**\n * Get the number of unique terms in the index.\n *\n * @returns Number of unique terms\n */\n getTermCount(): number {\n return this.index.size;\n }\n\n /**\n * Update the average document length after add/remove.\n */\n private updateAvgDocLength(): void {\n if (this.totalDocs === 0) {\n this.avgDocLength = 0;\n return;\n }\n\n let sum = 0;\n for (const length of this.docLengths.values()) {\n sum += length;\n }\n this.avgDocLength = sum / this.totalDocs;\n }\n}\n","/**\n * BM25 Scorer\n *\n * Implements the Okapi BM25 ranking algorithm for full-text search.\n * BM25 is a probabilistic relevance ranking function used to estimate\n * the relevance of documents to a given search query.\n *\n * @see https://en.wikipedia.org/wiki/Okapi_BM25\n * @module fts/BM25Scorer\n */\n\nimport type { BM25Options, ScoredDocument } from './types';\nimport type { BM25InvertedIndex } from './BM25InvertedIndex';\n\n/**\n * BM25 Scorer for relevance ranking\n *\n * The BM25 formula:\n * score(D,Q) = Σ IDF(qi) × (f(qi,D) × (k1 + 1)) / (f(qi,D) + k1 × (1 - b + b × |D| / avgdl))\n *\n * Where:\n * - D = document\n * - Q = query\n * - qi = query term i\n * - f(qi,D) = term frequency of qi in D\n * - |D| = length of D (number of terms)\n * - avgdl = average document length\n * - k1 = term frequency saturation parameter (default: 1.2)\n * - b = document length normalization parameter (default: 0.75)\n *\n * @example\n * ```typescript\n * const index = new BM25InvertedIndex();\n * index.addDocument('doc1', ['hello', 'world']);\n * index.addDocument('doc2', ['hello', 'there']);\n *\n * const scorer = new BM25Scorer();\n * const results = scorer.score(['hello'], index);\n * // [{ docId: 'doc1', score: 0.28, matchedTerms: ['hello'] }, ...]\n * ```\n */\nexport class BM25Scorer {\n /**\n * Term frequency saturation parameter.\n * Higher values give more weight to repeated terms.\n * Typical range: 1.2 - 2.0\n */\n private readonly k1: number;\n\n /**\n * Document length normalization parameter.\n * 0 = no length normalization\n * 1 = full length normalization\n * Typical value: 0.75\n */\n private readonly b: number;\n\n /**\n * Create a new BM25 scorer.\n *\n * @param options - BM25 configuration options\n */\n constructor(options?: BM25Options) {\n this.k1 = options?.k1 ?? 1.2;\n this.b = options?.b ?? 0.75;\n }\n\n /**\n * Score documents against a query.\n *\n * @param queryTerms - Array of query terms (already tokenized/stemmed)\n * @param index - The inverted index to search\n * @returns Array of scored documents, sorted by relevance (descending)\n */\n score(queryTerms: string[], index: BM25InvertedIndex): ScoredDocument[] {\n if (queryTerms.length === 0 || index.getTotalDocs() === 0) {\n return [];\n }\n\n const avgDocLength = index.getAvgDocLength();\n\n // Map to accumulate scores per document\n const docScores = new Map<string, { score: number; terms: Set<string> }>();\n\n // Process each query term\n for (const term of queryTerms) {\n const idf = index.getIDF(term);\n if (idf === 0) {\n continue; // Term not in index\n }\n\n const termInfos = index.getDocumentsForTerm(term);\n\n for (const { docId, termFrequency } of termInfos) {\n const docLength = index.getDocLength(docId);\n\n // BM25 term score calculation\n const numerator = termFrequency * (this.k1 + 1);\n const denominator = termFrequency + this.k1 * (1 - this.b + this.b * (docLength / avgDocLength));\n const termScore = idf * (numerator / denominator);\n\n // Accumulate score for this document\n const current = docScores.get(docId) || { score: 0, terms: new Set() };\n current.score += termScore;\n current.terms.add(term);\n docScores.set(docId, current);\n }\n }\n\n // Convert to array and sort by score (descending)\n const results: ScoredDocument[] = [];\n for (const [docId, { score, terms }] of docScores) {\n results.push({\n docId,\n score,\n matchedTerms: Array.from(terms),\n });\n }\n\n results.sort((a, b) => b.score - a.score);\n\n return results;\n }\n\n /**\n * Score a single document against query terms.\n * Uses pre-computed IDF from index but calculates TF locally.\n *\n * Complexity: O(Q × D) where Q = query terms, D = document tokens\n *\n * @param queryTerms - Tokenized query terms\n * @param docTokens - Tokenized document terms\n * @param index - Inverted index for IDF and avgDocLength\n * @returns BM25 score (0 if no matching terms)\n */\n scoreSingleDocument(\n queryTerms: string[],\n docTokens: string[],\n index: BM25InvertedIndex\n ): number {\n if (queryTerms.length === 0 || docTokens.length === 0) {\n return 0;\n }\n\n const avgDocLength = index.getAvgDocLength();\n const docLength = docTokens.length;\n\n if (avgDocLength === 0) {\n return 0;\n }\n\n // Build term frequency map for document\n const termFreqs = new Map<string, number>();\n for (const token of docTokens) {\n termFreqs.set(token, (termFreqs.get(token) || 0) + 1);\n }\n\n let score = 0;\n\n for (const term of queryTerms) {\n const tf = termFreqs.get(term) || 0;\n if (tf === 0) {\n continue;\n }\n\n // Get IDF from index (uses cached value)\n const idf = index.getIDF(term);\n if (idf <= 0) {\n continue;\n }\n\n // BM25 term score calculation\n const numerator = tf * (this.k1 + 1);\n const denominator = tf + this.k1 * (1 - this.b + this.b * (docLength / avgDocLength));\n const termScore = idf * (numerator / denominator);\n\n score += termScore;\n }\n\n return score;\n }\n\n /**\n * Get the k1 parameter value.\n */\n getK1(): number {\n return this.k1;\n }\n\n /**\n * Get the b parameter value.\n */\n getB(): number {\n return this.b;\n }\n}\n","import { BM25InvertedIndex } from './BM25InvertedIndex';\nimport type { SerializedIndex, TermInfo } from './types';\n\n/**\n * Serializer for BM25InvertedIndex\n *\n * Handles serialization/deserialization of the inverted index for persistence.\n * Matches the structure defined in PHASE_11_IMPLEMENTATION_NOTES.\n */\nexport class IndexSerializer {\n /**\n * Serialize inverted index to a JSON-serializable object.\n * Note: In a real app, you might want to encoding this to binary (msgpack) later.\n */\n serialize(index: BM25InvertedIndex): SerializedIndex {\n const data: SerializedIndex = {\n version: 1,\n metadata: {\n totalDocs: index.getTotalDocs(),\n avgDocLength: index.getAvgDocLength(),\n createdAt: Date.now(),\n lastModified: Date.now(),\n },\n terms: this.serializeTerms(index),\n docLengths: this.serializeDocLengths(index),\n };\n\n return data;\n }\n\n /**\n * Deserialize from object into a new BM25InvertedIndex.\n */\n deserialize(data: SerializedIndex): BM25InvertedIndex {\n // Validate version\n if (data.version !== 1) {\n throw new Error(`Unsupported index version: ${data.version}`);\n }\n\n const index = new BM25InvertedIndex();\n this.loadIntoIndex(index, data);\n\n return index;\n }\n\n private serializeTerms(index: BM25InvertedIndex): SerializedIndex['terms'] {\n const terms: SerializedIndex['terms'] = [];\n const indexMap = (index as any).index as Map<string, TermInfo[]>; // Access private map\n\n // We need access to internal map.\n // Since we can't easily access private 'index' property without 'any' cast or getter,\n // we rely on iteration if available, or 'any' cast for this system component.\n // The public API getTerms() only returns keys.\n\n for (const term of index.getTerms()) {\n const termInfos = index.getDocumentsForTerm(term);\n terms.push({\n term,\n idf: index.getIDF(term),\n postings: termInfos.map((info) => ({\n docId: info.docId,\n termFrequency: info.termFrequency,\n positions: info.fieldPositions,\n })),\n });\n }\n\n return terms;\n }\n\n private serializeDocLengths(index: BM25InvertedIndex): Record<string, number> {\n const lengths: Record<string, number> = {};\n for (const [docId, length] of index.getDocLengths()) {\n lengths[docId] = length;\n }\n return lengths;\n }\n\n private loadIntoIndex(index: BM25InvertedIndex, data: SerializedIndex): void {\n // Restore metadata\n // We need to set private properties. \n // We'll use a helper method on Index or 'any' cast for this serializer friend class.\n const idx = index as any;\n \n idx.totalDocs = data.metadata.totalDocs;\n idx.avgDocLength = data.metadata.avgDocLength;\n \n // Restore doc lengths\n idx.docLengths = new Map(Object.entries(data.docLengths));\n \n // Restore terms\n for (const { term, idf, postings } of data.terms) {\n const termInfos: TermInfo[] = postings.map((p) => ({\n docId: p.docId,\n termFrequency: p.termFrequency,\n fieldPositions: p.positions,\n }));\n \n idx.index.set(term, termInfos);\n idx.idfCache.set(term, idf);\n \n // We also need to restore docTerms for efficient removal\n // This is expensive to rebuild from inverted index (O(Terms * Docs)).\n // But essential for updates.\n for (const info of termInfos) {\n if (!idx.docTerms.has(info.docId)) {\n idx.docTerms.set(info.docId, new Set());\n }\n idx.docTerms.get(info.docId).add(term);\n }\n }\n }\n}\n\n","/**\n * Full-Text Index\n *\n * High-level integration class that combines Tokenizer, InvertedIndex,\n * and BM25Scorer for complete full-text search functionality.\n * Designed to integrate with TopGun's CRDT maps.\n *\n * @module fts/FullTextIndex\n */\n\nimport type {\n FullTextIndexConfig,\n SearchOptions,\n ScoredDocument,\n TokenizerOptions,\n BM25Options,\n SearchResult,\n SerializedIndex,\n} from './types';\nimport { BM25Tokenizer } from './Tokenizer';\nimport { BM25InvertedIndex } from './BM25InvertedIndex';\nimport { BM25Scorer } from './BM25Scorer';\nimport { IndexSerializer } from './IndexSerializer';\n\n/**\n * Full-Text Index for TopGun\n *\n * Provides BM25-based full-text search across document fields.\n * Supports incremental updates (add/update/remove) for real-time sync.\n *\n * @example\n * ```typescript\n * const index = new FullTextIndex({\n * fields: ['title', 'body'],\n * tokenizer: { minLength: 2 },\n * bm25: { k1: 1.2, b: 0.75 }\n * });\n *\n * index.onSet('doc1', { title: 'Hello World', body: 'Test content' });\n * const results = index.search('hello');\n * // [{ docId: 'doc1', score: 0.5, matchedTerms: ['hello'] }]\n * ```\n */\nexport class FullTextIndex {\n /** Fields to index from documents */\n private readonly fields: string[];\n\n /** Tokenizer for text processing */\n private readonly tokenizer: BM25Tokenizer;\n\n /** BM25 scorer for relevance ranking */\n private readonly scorer: BM25Scorer;\n\n /** Per-field inverted indexes for field boosting */\n private readonly fieldIndexes: Map<string, BM25InvertedIndex>;\n\n /** Combined index for all fields */\n private combinedIndex: BM25InvertedIndex;\n\n /** Track indexed documents */\n private readonly indexedDocs: Set<string>;\n\n /** Serializer for persistence */\n private readonly serializer: IndexSerializer;\n\n /**\n * Cache of document tokens for fast single-document scoring.\n * Maps docId → tokenized terms from all indexed fields.\n */\n private readonly documentTokensCache: Map<string, string[]>;\n\n /**\n * Create a new FullTextIndex.\n *\n * @param config - Index configuration\n */\n constructor(config: FullTextIndexConfig) {\n this.fields = config.fields;\n this.tokenizer = new BM25Tokenizer(config.tokenizer);\n this.scorer = new BM25Scorer(config.bm25);\n this.fieldIndexes = new Map();\n this.combinedIndex = new BM25InvertedIndex();\n this.indexedDocs = new Set();\n this.serializer = new IndexSerializer();\n this.documentTokensCache = new Map();\n\n // Create per-field indexes\n for (const field of this.fields) {\n this.fieldIndexes.set(field, new BM25InvertedIndex());\n }\n }\n\n /**\n * Index a document (add or update).\n * Called when a document is set in the CRDT map.\n *\n * @param docId - Document identifier\n * @param document - Document data containing fields to index\n */\n onSet(docId: string, document: Record<string, unknown> | null | undefined): void {\n // Handle null/undefined documents\n if (!document || typeof document !== 'object') {\n // Clear cache for null/undefined document\n this.documentTokensCache.delete(docId);\n return;\n }\n\n // If document already exists, remove it first\n if (this.indexedDocs.has(docId)) {\n this.removeFromIndexes(docId);\n }\n\n // Collect all tokens for combined index\n const allTokens: string[] = [];\n\n // Index each field\n for (const field of this.fields) {\n const value = document[field];\n\n // Only index string values\n if (typeof value !== 'string') {\n continue;\n }\n\n const tokens = this.tokenizer.tokenize(value);\n\n if (tokens.length > 0) {\n // Add to field-specific index\n const fieldIndex = this.fieldIndexes.get(field)!;\n fieldIndex.addDocument(docId, tokens);\n\n // Collect for combined index\n allTokens.push(...tokens);\n }\n }\n\n // Add to combined index if any tokens were found\n if (allTokens.length > 0) {\n this.combinedIndex.addDocument(docId, allTokens);\n this.indexedDocs.add(docId);\n // Cache tokens for scoreSingleDocument\n this.documentTokensCache.set(docId, allTokens);\n } else {\n // No tokens - clear cache entry\n this.documentTokensCache.delete(docId);\n }\n }\n\n /**\n * Remove a document from the index.\n * Called when a document is deleted from the CRDT map.\n *\n * @param docId - Document identifier to remove\n */\n onRemove(docId: string): void {\n if (!this.indexedDocs.has(docId)) {\n return;\n }\n\n this.removeFromIndexes(docId);\n this.indexedDocs.delete(docId);\n // Clear cache entry\n this.documentTokensCache.delete(docId);\n }\n\n /**\n * Search the index with a query.\n *\n * @param query - Search query text\n * @param options - Search options (limit, minScore, boost)\n * @returns Array of search results, sorted by relevance\n */\n search(query: string, options?: SearchOptions): SearchResult[] {\n // Tokenize query\n const queryTerms = this.tokenizer.tokenize(query);\n\n if (queryTerms.length === 0) {\n return [];\n }\n\n // Check if field boosting is requested\n const boost = options?.boost;\n\n let results: ScoredDocument[];\n\n if (boost && Object.keys(boost).length > 0) {\n // Search with field boosting\n results = this.searchWithBoost(queryTerms, boost);\n } else {\n // Search combined index\n results = this.scorer.score(queryTerms, this.combinedIndex);\n }\n\n // Apply minScore filter\n if (options?.minScore !== undefined) {\n results = results.filter((r) => r.score >= options.minScore!);\n }\n\n // Apply limit\n if (options?.limit !== undefined && options.limit > 0) {\n results = results.slice(0, options.limit);\n }\n\n // Map to SearchResult\n return results.map((r) => ({\n docId: r.docId,\n score: r.score,\n matchedTerms: r.matchedTerms,\n source: 'fulltext' as const,\n }));\n }\n\n /**\n * Serialize the index state.\n *\n * @returns Serialized index data\n */\n serialize(): SerializedIndex {\n // We only serialize the combined index for now as it's the primary one.\n // If field boosting is required after restore, we'd need to serialize field indexes too.\n // For MVP/Phase 11, combined index serialization covers the main use case.\n return this.serializer.serialize(this.combinedIndex);\n }\n\n /**\n * Load index from serialized state.\n *\n * @param data - Serialized index data\n */\n load(data: SerializedIndex): void {\n this.combinedIndex = this.serializer.deserialize(data);\n\n // Rebuild indexedDocs set\n this.indexedDocs.clear();\n // Use private docLengths to rebuild indexedDocs set efficiently\n // This assumes we added getDocLengths to BM25InvertedIndex\n for (const [docId] of this.combinedIndex.getDocLengths()) {\n this.indexedDocs.add(docId);\n }\n\n // Note: Field indexes are NOT restored from combined index.\n // They would need to be rebuilt from source documents or serialized separately.\n // This is a tradeoff: fast load vs field boosting availability immediately without source docs.\n this.fieldIndexes.clear();\n for (const field of this.fields) {\n this.fieldIndexes.set(field, new BM25InvertedIndex());\n }\n\n // Clear document tokens cache - tokens must be rebuilt from source documents\n // This is intentional: serialized index doesn't include raw tokens\n this.documentTokensCache.clear();\n }\n\n /**\n * Build the index from an array of entries.\n * Useful for initial bulk loading.\n *\n * @param entries - Array of [docId, document] tuples\n */\n buildFromEntries(entries: Array<[string, Record<string, unknown> | null]>): void {\n for (const [docId, document] of entries) {\n this.onSet(docId, document);\n }\n }\n\n /**\n * Clear all data from the index.\n */\n clear(): void {\n this.combinedIndex.clear();\n for (const fieldIndex of this.fieldIndexes.values()) {\n fieldIndex.clear();\n }\n this.indexedDocs.clear();\n this.documentTokensCache.clear();\n }\n\n /**\n * Get the number of indexed documents.\n *\n * @returns Number of documents in the index\n */\n getSize(): number {\n return this.indexedDocs.size;\n }\n\n /**\n * Tokenize a query string using the index's tokenizer.\n * Public method for external use (e.g., SearchCoordinator).\n *\n * @param query - Query text to tokenize\n * @returns Array of tokenized terms\n */\n tokenizeQuery(query: string): string[] {\n return this.tokenizer.tokenize(query);\n }\n\n /**\n * Score a single document against query terms.\n * O(Q × D) complexity where Q = query terms, D = document tokens.\n *\n * This method is optimized for checking if a single document\n * matches a query, avoiding full index scan.\n *\n * @param docId - Document ID to score\n * @param queryTerms - Pre-tokenized query terms\n * @param document - Optional document data (used if not in cache)\n * @returns SearchResult with score and matched terms, or null if no match\n */\n scoreSingleDocument(\n docId: string,\n queryTerms: string[],\n document?: Record<string, unknown>\n ): SearchResult | null {\n if (queryTerms.length === 0) {\n return null;\n }\n\n // Get tokens from cache or compute from document\n let docTokens = this.documentTokensCache.get(docId);\n\n if (!docTokens && document) {\n // Document not in cache - tokenize on the fly\n docTokens = this.tokenizeDocument(document);\n }\n\n if (!docTokens || docTokens.length === 0) {\n return null;\n }\n\n // Quick check: any query term matches document?\n const docTokenSet = new Set(docTokens);\n const matchedTerms = queryTerms.filter(term => docTokenSet.has(term));\n\n if (matchedTerms.length === 0) {\n return null;\n }\n\n // Calculate BM25 score\n const score = this.scorer.scoreSingleDocument(\n queryTerms,\n docTokens,\n this.combinedIndex\n );\n\n if (score <= 0) {\n return null;\n }\n\n return {\n docId,\n score,\n matchedTerms,\n source: 'fulltext' as const,\n };\n }\n\n /**\n * Tokenize all indexed fields of a document.\n * Internal helper for scoreSingleDocument when document not in cache.\n *\n * @param document - Document data\n * @returns Array of all tokens from indexed fields\n */\n private tokenizeDocument(document: Record<string, unknown>): string[] {\n const allTokens: string[] = [];\n\n for (const field of this.fields) {\n const value = document[field];\n if (typeof value === 'string') {\n const tokens = this.tokenizer.tokenize(value);\n allTokens.push(...tokens);\n }\n }\n\n return allTokens;\n }\n\n /**\n * Get the index name (for debugging/display).\n *\n * @returns Descriptive name including indexed fields\n */\n get name(): string {\n return `FullTextIndex(${this.fields.join(', ')})`;\n }\n\n /**\n * Remove document from all indexes (internal).\n */\n private removeFromIndexes(docId: string): void {\n this.combinedIndex.removeDocument(docId);\n for (const fieldIndex of this.fieldIndexes.values()) {\n fieldIndex.removeDocument(docId);\n }\n }\n\n /**\n * Search with field boosting.\n * Scores are computed per-field and combined with boost weights.\n */\n private searchWithBoost(\n queryTerms: string[],\n boost: Record<string, number>\n ): ScoredDocument[] {\n // Accumulate scores per document\n const docScores = new Map<string, { score: number; terms: Set<string> }>();\n\n for (const field of this.fields) {\n const fieldIndex = this.fieldIndexes.get(field)!;\n const boostWeight = boost[field] ?? 1.0;\n\n // Score for this field\n const fieldResults = this.scorer.score(queryTerms, fieldIndex);\n\n for (const result of fieldResults) {\n const current = docScores.get(result.docId) || {\n score: 0,\n terms: new Set(),\n };\n\n // Apply boost to field score\n current.score += result.score * boostWeight;\n\n // Collect matched terms\n for (const term of result.matchedTerms) {\n current.terms.add(term);\n }\n\n docScores.set(result.docId, current);\n }\n }\n\n // Convert to array and sort\n const results: ScoredDocument[] = [];\n for (const [docId, { score, terms }] of docScores) {\n results.push({\n docId,\n score,\n matchedTerms: Array.from(terms),\n });\n }\n\n results.sort((a, b) => b.score - a.score);\n\n return results;\n }\n}\n","/**\n * IndexedORMap Implementation\n *\n * ORMap with index support for O(1) to O(log N) queries.\n * Wraps ORMap with indexing capabilities using the Wrapper Pattern.\n *\n * Note: ORMap stores multiple values per key (with tags).\n * Indexes track unique (key, tag) composite keys.\n *\n * Features:\n * - Hash and Navigable indexes for efficient queries\n * - Composite key indexing (key:tag)\n * - Automatic index updates on CRDT operations\n * - Lazy filtering for tombstones\n * - Adaptive indexing with query pattern tracking (Phase 8.02)\n *\n * @module IndexedORMap\n */\n\nimport { ORMap, ORMapRecord } from './ORMap';\nimport { HLC, Timestamp } from './HLC';\nimport { IndexRegistry, IndexRegistryStats } from './query/IndexRegistry';\nimport { QueryOptimizer } from './query/QueryOptimizer';\nimport type { Index, IndexStats, IndexQuery } from './query/indexes/types';\nimport { HashIndex } from './query/indexes/HashIndex';\nimport { NavigableIndex } from './query/indexes/NavigableIndex';\nimport { FallbackIndex } from './query/indexes/FallbackIndex';\nimport { InvertedIndex } from './query/indexes/InvertedIndex';\nimport { TokenizationPipeline } from './query/tokenization';\nimport { Attribute, simpleAttribute } from './query/Attribute';\nimport type { Query, QueryPlan, PlanStep, SimpleQueryNode } from './query/QueryTypes';\nimport { isSimpleQuery } from './query/QueryTypes';\nimport type { ResultSet } from './query/resultset/ResultSet';\nimport { SetResultSet } from './query/resultset/SetResultSet';\nimport { IntersectionResultSet } from './query/resultset/IntersectionResultSet';\nimport { UnionResultSet } from './query/resultset/UnionResultSet';\nimport { FilteringResultSet } from './query/resultset/FilteringResultSet';\nimport { evaluatePredicate, PredicateNode } from './predicate';\n\n// Full-Text Search imports (Phase 11)\nimport { FullTextIndex } from './fts/FullTextIndex';\nimport type { FullTextIndexConfig, SearchOptions as FTSSearchOptions, ScoredDocument } from './fts/types';\n\n// Adaptive indexing imports (Phase 8.02)\nimport {\n QueryPatternTracker,\n IndexAdvisor,\n AutoIndexManager,\n DefaultIndexingStrategy,\n} from './query/adaptive';\nimport type {\n IndexedMapOptions,\n IndexSuggestion,\n IndexSuggestionOptions,\n QueryStatistics,\n TrackedQueryType,\n RecommendedIndexType,\n} from './query/adaptive/types';\nimport { ADAPTIVE_INDEXING_DEFAULTS } from './query/adaptive/types';\n\n/**\n * Result of a query on IndexedORMap.\n */\nexport interface ORMapQueryResult<K, V> {\n key: K;\n tag: string;\n value: V;\n}\n\n/**\n * Result of a full-text search on IndexedORMap.\n * Includes BM25 relevance score for ranking.\n */\nexport interface ORMapSearchResult<K, V> extends ORMapQueryResult<K, V> {\n /** BM25 relevance score */\n score: number;\n /** Terms from the query that matched */\n matchedTerms: string[];\n}\n\n/**\n * ORMap with index support.\n *\n * Note: ORMap stores multiple values per key (with tags).\n * Indexes track unique (key, tag) pairs using composite keys.\n *\n * K = key type (extends string for compatibility)\n * V = value type\n */\nexport class IndexedORMap<K extends string, V> extends ORMap<K, V> {\n // Composite key = \"mapKey:tag\"\n private indexRegistry: IndexRegistry<string, V>;\n private queryOptimizer: QueryOptimizer<string, V>;\n\n // Adaptive indexing (Phase 8.02)\n private readonly queryTracker: QueryPatternTracker;\n private readonly indexAdvisor: IndexAdvisor;\n private readonly autoIndexManager: AutoIndexManager<string, V> | null;\n private readonly defaultIndexingStrategy: DefaultIndexingStrategy<V> | null;\n private readonly options: IndexedMapOptions;\n\n // Full-Text Search (Phase 11)\n private fullTextIndex: FullTextIndex | null = null;\n\n constructor(hlc: HLC, options: IndexedMapOptions = {}) {\n super(hlc);\n this.options = options;\n\n this.indexRegistry = new IndexRegistry();\n this.queryOptimizer = new QueryOptimizer({\n indexRegistry: this.indexRegistry,\n });\n\n // Set up fallback index for full scans\n this.indexRegistry.setFallbackIndex(\n new FallbackIndex<string, V>(\n () => this.getAllCompositeKeys(),\n (compositeKey) => this.getRecordByCompositeKey(compositeKey),\n (record, query) => this.matchesIndexQuery(record, query)\n )\n );\n\n // Initialize adaptive indexing (Phase 8.02)\n this.queryTracker = new QueryPatternTracker();\n this.indexAdvisor = new IndexAdvisor(this.queryTracker);\n\n // Initialize auto-index manager if enabled\n if (options.adaptiveIndexing?.autoIndex?.enabled) {\n this.autoIndexManager = new AutoIndexManager(\n this.queryTracker,\n this.indexAdvisor,\n options.adaptiveIndexing.autoIndex\n );\n this.autoIndexManager.setMap(this);\n } else {\n this.autoIndexManager = null;\n }\n\n // Initialize default indexing strategy\n if (options.defaultIndexing && options.defaultIndexing !== 'none') {\n this.defaultIndexingStrategy = new DefaultIndexingStrategy<V>(options.defaultIndexing);\n } else {\n this.defaultIndexingStrategy = null;\n }\n }\n\n // ==================== Index Management ====================\n\n /**\n * Add a hash index on an attribute.\n *\n * @param attribute - Attribute to index\n * @returns Created HashIndex\n */\n addHashIndex<A>(attribute: Attribute<V, A>): HashIndex<string, V, A> {\n const index = new HashIndex<string, V, A>(attribute);\n this.indexRegistry.addIndex(index);\n this.buildIndexFromExisting(index);\n return index;\n }\n\n /**\n * Add a navigable index on an attribute.\n * Navigable indexes support range queries (gt, gte, lt, lte, between).\n *\n * @param attribute - Attribute to index\n * @param comparator - Optional custom comparator\n * @returns Created NavigableIndex\n */\n addNavigableIndex<A extends string | number>(\n attribute: Attribute<V, A>,\n comparator?: (a: A, b: A) => number\n ): NavigableIndex<string, V, A> {\n const index = new NavigableIndex<string, V, A>(attribute, comparator);\n this.indexRegistry.addIndex(index);\n this.buildIndexFromExisting(index);\n return index;\n }\n\n /**\n * Add an inverted index for full-text search on an attribute.\n * Inverted indexes support text search queries (contains, containsAll, containsAny).\n *\n * @param attribute - Text attribute to index\n * @param pipeline - Optional custom tokenization pipeline\n * @returns Created InvertedIndex\n */\n addInvertedIndex<A extends string = string>(\n attribute: Attribute<V, A>,\n pipeline?: TokenizationPipeline\n ): InvertedIndex<string, V, A> {\n const index = new InvertedIndex<string, V, A>(attribute, pipeline);\n this.indexRegistry.addIndex(index);\n this.buildIndexFromExisting(index);\n return index;\n }\n\n /**\n * Add a custom index.\n *\n * @param index - Index to add\n */\n addIndex<A>(index: Index<string, V, A>): void {\n this.indexRegistry.addIndex(index);\n this.buildIndexFromExisting(index);\n }\n\n // ==================== Full-Text Search (Phase 11) ====================\n\n /**\n * Enable BM25-based full-text search on specified fields.\n * This creates a FullTextIndex for relevance-ranked search.\n *\n * Note: This is different from addInvertedIndex which provides\n * boolean matching (contains/containsAll/containsAny). This method\n * provides BM25 relevance scoring for true full-text search.\n *\n * @param config - Full-text index configuration\n * @returns The created FullTextIndex\n *\n * @example\n * ```typescript\n * const map = new IndexedORMap(hlc);\n * map.enableFullTextSearch({\n * fields: ['title', 'body'],\n * tokenizer: { minLength: 2 },\n * bm25: { k1: 1.2, b: 0.75 }\n * });\n *\n * map.add('doc1', { title: 'Hello World', body: 'Test content' });\n * const results = map.search('hello');\n * // [{ key: 'doc1', tag: '...', value: {...}, score: 0.5, matchedTerms: ['hello'] }]\n * ```\n */\n enableFullTextSearch(config: FullTextIndexConfig): FullTextIndex {\n // Create the full-text index\n this.fullTextIndex = new FullTextIndex(config);\n\n // Build from existing data\n const snapshot = this.getSnapshot();\n const entries: Array<[string, Record<string, unknown>]> = [];\n\n for (const [key, tagMap] of snapshot.items) {\n for (const [tag, record] of tagMap) {\n if (!snapshot.tombstones.has(tag)) {\n const compositeKey = this.createCompositeKey(key, tag);\n entries.push([compositeKey, record.value as Record<string, unknown>]);\n }\n }\n }\n\n this.fullTextIndex.buildFromEntries(entries);\n\n return this.fullTextIndex;\n }\n\n /**\n * Check if full-text search is enabled.\n *\n * @returns true if full-text search is enabled\n */\n isFullTextSearchEnabled(): boolean {\n return this.fullTextIndex !== null;\n }\n\n /**\n * Get the full-text index (if enabled).\n *\n * @returns The FullTextIndex or null\n */\n getFullTextIndex(): FullTextIndex | null {\n return this.fullTextIndex;\n }\n\n /**\n * Perform a BM25-ranked full-text search.\n * Results are sorted by relevance score (highest first).\n *\n * @param query - Search query text\n * @param options - Search options (limit, minScore, boost)\n * @returns Array of search results with scores, sorted by relevance\n *\n * @throws Error if full-text search is not enabled\n */\n search(query: string, options?: FTSSearchOptions): ORMapSearchResult<K, V>[] {\n if (!this.fullTextIndex) {\n throw new Error('Full-text search is not enabled. Call enableFullTextSearch() first.');\n }\n\n const scoredDocs = this.fullTextIndex.search(query, options);\n const results: ORMapSearchResult<K, V>[] = [];\n\n for (const { docId: compositeKey, score, matchedTerms } of scoredDocs) {\n const [key, tag] = this.parseCompositeKey(compositeKey);\n const records = this.getRecords(key as K);\n const record = records.find((r) => r.tag === tag);\n\n if (record) {\n results.push({\n key: key as K,\n tag,\n value: record.value,\n score,\n matchedTerms: matchedTerms ?? [],\n });\n }\n }\n\n return results;\n }\n\n /**\n * Disable full-text search and release the index.\n */\n disableFullTextSearch(): void {\n if (this.fullTextIndex) {\n this.fullTextIndex.clear();\n this.fullTextIndex = null;\n }\n }\n\n /**\n * Remove an index.\n *\n * @param index - Index to remove\n * @returns true if index was found and removed\n */\n removeIndex<A>(index: Index<string, V, A>): boolean {\n return this.indexRegistry.removeIndex(index);\n }\n\n /**\n * Get all indexes.\n *\n * @returns Array of all indexes\n */\n getIndexes(): Index<string, V, unknown>[] {\n return this.indexRegistry.getAllIndexes();\n }\n\n /**\n * Check if an attribute is indexed.\n *\n * @param attributeName - Attribute name\n * @returns true if attribute has indexes\n */\n hasIndexOn(attributeName: string): boolean {\n return this.indexRegistry.hasIndex(attributeName);\n }\n\n /**\n * Build index from existing data.\n */\n private buildIndexFromExisting<A>(index: Index<string, V, A>): void {\n const snapshot = this.getSnapshot();\n for (const [key, tagMap] of snapshot.items) {\n for (const [tag, record] of tagMap) {\n if (!snapshot.tombstones.has(tag)) {\n const compositeKey = this.createCompositeKey(key, tag);\n index.add(compositeKey, record.value);\n }\n }\n }\n }\n\n // ==================== Query Execution ====================\n\n /**\n * Execute a query across all records.\n * Returns array of matching results with key, tag, and value.\n *\n * Also tracks query patterns for adaptive indexing (Phase 8.02).\n *\n * @param query - Query to execute\n * @returns Array of query results\n */\n query(query: Query): ORMapQueryResult<K, V>[] {\n const start = performance.now();\n const plan = this.queryOptimizer.optimize(query);\n const resultSet = this.executePlan(plan.root);\n\n const results: ORMapQueryResult<K, V>[] = [];\n for (const compositeKey of resultSet) {\n const [key, tag] = this.parseCompositeKey(compositeKey);\n const records = this.getRecords(key as K);\n const record = records.find((r) => r.tag === tag);\n if (record) {\n results.push({ key: key as K, tag, value: record.value });\n }\n }\n\n // Track query pattern for adaptive indexing (Phase 8.02)\n const duration = performance.now() - start;\n this.trackQueryPattern(query, duration, results.length, plan.usesIndexes);\n\n return results;\n }\n\n /**\n * Execute a query and return matching values only.\n *\n * @param query - Query to execute\n * @returns Array of matching values\n */\n queryValues(query: Query): V[] {\n return this.query(query).map((r) => r.value);\n }\n\n /**\n * Count matching records without materializing results.\n *\n * @param query - Query to execute\n * @returns Number of matching records\n */\n count(query: Query): number {\n const plan = this.queryOptimizer.optimize(query);\n const resultSet = this.executePlan(plan.root);\n return resultSet.size();\n }\n\n /**\n * Execute plan and return result set.\n */\n private executePlan(step: PlanStep): ResultSet<string> {\n switch (step.type) {\n case 'index-scan':\n return step.index.retrieve(step.query) as ResultSet<string>;\n\n case 'full-scan': {\n const fallback = this.indexRegistry.getFallbackIndex();\n if (fallback) {\n // FallbackIndex uses predicate internally - cast through unknown for compatibility\n return fallback.retrieve(step.predicate as unknown as IndexQuery<unknown>) as ResultSet<string>;\n }\n return this.fullScan(step.predicate as Query);\n }\n\n case 'intersection':\n return new IntersectionResultSet(\n step.steps.map((s) => this.executePlan(s))\n );\n\n case 'union':\n return new UnionResultSet(step.steps.map((s) => this.executePlan(s)));\n\n case 'filter':\n return new FilteringResultSet(\n this.executePlan(step.source),\n (compositeKey) => this.getRecordByCompositeKey(compositeKey),\n (record) => {\n if (record === undefined) return false;\n return this.matchesPredicate(record, step.predicate as Query);\n }\n );\n\n case 'not': {\n const matching = new Set(this.executePlan(step.source).toArray());\n const allKeysSet = new Set(this.getAllCompositeKeys());\n for (const key of matching) {\n allKeysSet.delete(key);\n }\n return new SetResultSet(allKeysSet, 100);\n }\n\n default:\n throw new Error(`Unknown plan step type: ${(step as PlanStep).type}`);\n }\n }\n\n /**\n * Perform full scan with predicate evaluation.\n */\n private fullScan(query: Query): ResultSet<string> {\n const result = new Set<string>();\n const snapshot = this.getSnapshot();\n\n for (const [key, tagMap] of snapshot.items) {\n for (const [tag, record] of tagMap) {\n if (!snapshot.tombstones.has(tag)) {\n if (this.matchesPredicate(record.value, query)) {\n result.add(this.createCompositeKey(key, tag));\n }\n }\n }\n }\n\n return new SetResultSet(result, Number.MAX_SAFE_INTEGER);\n }\n\n // ==================== Override CRDT Operations ====================\n\n /**\n * Add a value (with index updates).\n */\n public add(key: K, value: V, ttlMs?: number): ORMapRecord<V> {\n const record = super.add(key, value, ttlMs);\n const compositeKey = this.createCompositeKey(key, record.tag);\n this.indexRegistry.onRecordAdded(compositeKey, value);\n\n // Update full-text index (Phase 11)\n if (this.fullTextIndex) {\n this.fullTextIndex.onSet(compositeKey, value as Record<string, unknown>);\n }\n\n return record;\n }\n\n /**\n * Remove a value (with index updates).\n */\n public remove(key: K, value: V): string[] {\n const records = this.getRecords(key);\n const matchingRecords = records.filter((r) => r.value === value);\n const result = super.remove(key, value);\n\n for (const record of matchingRecords) {\n const compositeKey = this.createCompositeKey(key, record.tag);\n this.indexRegistry.onRecordRemoved(compositeKey, record.value);\n\n // Update full-text index (Phase 11)\n if (this.fullTextIndex) {\n this.fullTextIndex.onRemove(compositeKey);\n }\n }\n\n return result;\n }\n\n /**\n * Apply a record from remote (with index updates).\n */\n public apply(key: K, record: ORMapRecord<V>): boolean {\n const applied = super.apply(key, record);\n if (applied) {\n const compositeKey = this.createCompositeKey(key, record.tag);\n this.indexRegistry.onRecordAdded(compositeKey, record.value);\n\n // Update full-text index (Phase 11)\n if (this.fullTextIndex) {\n this.fullTextIndex.onSet(compositeKey, record.value as Record<string, unknown>);\n }\n }\n return applied;\n }\n\n /**\n * Apply a tombstone (with index updates).\n */\n public applyTombstone(tag: string): void {\n // Find the record before tombstoning\n const snapshot = this.getSnapshot();\n let removedValue: V | undefined;\n let removedKey: K | undefined;\n\n for (const [key, tagMap] of snapshot.items) {\n const record = tagMap.get(tag);\n if (record) {\n removedValue = record.value;\n removedKey = key;\n break;\n }\n }\n\n super.applyTombstone(tag);\n\n if (removedValue !== undefined && removedKey !== undefined) {\n const compositeKey = this.createCompositeKey(removedKey, tag);\n this.indexRegistry.onRecordRemoved(compositeKey, removedValue);\n\n // Update full-text index (Phase 11)\n if (this.fullTextIndex) {\n this.fullTextIndex.onRemove(compositeKey);\n }\n }\n }\n\n /**\n * Clear all data (and indexes).\n */\n public clear(): void {\n super.clear();\n this.indexRegistry.clear();\n\n // Clear full-text index (Phase 11)\n if (this.fullTextIndex) {\n this.fullTextIndex.clear();\n }\n }\n\n // ==================== Helper Methods ====================\n\n /**\n * Create composite key from map key and tag.\n * Uses '||' as separator since HLC tags contain ':'\n */\n private createCompositeKey(key: K, tag: string): string {\n return `${key}||${tag}`;\n }\n\n /**\n * Parse composite key into [key, tag].\n * Expects '||' separator.\n */\n private parseCompositeKey(compositeKey: string): [string, string] {\n const separatorIndex = compositeKey.indexOf('||');\n if (separatorIndex === -1) {\n // Fallback for malformed keys\n return [compositeKey, ''];\n }\n return [\n compositeKey.substring(0, separatorIndex),\n compositeKey.substring(separatorIndex + 2),\n ];\n }\n\n /**\n * Get all composite keys from the map.\n */\n private getAllCompositeKeys(): Iterable<string> {\n const self = this;\n return {\n *[Symbol.iterator]() {\n const snapshot = self.getSnapshot();\n for (const [key, tagMap] of snapshot.items) {\n for (const [tag] of tagMap) {\n if (!snapshot.tombstones.has(tag)) {\n yield self.createCompositeKey(key, tag);\n }\n }\n }\n },\n };\n }\n\n /**\n * Get record by composite key.\n */\n private getRecordByCompositeKey(compositeKey: string): V | undefined {\n const [key, tag] = this.parseCompositeKey(compositeKey);\n const records = this.getRecords(key as K);\n const record = records.find((r) => r.tag === tag);\n return record?.value;\n }\n\n /**\n * Check if record matches predicate.\n */\n private matchesPredicate(record: V, query: Query): boolean {\n try {\n const predicate = this.queryToPredicate(query);\n return evaluatePredicate(predicate, record);\n } catch {\n return false;\n }\n }\n\n /**\n * Check if record matches IndexQuery (used by FallbackIndex).\n * This is a simplified matcher for full scan fallback.\n */\n private matchesIndexQuery(record: V, query: IndexQuery<unknown>): boolean {\n // Full scan matcher - evaluates the stored predicate\n // FallbackIndex passes the original query predicate\n if ('attribute' in (query as unknown as Record<string, unknown>)) {\n // This is a Query-like object passed through\n return this.matchesPredicate(record, query as unknown as Query);\n }\n // For simple IndexQuery without attribute context, always match\n return true;\n }\n\n /**\n * Convert Query to PredicateNode format.\n */\n private queryToPredicate(query: Query): PredicateNode {\n if ('type' in query) {\n switch (query.type) {\n case 'eq':\n return {\n op: 'eq',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'neq':\n return {\n op: 'neq',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'gt':\n return {\n op: 'gt',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'gte':\n return {\n op: 'gte',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'lt':\n return {\n op: 'lt',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'lte':\n return {\n op: 'lte',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'and':\n return {\n op: 'and',\n children: ((query as { children: Query[] }).children || []).map(\n (c) => this.queryToPredicate(c)\n ),\n };\n case 'or':\n return {\n op: 'or',\n children: ((query as { children: Query[] }).children || []).map(\n (c) => this.queryToPredicate(c)\n ),\n };\n case 'not':\n return {\n op: 'not',\n children: [\n this.queryToPredicate((query as { child: Query }).child),\n ],\n };\n case 'contains':\n return {\n op: 'contains',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { value: unknown }).value,\n };\n case 'containsAll':\n return {\n op: 'containsAll',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { values: unknown[] }).values,\n };\n case 'containsAny':\n return {\n op: 'containsAny',\n attribute: (query as { attribute: string }).attribute,\n value: (query as { values: unknown[] }).values,\n };\n default:\n return { op: 'eq', value: null };\n }\n }\n return { op: 'eq', value: null };\n }\n\n // ==================== Stats ====================\n\n /**\n * Get index statistics.\n */\n getIndexStats(): Map<string, IndexStats> {\n const stats = new Map<string, IndexStats>();\n for (const index of this.indexRegistry.getAllIndexes()) {\n stats.set(index.attribute.name, index.getStats());\n }\n return stats;\n }\n\n /**\n * Get index registry statistics.\n */\n getIndexRegistryStats(): IndexRegistryStats {\n return this.indexRegistry.getStats();\n }\n\n /**\n * Get query optimizer for plan inspection.\n */\n getQueryOptimizer(): QueryOptimizer<string, V> {\n return this.queryOptimizer;\n }\n\n /**\n * Explain query execution plan.\n *\n * @param query - Query to explain\n * @returns Query execution plan\n */\n explainQuery(query: Query): QueryPlan {\n return this.queryOptimizer.optimize(query);\n }\n\n // ==================== Adaptive Indexing (Phase 8.02) ====================\n\n /**\n * Register an attribute for auto-indexing.\n * Required before auto-index can create indexes on this attribute.\n *\n * @param attribute - The attribute to register\n * @param allowedIndexTypes - Optional list of allowed index types\n */\n registerAttribute<A>(\n attribute: Attribute<V, A>,\n allowedIndexTypes?: RecommendedIndexType[]\n ): void {\n if (this.autoIndexManager) {\n this.autoIndexManager.registerAttribute(attribute, allowedIndexTypes);\n }\n }\n\n /**\n * Unregister an attribute from auto-indexing.\n *\n * @param attributeName - Name of attribute to unregister\n */\n unregisterAttribute(attributeName: string): void {\n if (this.autoIndexManager) {\n this.autoIndexManager.unregisterAttribute(attributeName);\n }\n }\n\n /**\n * Get index suggestions based on query patterns.\n * Use this in production to get recommendations for manual index creation.\n *\n * @param options - Suggestion options\n * @returns Array of index suggestions sorted by priority\n */\n getIndexSuggestions(options?: IndexSuggestionOptions): IndexSuggestion[] {\n return this.indexAdvisor.getSuggestions(options);\n }\n\n /**\n * Get query pattern statistics.\n * Useful for debugging and understanding query patterns.\n *\n * @returns Array of query statistics\n */\n getQueryStatistics(): QueryStatistics[] {\n return this.queryTracker.getStatistics();\n }\n\n /**\n * Reset query statistics.\n * Call this to clear accumulated query patterns.\n */\n resetQueryStatistics(): void {\n this.queryTracker.clear();\n if (this.autoIndexManager) {\n this.autoIndexManager.resetCounts();\n }\n }\n\n /**\n * Get query pattern tracker for advanced usage.\n */\n getQueryTracker(): QueryPatternTracker {\n return this.queryTracker;\n }\n\n /**\n * Get index advisor for advanced usage.\n */\n getIndexAdvisor(): IndexAdvisor {\n return this.indexAdvisor;\n }\n\n /**\n * Get auto-index manager (if enabled).\n */\n getAutoIndexManager(): AutoIndexManager<string, V> | null {\n return this.autoIndexManager;\n }\n\n /**\n * Check if auto-indexing is enabled.\n */\n isAutoIndexingEnabled(): boolean {\n return this.autoIndexManager !== null;\n }\n\n /**\n * Track query pattern for adaptive indexing.\n */\n private trackQueryPattern(\n query: Query,\n duration: number,\n resultSize: number,\n usedIndex: boolean\n ): void {\n // Only track if advisor is enabled (default: true)\n const advisorEnabled = this.options.adaptiveIndexing?.advisor?.enabled ??\n ADAPTIVE_INDEXING_DEFAULTS.advisor.enabled;\n\n if (!advisorEnabled && !this.autoIndexManager) {\n return;\n }\n\n // Extract attribute from query\n const attribute = this.extractAttribute(query);\n if (!attribute) return;\n\n // Extract query type\n const queryType = this.extractQueryType(query);\n if (!queryType) return;\n\n // Check if this attribute has an index\n const hasIndex = this.indexRegistry.hasIndex(attribute);\n\n // Record query in tracker\n this.queryTracker.recordQuery(\n attribute,\n queryType,\n duration,\n resultSize,\n hasIndex\n );\n\n // Notify auto-index manager if enabled\n if (this.autoIndexManager) {\n this.autoIndexManager.onQueryExecuted(attribute, queryType);\n }\n }\n\n /**\n * Extract attribute name from query.\n */\n private extractAttribute(query: Query): string | null {\n if (isSimpleQuery(query)) {\n return (query as SimpleQueryNode).attribute;\n }\n\n // For compound queries, extract from first child\n if (query.type === 'and' || query.type === 'or') {\n const children = (query as { children?: Query[] }).children;\n if (children && children.length > 0) {\n return this.extractAttribute(children[0]);\n }\n }\n\n if (query.type === 'not') {\n const child = (query as { child?: Query }).child;\n if (child) {\n return this.extractAttribute(child);\n }\n }\n\n return null;\n }\n\n /**\n * Extract query type from query.\n */\n private extractQueryType(query: Query): TrackedQueryType | null {\n if (isSimpleQuery(query)) {\n const type = query.type;\n // Only track types that can be indexed\n const indexableTypes: TrackedQueryType[] = [\n 'eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'between', 'in', 'has',\n 'contains', 'containsAll', 'containsAny',\n ];\n if (indexableTypes.includes(type as TrackedQueryType)) {\n return type as TrackedQueryType;\n }\n }\n\n // For compound queries, extract from first child\n if (query.type === 'and' || query.type === 'or') {\n const children = (query as { children?: Query[] }).children;\n if (children && children.length > 0) {\n return this.extractQueryType(children[0]);\n }\n }\n\n if (query.type === 'not') {\n const child = (query as { child?: Query }).child;\n if (child) {\n return this.extractQueryType(child);\n }\n }\n\n return null;\n }\n}\n","/**\n * SearchCursor - Cursor-based pagination for distributed search\n *\n * Implements opaque cursor encoding for efficient deep pagination in distributed\n * search queries. Cursors encode the last seen position per node, enabling\n * each node to resume from where it left off.\n *\n * Problem solved: With offset-based pagination in a distributed system, each node\n * must return offset+limit results, causing O(N*offset) network overhead.\n * Cursor-based pagination reduces this to O(N*limit).\n *\n * Related: QueryCursor (query/QueryCursor.ts) provides similar functionality for\n * predicate-based queries. Both use shared base64url encoding utilities.\n *\n * Future consideration: A shared base class could extract common encode/decode\n * and timestamp validation logic, but the semantic differences (score vs sortValue,\n * fixed DESC vs configurable direction) make this a low-priority refactor.\n *\n * @module search/SearchCursor\n */\n\nimport { hashString } from '../utils/hash';\nimport { encodeBase64Url, decodeBase64Url } from '../utils/base64url';\n\n/**\n * Internal cursor data structure.\n * Encoded as base64url for wire transfer.\n */\nexport interface SearchCursorData {\n /** Last seen scores per node */\n nodeScores: Record<string, number>;\n /** Last seen keys per node (for tie-breaking when scores are equal) */\n nodeKeys: Record<string, string>;\n /** Hash of original query (for validation) */\n queryHash: number;\n /** Timestamp when cursor was created (for expiration) */\n timestamp: number;\n}\n\n/**\n * Result item with node tracking for cursor generation.\n */\nexport interface CursorableResult {\n key: string;\n score: number;\n nodeId: string;\n}\n\n/**\n * Default cursor expiration time (5 minutes).\n */\nexport const DEFAULT_CURSOR_MAX_AGE_MS = 5 * 60 * 1000;\n\n/**\n * SearchCursor provides cursor-based pagination for distributed search.\n *\n * @example\n * ```typescript\n * // Create cursor from search results\n * const cursor = SearchCursor.fromResults(results, 'machine learning');\n *\n * // Use cursor in next search request\n * const cursorData = SearchCursor.decode(cursor);\n * if (cursorData && SearchCursor.isValid(cursorData, 'machine learning')) {\n * // Each node filters: score < cursorData.nodeScores[nodeId]\n * // OR (score === nodeScores[nodeId] && key > nodeKeys[nodeId])\n * }\n * ```\n */\nexport class SearchCursor {\n /**\n * Encode cursor data to an opaque base64url string.\n *\n * @param data - Cursor data to encode\n * @returns Opaque cursor string\n */\n static encode(data: SearchCursorData): string {\n const json = JSON.stringify(data);\n // Use shared base64url utility (works in both Node.js and browsers)\n return encodeBase64Url(json);\n }\n\n /**\n * Decode cursor string back to data.\n *\n * @param cursor - Opaque cursor string\n * @returns Decoded cursor data, or null if invalid\n */\n static decode(cursor: string): SearchCursorData | null {\n try {\n // Use shared base64url utility (works in both Node.js and browsers)\n const json = decodeBase64Url(cursor);\n const data = JSON.parse(json);\n\n // Validate structure\n if (\n typeof data !== 'object' ||\n typeof data.nodeScores !== 'object' ||\n typeof data.nodeKeys !== 'object' ||\n typeof data.queryHash !== 'number' ||\n typeof data.timestamp !== 'number'\n ) {\n return null;\n }\n\n return data as SearchCursorData;\n } catch {\n return null;\n }\n }\n\n /**\n * Create a cursor from the last results of a search.\n *\n * The cursor captures the last seen position for each node that contributed\n * results, enabling efficient resumption in the next page request.\n *\n * @param results - Array of results with node tracking\n * @param query - Original query string (for validation)\n * @returns Encoded cursor string\n */\n static fromResults(results: CursorableResult[], query: string): string {\n const nodeScores: Record<string, number> = {};\n const nodeKeys: Record<string, string> = {};\n\n // Track last result per node\n // Results should be in score-descending order, so we just take the last per node\n for (const result of results) {\n // Always update to get the last (lowest score) for each node\n nodeScores[result.nodeId] = result.score;\n nodeKeys[result.nodeId] = result.key;\n }\n\n const data: SearchCursorData = {\n nodeScores,\n nodeKeys,\n queryHash: hashString(query),\n timestamp: Date.now(),\n };\n\n return this.encode(data);\n }\n\n /**\n * Create a cursor from the last result only.\n * Useful when you only have the final merged result.\n *\n * @param lastResult - The last result in the current page\n * @param query - Original query string\n * @returns Encoded cursor string\n */\n static fromLastResult(lastResult: CursorableResult, query: string): string {\n return this.fromResults([lastResult], query);\n }\n\n /**\n * Generate a hash for a query string.\n * Used to validate that cursor matches the current query.\n *\n * @param query - Query string to hash\n * @returns Numeric hash\n */\n static hashQuery(query: string): number {\n return hashString(query);\n }\n\n /**\n * Validate that a cursor is valid for the given query.\n *\n * Checks:\n * 1. Query hash matches (cursor was created for this query)\n * 2. Cursor is not expired\n *\n * @param cursor - Decoded cursor data\n * @param query - Query string to validate against\n * @param maxAgeMs - Maximum cursor age in milliseconds (default: 5 minutes)\n * @returns true if cursor is valid\n */\n static isValid(\n cursor: SearchCursorData,\n query: string,\n maxAgeMs: number = DEFAULT_CURSOR_MAX_AGE_MS\n ): boolean {\n // Check query hash matches\n if (cursor.queryHash !== hashString(query)) {\n return false;\n }\n\n // Check not expired\n if (Date.now() - cursor.timestamp > maxAgeMs) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Get the cursor position for a specific node.\n *\n * @param cursor - Decoded cursor data\n * @param nodeId - Node ID to get position for\n * @returns Position info or null if node not in cursor\n */\n static getNodePosition(\n cursor: SearchCursorData,\n nodeId: string\n ): { afterScore: number; afterKey: string } | null {\n if (!(nodeId in cursor.nodeScores)) {\n return null;\n }\n\n return {\n afterScore: cursor.nodeScores[nodeId],\n afterKey: cursor.nodeKeys[nodeId],\n };\n }\n\n /**\n * Check if a result should be included based on cursor position.\n *\n * Results are ordered by score descending, then key ascending for tie-breaking.\n * A result should be included if it comes AFTER the cursor position:\n * - score < cursorScore, OR\n * - score === cursorScore AND key > cursorKey\n *\n * @param result - Result to check\n * @param cursor - Decoded cursor data\n * @returns true if result should be included (is after cursor)\n */\n static isAfterCursor(\n result: CursorableResult,\n cursor: SearchCursorData\n ): boolean {\n const position = this.getNodePosition(cursor, result.nodeId);\n\n // If node not in cursor, include all results from that node\n if (!position) {\n return true;\n }\n\n // Score descending: lower score comes after\n if (result.score < position.afterScore) {\n return true;\n }\n\n // Tie-breaking: key ascending (higher key comes after)\n if (result.score === position.afterScore && result.key > position.afterKey) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Merge multiple cursors into one.\n * Useful when combining results from multiple sub-queries.\n *\n * @param cursors - Array of decoded cursor data\n * @param query - Original query string\n * @returns New merged cursor\n */\n static merge(cursors: SearchCursorData[], query: string): SearchCursorData {\n const nodeScores: Record<string, number> = {};\n const nodeKeys: Record<string, string> = {};\n\n for (const cursor of cursors) {\n for (const nodeId of Object.keys(cursor.nodeScores)) {\n const existingScore = nodeScores[nodeId];\n const newScore = cursor.nodeScores[nodeId];\n\n // Keep the lowest score (furthest position) for each node\n if (existingScore === undefined || newScore < existingScore) {\n nodeScores[nodeId] = newScore;\n nodeKeys[nodeId] = cursor.nodeKeys[nodeId];\n } else if (newScore === existingScore) {\n // Tie-break by highest key (furthest position)\n if (cursor.nodeKeys[nodeId] > nodeKeys[nodeId]) {\n nodeKeys[nodeId] = cursor.nodeKeys[nodeId];\n }\n }\n }\n }\n\n return {\n nodeScores,\n nodeKeys,\n queryHash: hashString(query),\n timestamp: Date.now(),\n };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACMO,IAAM,OAAN,MAAM,KAAI;AAAA,EAQf,YAAY,QAAgB;AAC1B,SAAK,SAAS;AACd,SAAK,aAAa;AAClB,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,IAAW,YAAoB;AAC7B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,MAAiB;AACtB,UAAM,aAAa,KAAK,IAAI;AAG5B,QAAI,aAAa,KAAK,YAAY;AAChC,WAAK,aAAa;AAClB,WAAK,cAAc;AAAA,IACrB,OAAO;AAEL,WAAK;AAAA,IACP;AAEA,WAAO;AAAA,MACL,QAAQ,KAAK;AAAA,MACb,SAAS,KAAK;AAAA,MACd,QAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,OAAO,QAAyB;AACrC,UAAM,aAAa,KAAK,IAAI;AAG5B,QAAI,OAAO,SAAS,aAAa,KAAI,WAAW;AAC9C,cAAQ,KAAK,qCAAqC,OAAO,MAAM,0BAA0B,UAAU,EAAE;AAAA,IAEvG;AAEA,UAAM,YAAY,KAAK,IAAI,KAAK,YAAY,YAAY,OAAO,MAAM;AAErE,QAAI,cAAc,KAAK,cAAc,cAAc,OAAO,QAAQ;AAEhE,WAAK,cAAc,KAAK,IAAI,KAAK,aAAa,OAAO,OAAO,IAAI;AAAA,IAClE,WAAW,cAAc,KAAK,YAAY;AAExC,WAAK;AAAA,IACP,WAAW,cAAc,OAAO,QAAQ;AAEtC,WAAK,cAAc,OAAO,UAAU;AAAA,IACtC,OAAO;AAEL,WAAK,cAAc;AAAA,IACrB;AAEA,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAc,QAAQ,GAAc,GAAsB;AACxD,QAAI,EAAE,WAAW,EAAE,QAAQ;AACzB,aAAO,EAAE,SAAS,EAAE;AAAA,IACtB;AACA,QAAI,EAAE,YAAY,EAAE,SAAS;AAC3B,aAAO,EAAE,UAAU,EAAE;AAAA,IACvB;AACA,WAAO,EAAE,OAAO,cAAc,EAAE,MAAM;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAc,SAAS,IAAuB;AAC5C,WAAO,GAAG,GAAG,MAAM,IAAI,GAAG,OAAO,IAAI,GAAG,MAAM;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAKA,OAAc,MAAM,KAAwB;AAC1C,UAAM,QAAQ,IAAI,MAAM,GAAG;AAC3B,QAAI,MAAM,WAAW,GAAG;AACtB,YAAM,IAAI,MAAM,6BAA6B,GAAG,EAAE;AAAA,IACpD;AACA,WAAO;AAAA,MACL,QAAQ,SAAS,MAAM,CAAC,GAAG,EAAE;AAAA,MAC7B,SAAS,SAAS,MAAM,CAAC,GAAG,EAAE;AAAA,MAC9B,QAAQ,MAAM,CAAC;AAAA,IACjB;AAAA,EACF;AACF;AAAA;AA7Ga,KAMa,YAAY;AAN/B,IAAM,MAAN;;;ACIP,IAAI,aAGO;AAEX,IAAI,sBAAsB;AAE1B,SAAS,gBAAsB;AAC7B,MAAI,oBAAqB;AACzB,wBAAsB;AAEtB,MAAI;AAEF,iBAAa,QAAQ,qBAAqB;AAAA,EAC5C,QAAQ;AAAA,EAER;AACF;AAOA,SAAS,UAAU,KAAqB;AACtC,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,YAAQ,IAAI,WAAW,CAAC;AACxB,WAAO,KAAK,KAAK,MAAM,QAAU;AAAA,EACnC;AACA,SAAO,SAAS;AAClB;AAWO,SAAS,WAAW,KAAqB;AAC9C,gBAAc;AAEd,MAAI,cAAc,WAAW,sBAAsB,GAAG;AACpD,WAAO,WAAW,WAAW,GAAG;AAAA,EAClC;AAEA,SAAO,UAAU,GAAG;AACtB;AAWO,SAAS,cAAc,QAA0B;AACtD,MAAI,SAAS;AACb,aAAW,KAAK,QAAQ;AACtB,aAAU,SAAS,IAAK;AAAA,EAC1B;AACA,SAAO,WAAW;AACpB;AAMO,SAAS,oBAA6B;AAC3C,gBAAc;AACd,SAAO,YAAY,sBAAsB,MAAM;AACjD;AAMO,SAAS,oBAA0B;AACxC,eAAa;AACb,wBAAsB;AACxB;AAMO,SAAS,kBAAwB;AACtC,eAAa;AACb,wBAAsB;AACxB;AASO,SAAS,WAAW,KAAsB;AAE/C,QAAM,OAAO,KAAK,UAAU,KAAK,CAAC,GAAG,UAAU;AAC7C,QAAI,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AAC/D,aAAO,OAAO,KAAK,KAAK,EACrB,KAAK,EACL,OAAO,CAAC,QAAiC,QAAQ;AAChD,eAAO,GAAG,IAAI,MAAM,GAAG;AACvB,eAAO;AAAA,MACT,GAAG,CAAC,CAAC;AAAA,IACT;AACA,WAAO;AAAA,EACT,CAAC;AAED,SAAO,WAAW,IAAI;AACxB;;;AC7GO,IAAM,aAAN,MAAiB;AAAA,EAItB,YAAY,UAAuC,oBAAI,IAAI,GAAG,QAAgB,GAAG;AAC/E,SAAK,QAAQ;AACb,SAAK,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC,EAAE;AAEpC,eAAW,CAAC,KAAK,MAAM,KAAK,SAAS;AACjC,WAAK,OAAO,KAAK,MAAM;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,OAAO,KAAa,QAAwB;AACjD,UAAM,WAAW,WAAW,GAAG,GAAG,IAAI,OAAO,UAAU,MAAM,IAAI,OAAO,UAAU,OAAO,IAAI,OAAO,UAAU,MAAM,EAAE;AAGtH,UAAM,WAAW,WAAW,GAAG,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAE7D,SAAK,WAAW,KAAK,MAAM,KAAK,UAAU,UAAU,CAAC;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,OAAO,KAAa;AACzB,UAAM,WAAW,WAAW,GAAG,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAC7D,SAAK,WAAW,KAAK,MAAM,KAAK,UAAU,CAAC;AAAA,EAC7C;AAAA,EAEQ,WAAW,MAAkB,KAAa,UAAkB,OAAuB;AAEzF,QAAI,SAAS,KAAK,OAAO;AACvB,UAAI,KAAK,SAAS;AAChB,aAAK,QAAQ,OAAO,GAAG;AAGvB,YAAIA,KAAI;AACR,mBAAW,OAAO,KAAK,QAAQ,OAAO,GAAG;AACvC,UAAAA,KAAKA,KAAI,MAAO;AAAA,QAClB;AACA,aAAK,OAAOA,OAAM;AAAA,MACpB;AACA,aAAO,KAAK;AAAA,IACd;AAGA,UAAM,aAAa,SAAS,KAAK;AACjC,QAAI,KAAK,YAAY,KAAK,SAAS,UAAU,GAAG;AAC9C,YAAM,YAAY,KAAK,WAAW,KAAK,SAAS,UAAU,GAAG,KAAK,UAAU,QAAQ,CAAC;AAAA,IAGvF;AAGA,QAAI,IAAI;AACR,QAAI,KAAK,UAAU;AACjB,iBAAW,SAAS,OAAO,OAAO,KAAK,QAAQ,GAAG;AAChD,YAAK,IAAI,MAAM,OAAQ;AAAA,MACzB;AAAA,IACF;AACA,SAAK,OAAO,MAAM;AAClB,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,WAAW,MAAkB,KAAa,UAAkB,UAAkB,OAAuB;AAE3G,QAAI,SAAS,KAAK,OAAO;AACvB,UAAI,CAAC,KAAK,QAAS,MAAK,UAAU,oBAAI,IAAI;AAC1C,WAAK,QAAQ,IAAI,KAAK,QAAQ;AAG9B,UAAIA,KAAI;AACR,iBAAW,OAAO,KAAK,QAAQ,OAAO,GAAG;AACvC,QAAAA,KAAKA,KAAI,MAAO;AAAA,MAClB;AACA,WAAK,OAAOA,OAAM;AAClB,aAAO,KAAK;AAAA,IACd;AAGA,UAAM,aAAa,SAAS,KAAK;AACjC,QAAI,CAAC,KAAK,SAAU,MAAK,WAAW,CAAC;AAErC,QAAI,CAAC,KAAK,SAAS,UAAU,GAAG;AAC9B,WAAK,SAAS,UAAU,IAAI,EAAE,MAAM,EAAE;AAAA,IACxC;AAEA,SAAK,WAAW,KAAK,SAAS,UAAU,GAAG,KAAK,UAAU,UAAU,QAAQ,CAAC;AAG7E,QAAI,IAAI;AACR,eAAW,SAAS,OAAO,OAAO,KAAK,QAAQ,GAAG;AAChD,UAAK,IAAI,MAAM,OAAQ;AAAA,IACzB;AACA,SAAK,OAAO,MAAM;AAClB,WAAO,KAAK;AAAA,EACd;AAAA,EAEO,cAAsB;AAC3B,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA,EAEO,QAAQ,MAAsC;AACnD,QAAI,UAAU,KAAK;AACnB,eAAW,QAAQ,MAAM;AACvB,UAAI,CAAC,QAAQ,YAAY,CAAC,QAAQ,SAAS,IAAI,GAAG;AAChD,eAAO;AAAA,MACT;AACA,gBAAU,QAAQ,SAAS,IAAI;AAAA,IACjC;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,WAAW,MAAsC;AACtD,UAAM,OAAO,KAAK,QAAQ,IAAI;AAC9B,QAAI,CAAC,QAAQ,CAAC,KAAK,SAAU,QAAO,CAAC;AAErC,UAAM,SAAiC,CAAC;AACxC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,QAAQ,GAAG;AACxD,aAAO,GAAG,IAAI,MAAM;AAAA,IACtB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,gBAAgB,MAAwB;AAC7C,UAAM,OAAO,KAAK,QAAQ,IAAI;AAC9B,QAAI,CAAC,QAAQ,CAAC,KAAK,QAAS,QAAO,CAAC;AACpC,WAAO,MAAM,KAAK,KAAK,QAAQ,KAAK,CAAC;AAAA,EACvC;AACF;;;AClJO,IAAM,SAAN,MAAmB;AAAA,EAMxB,YAAY,KAAU;AAHtB,SAAQ,YAA+B,CAAC;AAItC,SAAK,MAAM;AACX,SAAK,OAAO,oBAAI,IAAI;AACpB,SAAK,aAAa,IAAI,WAAW;AAAA,EACnC;AAAA,EAEO,SAAS,UAAkC;AAChD,SAAK,UAAU,KAAK,QAAQ;AAC5B,WAAO,MAAM;AACX,WAAK,YAAY,KAAK,UAAU,OAAO,QAAM,OAAO,QAAQ;AAAA,IAC9D;AAAA,EACF;AAAA,EAEQ,SAAe;AACrB,SAAK,UAAU,QAAQ,QAAM,GAAG,CAAC;AAAA,EACnC;AAAA,EAEO,gBAA4B;AACjC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAW,OAAe;AACxB,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,IAAI,KAAQ,OAAU,OAA8B;AACzD,UAAM,YAAY,KAAK,IAAI,IAAI;AAC/B,UAAM,SAAuB,EAAE,OAAO,UAAU;AAEhD,QAAI,UAAU,QAAW;AACvB,UAAI,OAAO,UAAU,YAAY,SAAS,KAAK,CAAC,OAAO,SAAS,KAAK,GAAG;AAGtE,cAAM,IAAI,MAAM,sCAAsC;AAAA,MACxD;AACA,aAAO,QAAQ;AAAA,IACjB;AAKA,SAAK,KAAK,IAAI,KAAK,MAAM;AACzB,SAAK,WAAW,OAAO,OAAO,GAAG,GAAG,MAAM;AAE1C,SAAK,OAAO;AACZ,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,IAAI,KAAuB;AAChC,UAAM,SAAS,KAAK,KAAK,IAAI,GAAG;AAChC,QAAI,CAAC,UAAU,OAAO,UAAU,MAAM;AACpC,aAAO;AAAA,IACT;AAGA,QAAI,OAAO,OAAO;AAChB,YAAM,MAAM,KAAK,IAAI;AACrB,UAAI,OAAO,UAAU,SAAS,OAAO,QAAQ,KAAK;AAChD,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,UAAU,KAAkC;AACjD,WAAO,KAAK,KAAK,IAAI,GAAG;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKO,OAAO,KAAsB;AAClC,UAAM,YAAY,KAAK,IAAI,IAAI;AAC/B,UAAM,YAA0B,EAAE,OAAO,MAAM,UAAU;AAEzD,SAAK,KAAK,IAAI,KAAK,SAAS;AAC5B,SAAK,WAAW,OAAO,OAAO,GAAG,GAAG,SAAS;AAE7C,SAAK,OAAO;AACZ,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,MAAM,KAAQ,cAAqC;AAExD,SAAK,IAAI,OAAO,aAAa,SAAS;AAEtC,UAAM,cAAc,KAAK,KAAK,IAAI,GAAG;AAQrC,QAAI,CAAC,eAAe,IAAI,QAAQ,aAAa,WAAW,YAAY,SAAS,IAAI,GAAG;AAClF,WAAK,KAAK,IAAI,KAAK,YAAY;AAC/B,WAAK,WAAW,OAAO,OAAO,GAAG,GAAG,YAAY;AAEhD,WAAK,OAAO;AACZ,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,MAAM,WAA2B;AACtC,UAAM,cAAmB,CAAC;AAE1B,eAAW,CAAC,KAAK,MAAM,KAAK,KAAK,KAAK,QAAQ,GAAG;AAE/C,UAAI,OAAO,UAAU,MAAM;AAGzB,YAAI,IAAI,QAAQ,OAAO,WAAW,SAAS,IAAI,GAAG;AAChD,eAAK,KAAK,OAAO,GAAG;AACpB,eAAK,WAAW,OAAO,OAAO,GAAG,CAAC;AAClC,sBAAY,KAAK,GAAG;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,YAAY,SAAS,GAAG;AAC1B,WAAK,OAAO;AAAA,IACd;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,QAAc;AACnB,SAAK,KAAK,MAAM;AAChB,SAAK,aAAa,IAAI,WAAW;AACjC,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,UAAoC;AACzC,UAAM,WAAW,KAAK,KAAK,QAAQ;AACnC,UAAM,MAAM,KAAK,IAAI;AAErB,WAAO;AAAA,MACL,CAAC,OAAO,QAAQ,IAAI;AAAE,eAAO;AAAA,MAAM;AAAA,MACnC,MAAM,MAAM;AACV,YAAI,SAAS,SAAS,KAAK;AAC3B,eAAO,CAAC,OAAO,MAAM;AACnB,gBAAM,CAAC,KAAK,MAAM,IAAI,OAAO;AAC7B,cAAI,OAAO,UAAU,MAAM;AAEzB,gBAAI,OAAO,SAAS,OAAO,UAAU,SAAS,OAAO,QAAQ,KAAK;AAC9D,uBAAS,SAAS,KAAK;AACvB;AAAA,YACJ;AACA,mBAAO,EAAE,OAAO,CAAC,KAAK,OAAO,KAAK,GAAG,MAAM,MAAM;AAAA,UACnD;AACA,mBAAS,SAAS,KAAK;AAAA,QACzB;AACA,eAAO,EAAE,OAAO,QAAW,MAAM,KAAK;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKO,UAA+B;AACpC,WAAO,KAAK,KAAK,KAAK;AAAA,EACxB;AACF;;;ACnNO,SAAS,kBAAkB,IAAuB;AACvD,SAAO,GAAG,GAAG,MAAM,IAAI,GAAG,OAAO,IAAI,GAAG,MAAM;AAChD;AAKA,SAAS,eAAe,OAAwB;AAC9C,MAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,WAAO,OAAO,KAAK;AAAA,EACrB;AACA,MAAI,OAAO,UAAU,UAAU;AAE7B,WAAO,KAAK,UAAU,OAAO,OAAO,KAAK,KAAgC,EAAE,KAAK,CAAC;AAAA,EACnF;AACA,SAAO,OAAO,KAAK;AACrB;AAUO,SAAS,eACd,KACA,SACQ;AAER,QAAM,aAAa,MAAM,KAAK,QAAQ,KAAK,CAAC,EAAE,KAAK;AAGnD,QAAM,QAAkB,CAAC,OAAO,GAAG,EAAE;AAErC,aAAW,OAAO,YAAY;AAC5B,UAAM,SAAS,QAAQ,IAAI,GAAG;AAE9B,UAAM,YAAY,eAAe,OAAO,KAAK;AAE7C,QAAI,YAAY,GAAG,GAAG,IAAI,SAAS,IAAI,kBAAkB,OAAO,SAAS,CAAC;AAC1E,QAAI,OAAO,UAAU,QAAW;AAC9B,mBAAa,QAAQ,OAAO,KAAK;AAAA,IACnC;AACA,UAAM,KAAK,SAAS;AAAA,EACtB;AAEA,SAAO,WAAW,MAAM,KAAK,GAAG,CAAC;AACnC;AAMO,SAAS,gBAAmB,QAAgC;AACjE,QAAM,YAAY,eAAe,OAAO,KAAK;AAE7C,MAAI,MAAM,GAAG,OAAO,GAAG,IAAI,SAAS,IAAI,kBAAkB,OAAO,SAAS,CAAC;AAC3E,MAAI,OAAO,UAAU,QAAW;AAC9B,WAAO,QAAQ,OAAO,KAAK;AAAA,EAC7B;AAEA,SAAO,WAAW,GAAG;AACvB;AASO,SAAS,kBAAkB,GAAc,GAAsB;AACpE,MAAI,EAAE,WAAW,EAAE,QAAQ;AACzB,WAAO,EAAE,SAAS,EAAE;AAAA,EACtB;AACA,MAAI,EAAE,YAAY,EAAE,SAAS;AAC3B,WAAO,EAAE,UAAU,EAAE;AAAA,EACvB;AACA,SAAO,EAAE,OAAO,cAAc,EAAE,MAAM;AACxC;;;AChEO,IAAM,kBAAN,MAAsB;AAAA,EAI3B,YAAY,QAAgB,GAAG;AAC7B,SAAK,QAAQ;AACb,SAAK,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC,EAAE;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAsB,KAAwB;AAE5C,SAAK,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC,EAAE;AAIpC,UAAM,WAAW,IAAI,YAAY;AAEjC,eAAW,CAAC,KAAK,OAAO,KAAK,SAAS,OAAO;AAC3C,UAAI,QAAQ,OAAO,GAAG;AACpB,cAAM,SAAS,OAAO,GAAG;AACzB,cAAM,YAAY,eAAe,QAAQ,OAAO;AAChD,cAAM,WAAW,WAAW,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAChE,aAAK,WAAW,KAAK,MAAM,QAAQ,WAAW,UAAU,CAAC;AAAA,MAC3D;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAU,KAAa,SAA4C;AACjE,UAAM,WAAW,WAAW,GAAG,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAE7D,QAAI,QAAQ,SAAS,GAAG;AAEtB,WAAK,WAAW,KAAK,MAAM,KAAK,UAAU,CAAC;AAAA,IAC7C,OAAO;AACL,YAAM,YAAY,eAAe,KAAK,OAAO;AAC7C,WAAK,WAAW,KAAK,MAAM,KAAK,WAAW,UAAU,CAAC;AAAA,IACxD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,KAAmB;AACxB,UAAM,WAAW,WAAW,GAAG,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAC7D,SAAK,WAAW,KAAK,MAAM,KAAK,UAAU,CAAC;AAAA,EAC7C;AAAA,EAEQ,WACN,MACA,KACA,WACA,UACA,OACQ;AAER,QAAI,SAAS,KAAK,OAAO;AACvB,UAAI,CAAC,KAAK,QAAS,MAAK,UAAU,oBAAI,IAAI;AAC1C,WAAK,QAAQ,IAAI,KAAK,SAAS;AAG/B,UAAIC,KAAI;AACR,iBAAW,OAAO,KAAK,QAAQ,OAAO,GAAG;AACvC,QAAAA,KAAKA,KAAI,MAAO;AAAA,MAClB;AACA,WAAK,OAAOA,OAAM;AAClB,aAAO,KAAK;AAAA,IACd;AAGA,UAAM,aAAa,SAAS,KAAK;AACjC,QAAI,CAAC,KAAK,SAAU,MAAK,WAAW,CAAC;AAErC,QAAI,CAAC,KAAK,SAAS,UAAU,GAAG;AAC9B,WAAK,SAAS,UAAU,IAAI,EAAE,MAAM,EAAE;AAAA,IACxC;AAEA,SAAK,WAAW,KAAK,SAAS,UAAU,GAAG,KAAK,WAAW,UAAU,QAAQ,CAAC;AAG9E,QAAI,IAAI;AACR,eAAW,SAAS,OAAO,OAAO,KAAK,QAAQ,GAAG;AAChD,UAAK,IAAI,MAAM,OAAQ;AAAA,IACzB;AACA,SAAK,OAAO,MAAM;AAClB,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,WACN,MACA,KACA,UACA,OACQ;AAER,QAAI,SAAS,KAAK,OAAO;AACvB,UAAI,KAAK,SAAS;AAChB,aAAK,QAAQ,OAAO,GAAG;AAGvB,YAAIA,KAAI;AACR,mBAAW,OAAO,KAAK,QAAQ,OAAO,GAAG;AACvC,UAAAA,KAAKA,KAAI,MAAO;AAAA,QAClB;AACA,aAAK,OAAOA,OAAM;AAAA,MACpB;AACA,aAAO,KAAK;AAAA,IACd;AAGA,UAAM,aAAa,SAAS,KAAK;AACjC,QAAI,KAAK,YAAY,KAAK,SAAS,UAAU,GAAG;AAC9C,WAAK,WAAW,KAAK,SAAS,UAAU,GAAG,KAAK,UAAU,QAAQ,CAAC;AAAA,IACrE;AAGA,QAAI,IAAI;AACR,QAAI,KAAK,UAAU;AACjB,iBAAW,SAAS,OAAO,OAAO,KAAK,QAAQ,GAAG;AAChD,YAAK,IAAI,MAAM,OAAQ;AAAA,MACzB;AAAA,IACF;AACA,SAAK,OAAO,MAAM;AAClB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,cAAsB;AACpB,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,MAA2C;AACjD,QAAI,UAAU,KAAK;AACnB,eAAW,QAAQ,MAAM;AACvB,UAAI,CAAC,QAAQ,YAAY,CAAC,QAAQ,SAAS,IAAI,GAAG;AAChD,eAAO;AAAA,MACT;AACA,gBAAU,QAAQ,SAAS,IAAI;AAAA,IACjC;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,MAAsC;AAC/C,UAAM,OAAO,KAAK,QAAQ,IAAI;AAC9B,QAAI,CAAC,QAAQ,CAAC,KAAK,SAAU,QAAO,CAAC;AAErC,UAAM,SAAiC,CAAC;AACxC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,QAAQ,GAAG;AACxD,aAAO,GAAG,IAAI,MAAM;AAAA,IACtB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,MAAwB;AACtC,UAAM,OAAO,KAAK,QAAQ,IAAI;AAC9B,QAAI,CAAC,QAAQ,CAAC,KAAK,QAAS,QAAO,CAAC;AACpC,WAAO,MAAM,KAAK,KAAK,QAAQ,KAAK,CAAC;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,aAAa,MAAc,eAAiD;AAC1E,UAAM,WAAW,oBAAI,IAAY;AACjC,UAAM,OAAO,KAAK,QAAQ,IAAI;AAC9B,UAAM,eAAe,MAAM,WAAW,oBAAI,IAAI;AAG9C,eAAW,CAAC,KAAK,IAAI,KAAK,cAAc;AACtC,YAAM,aAAa,cAAc,IAAI,GAAG;AACxC,UAAI,eAAe,UAAa,eAAe,MAAM;AACnD,iBAAS,IAAI,GAAG;AAAA,MAClB;AAAA,IACF;AAGA,eAAW,OAAO,cAAc,KAAK,GAAG;AACtC,UAAI,CAAC,aAAa,IAAI,GAAG,GAAG;AAC1B,iBAAS,IAAI,GAAG;AAAA,MAClB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAe,MAAmC;AAChD,UAAM,OAAO,KAAK,QAAQ,IAAI;AAC9B,WAAO,MAAM,WAAW,oBAAI,IAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,MAAuB;AAC5B,UAAM,OAAO,KAAK,QAAQ,IAAI;AAC9B,WAAO,SAAS,UAAa,KAAK,YAAY,UAAa,KAAK,QAAQ,OAAO;AAAA,EACjF;AACF;;;ACjNO,IAAM,QAAN,MAAkB;AAAA,EAiBvB,YAAY,KAAU;AAOtB,SAAQ,YAA+B,CAAC;AANtC,SAAK,MAAM;AACX,SAAK,QAAQ,oBAAI,IAAI;AACrB,SAAK,aAAa,oBAAI,IAAI;AAC1B,SAAK,aAAa,IAAI,gBAAgB;AAAA,EACxC;AAAA,EAIO,SAAS,UAAkC;AAChD,SAAK,UAAU,KAAK,QAAQ;AAC5B,WAAO,MAAM;AACX,WAAK,YAAY,KAAK,UAAU,OAAO,QAAM,OAAO,QAAQ;AAAA,IAC9D;AAAA,EACF;AAAA,EAEQ,SAAe;AACrB,SAAK,UAAU,QAAQ,QAAM,GAAG,CAAC;AAAA,EACnC;AAAA,EAEA,IAAW,OAAe;AACxB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,IAAW,eAAuB;AAChC,QAAI,QAAQ;AACZ,eAAW,UAAU,KAAK,MAAM,OAAO,GAAG;AACxC,eAAS,OAAO;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,IAAI,KAAQ,OAAU,OAAgC;AAC3D,UAAM,YAAY,KAAK,IAAI,IAAI;AAE/B,UAAM,MAAM,IAAI,SAAS,SAAS;AAElC,UAAM,SAAyB;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI,UAAU,QAAW;AACvB,UAAI,OAAO,UAAU,YAAY,SAAS,KAAK,CAAC,OAAO,SAAS,KAAK,GAAG;AACtE,cAAM,IAAI,MAAM,sCAAsC;AAAA,MACxD;AACA,aAAO,QAAQ;AAAA,IACjB;AAEA,QAAI,SAAS,KAAK,MAAM,IAAI,GAAG;AAC/B,QAAI,CAAC,QAAQ;AACX,eAAS,oBAAI,IAAI;AACjB,WAAK,MAAM,IAAI,KAAK,MAAM;AAAA,IAC5B;AAEA,WAAO,IAAI,KAAK,MAAM;AACtB,SAAK,iBAAiB,GAAG;AACzB,SAAK,OAAO;AACZ,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,OAAO,KAAQ,OAAoB;AACxC,UAAM,SAAS,KAAK,MAAM,IAAI,GAAG;AACjC,QAAI,CAAC,OAAQ,QAAO,CAAC;AAGrB,UAAM,eAAyB,CAAC;AAEhC,eAAW,CAAC,KAAK,MAAM,KAAK,OAAO,QAAQ,GAAG;AAE5C,UAAI,OAAO,UAAU,OAAO;AAC1B,qBAAa,KAAK,GAAG;AAAA,MACvB;AAAA,IACF;AAEA,eAAW,OAAO,cAAc;AAC9B,WAAK,WAAW,IAAI,GAAG;AACvB,aAAO,OAAO,GAAG;AAAA,IACnB;AAEA,QAAI,OAAO,SAAS,GAAG;AACrB,WAAK,MAAM,OAAO,GAAG;AAAA,IACvB;AAEA,SAAK,iBAAiB,GAAG;AACzB,SAAK,OAAO;AACZ,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKO,QAAc;AACnB,SAAK,MAAM,MAAM;AACjB,SAAK,WAAW,MAAM;AACtB,SAAK,aAAa,IAAI,gBAAgB;AACtC,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,IAAI,KAAa;AACtB,UAAM,SAAS,KAAK,MAAM,IAAI,GAAG;AACjC,QAAI,CAAC,OAAQ,QAAO,CAAC;AAErB,UAAM,SAAc,CAAC;AACrB,UAAM,MAAM,KAAK,IAAI;AAErB,eAAW,CAAC,KAAK,MAAM,KAAK,OAAO,QAAQ,GAAG;AAC5C,UAAI,CAAC,KAAK,WAAW,IAAI,GAAG,GAAG;AAE7B,YAAI,OAAO,SAAS,OAAO,UAAU,SAAS,OAAO,QAAQ,KAAK;AAChE;AAAA,QACF;AACA,eAAO,KAAK,OAAO,KAAK;AAAA,MAC1B;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,WAAW,KAA0B;AAC1C,UAAM,SAAS,KAAK,MAAM,IAAI,GAAG;AACjC,QAAI,CAAC,OAAQ,QAAO,CAAC;AAErB,UAAM,UAA4B,CAAC;AACnC,UAAM,MAAM,KAAK,IAAI;AAErB,eAAW,CAAC,KAAK,MAAM,KAAK,OAAO,QAAQ,GAAG;AAC5C,UAAI,CAAC,KAAK,WAAW,IAAI,GAAG,GAAG;AAE7B,YAAI,OAAO,SAAS,OAAO,UAAU,SAAS,OAAO,QAAQ,KAAK;AAChE;AAAA,QACF;AACA,gBAAQ,KAAK,MAAM;AAAA,MACrB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKO,gBAA0B;AAC/B,WAAO,MAAM,KAAK,KAAK,UAAU;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,MAAM,KAAQ,QAAiC;AACpD,QAAI,KAAK,WAAW,IAAI,OAAO,GAAG,EAAG,QAAO;AAE5C,QAAI,SAAS,KAAK,MAAM,IAAI,GAAG;AAC/B,QAAI,CAAC,QAAQ;AACX,eAAS,oBAAI,IAAI;AACjB,WAAK,MAAM,IAAI,KAAK,MAAM;AAAA,IAC5B;AACA,WAAO,IAAI,OAAO,KAAK,MAAM;AAC7B,SAAK,IAAI,OAAO,OAAO,SAAS;AAChC,SAAK,iBAAiB,GAAG;AACzB,SAAK,OAAO;AACZ,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKO,eAAe,KAAmB;AACvC,SAAK,WAAW,IAAI,GAAG;AAEvB,eAAW,CAAC,KAAK,MAAM,KAAK,KAAK,OAAO;AACtC,UAAI,OAAO,IAAI,GAAG,GAAG;AACnB,eAAO,OAAO,GAAG;AACjB,YAAI,OAAO,SAAS,EAAG,MAAK,MAAM,OAAO,GAAG;AAC5C,aAAK,iBAAiB,GAAG;AAEzB;AAAA,MACF;AAAA,IACF;AACA,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,MAAM,OAA0B;AACrC,UAAM,cAAc,oBAAI,IAAO;AAG/B,eAAW,OAAO,MAAM,YAAY;AAClC,WAAK,WAAW,IAAI,GAAG;AAAA,IACzB;AAGA,eAAW,CAAC,KAAK,WAAW,KAAK,MAAM,OAAO;AAC5C,UAAI,cAAc,KAAK,MAAM,IAAI,GAAG;AACpC,UAAI,CAAC,aAAa;AAChB,sBAAc,oBAAI,IAAI;AACtB,aAAK,MAAM,IAAI,KAAK,WAAW;AAAA,MACjC;AAEA,iBAAW,CAAC,KAAK,MAAM,KAAK,aAAa;AAEvC,YAAI,CAAC,KAAK,WAAW,IAAI,GAAG,GAAG;AAC7B,cAAI,CAAC,YAAY,IAAI,GAAG,GAAG;AACzB,wBAAY,IAAI,KAAK,MAAM;AAC3B,wBAAY,IAAI,GAAG;AAAA,UACrB;AAEA,eAAK,IAAI,OAAO,OAAO,SAAS;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAGA,eAAW,CAAC,KAAK,WAAW,KAAK,KAAK,OAAO;AAC3C,iBAAW,OAAO,YAAY,KAAK,GAAG;AACpC,YAAI,KAAK,WAAW,IAAI,GAAG,GAAG;AAC5B,sBAAY,OAAO,GAAG;AACtB,sBAAY,IAAI,GAAG;AAAA,QACrB;AAAA,MACF;AACA,UAAI,YAAY,SAAS,GAAG;AAC1B,aAAK,MAAM,OAAO,GAAG;AAAA,MACvB;AAAA,IACF;AAGA,eAAW,OAAO,aAAa;AAC7B,WAAK,iBAAiB,GAAG;AAAA,IAC3B;AAEA,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKO,MAAM,WAAgC;AAC3C,UAAM,cAAwB,CAAC;AAE/B,eAAW,OAAO,KAAK,YAAY;AACjC,UAAI;AACF,cAAM,YAAY,IAAI,MAAM,GAAG;AAC/B,YAAI,IAAI,QAAQ,WAAW,SAAS,IAAI,GAAG;AACzC,eAAK,WAAW,OAAO,GAAG;AAC1B,sBAAY,KAAK,GAAG;AAAA,QACtB;AAAA,MACF,SAAS,GAAG;AAAA,MAEZ;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,gBAAiC;AACtC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,cAAmC;AACxC,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,YAAY,KAAK;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKO,UAAe;AACpB,WAAO,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,cAAc,KAAiD;AACpE,WAAO,KAAK,MAAM,IAAI,GAAG;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYO,SACL,KACA,eACA,mBAA6B,CAAC,GACd;AAChB,QAAI,QAAQ;AACZ,QAAI,UAAU;AAGd,eAAW,OAAO,kBAAkB;AAClC,UAAI,CAAC,KAAK,WAAW,IAAI,GAAG,GAAG;AAC7B,aAAK,WAAW,IAAI,GAAG;AAAA,MACzB;AAAA,IACF;AAGA,QAAI,cAAc,KAAK,MAAM,IAAI,GAAG;AACpC,QAAI,CAAC,aAAa;AAChB,oBAAc,oBAAI,IAAI;AACtB,WAAK,MAAM,IAAI,KAAK,WAAW;AAAA,IACjC;AAGA,eAAW,OAAO,YAAY,KAAK,GAAG;AACpC,UAAI,KAAK,WAAW,IAAI,GAAG,GAAG;AAC5B,oBAAY,OAAO,GAAG;AAAA,MACxB;AAAA,IACF;AAGA,eAAW,gBAAgB,eAAe;AAExC,UAAI,KAAK,WAAW,IAAI,aAAa,GAAG,GAAG;AACzC;AAAA,MACF;AAEA,YAAM,cAAc,YAAY,IAAI,aAAa,GAAG;AAEpD,UAAI,CAAC,aAAa;AAEhB,oBAAY,IAAI,aAAa,KAAK,YAAY;AAC9C;AAAA,MACF,WAAW,kBAAkB,aAAa,WAAW,YAAY,SAAS,IAAI,GAAG;AAE/E,oBAAY,IAAI,aAAa,KAAK,YAAY;AAC9C;AAAA,MACF;AAIA,WAAK,IAAI,OAAO,aAAa,SAAS;AAAA,IACxC;AAGA,QAAI,YAAY,SAAS,GAAG;AAC1B,WAAK,MAAM,OAAO,GAAG;AAAA,IACvB;AAGA,SAAK,iBAAiB,GAAG;AAEzB,QAAI,QAAQ,KAAK,UAAU,GAAG;AAC5B,WAAK,OAAO;AAAA,IACd;AAEA,WAAO,EAAE,OAAO,QAAQ;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKO,aAAa,KAAsB;AACxC,WAAO,KAAK,WAAW,IAAI,GAAG;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAAiB,KAAc;AACrC,UAAM,SAAS,OAAO,GAAG;AACzB,UAAM,SAAS,KAAK,MAAM,IAAI,GAAG;AAEjC,QAAI,CAAC,UAAU,OAAO,SAAS,GAAG;AAChC,WAAK,WAAW,OAAO,MAAM;AAAA,IAC/B,OAAO;AACL,WAAK,WAAW,OAAO,QAAQ,MAAM;AAAA,IACvC;AAAA,EACF;AACF;;;ACxdA,sBAA6B;AAQtB,SAAS,UAAU,MAA2B;AACnD,aAAO,sBAAK,IAAI;AAClB;AAQO,SAAS,YAAyB,MAAmC;AAE1E,QAAM,SAAS,gBAAgB,cAAc,IAAI,WAAW,IAAI,IAAI;AACpE,aAAO,wBAAO,MAAM;AACtB;;;AC0DO,IAAM,gBAAN,MAAyC;AAAA,EAK9C,YAAY,QAAyB;AAFrC,SAAQ,YAA0C,oBAAI,IAAI;AAGxD,SAAK,SAAS,OAAO;AACrB,SAAK,QAAQ,OAAO,gBAAgB;AAAA,MAClC,UAAU,oBAAI,IAAI;AAAA,MAClB,UAAU,oBAAI,IAAI;AAAA,IACpB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc;AACZ,QAAI,MAAM;AACV,eAAW,KAAK,KAAK,MAAM,SAAS,OAAO,EAAG,QAAO;AACrD,eAAW,KAAK,KAAK,MAAM,SAAS,OAAO,EAAG,QAAO;AACrD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,YAAoB;AAClB,WAAO,KAAK,UAAU,CAAC;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,YAAoB;AAClB,WAAO,KAAK,UAAU,EAAE;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,OAAuB;AAC/B,QAAI,UAAU,EAAG,QAAO,KAAK,IAAI;AAEjC,QAAI,QAAQ,GAAG;AACb,YAAM,UAAU,KAAK,MAAM,SAAS,IAAI,KAAK,MAAM,KAAK;AACxD,WAAK,MAAM,SAAS,IAAI,KAAK,QAAQ,UAAU,KAAK;AAAA,IACtD,OAAO;AACL,YAAM,UAAU,KAAK,MAAM,SAAS,IAAI,KAAK,MAAM,KAAK;AACxD,WAAK,MAAM,SAAS,IAAI,KAAK,QAAQ,UAAU,KAAK,IAAI,KAAK,CAAC;AAAA,IAChE;AAEA,UAAM,WAAW,KAAK,IAAI;AAC1B,SAAK,gBAAgB,QAAQ;AAC7B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,WAA2B;AACzB,WAAO;AAAA,MACL,UAAU,IAAI,IAAI,KAAK,MAAM,QAAQ;AAAA,MACrC,UAAU,IAAI,IAAI,KAAK,MAAM,QAAQ;AAAA,IACvC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,QAA8B;AAClC,QAAI,UAAU;AAGd,eAAW,CAAC,QAAQ,KAAK,KAAK,OAAO,UAAU;AAC7C,YAAM,UAAU,KAAK,MAAM,SAAS,IAAI,MAAM,KAAK;AACnD,UAAI,QAAQ,SAAS;AACnB,aAAK,MAAM,SAAS,IAAI,QAAQ,KAAK;AACrC,kBAAU;AAAA,MACZ;AAAA,IACF;AAGA,eAAW,CAAC,QAAQ,KAAK,KAAK,OAAO,UAAU;AAC7C,YAAM,UAAU,KAAK,MAAM,SAAS,IAAI,MAAM,KAAK;AACnD,UAAI,QAAQ,SAAS;AACnB,aAAK,MAAM,SAAS,IAAI,QAAQ,KAAK;AACrC,kBAAU;AAAA,MACZ;AAAA,IACF;AAEA,QAAI,SAAS;AACX,WAAK,gBAAgB,KAAK,IAAI,CAAC;AAAA,IACjC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,UAAU,UAA+C;AACvD,SAAK,UAAU,IAAI,QAAQ;AAE3B,aAAS,KAAK,IAAI,CAAC;AACnB,WAAO,MAAM,KAAK,UAAU,OAAO,QAAQ;AAAA,EAC7C;AAAA,EAEQ,gBAAgB,OAAqB;AAC3C,eAAW,YAAY,KAAK,WAAW;AACrC,UAAI;AACF,iBAAS,KAAK;AAAA,MAChB,SAAS,GAAG;AAAA,MAEZ;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,YAAoB;AAClB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,UAAU,OAAmC;AAClD,UAAM,MAA4B;AAAA,MAChC,GAAG,OAAO,YAAY,MAAM,QAAQ;AAAA,MACpC,GAAG,OAAO,YAAY,MAAM,QAAQ;AAAA,IACtC;AACA,WAAO,UAAU,GAAG;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,YAAY,MAAkC;AACnD,UAAM,MAAM,YAAkC,IAAI;AAClD,WAAO;AAAA,MACL,UAAU,IAAI,IAAI,OAAO,QAAQ,IAAI,CAAC,CAAC;AAAA,MACvC,UAAU,IAAI,IAAI,OAAO,QAAQ,IAAI,CAAC,CAAC;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,cAAc,OAA6C;AAChE,WAAO;AAAA,MACL,GAAG,OAAO,YAAY,MAAM,QAAQ;AAAA,MACpC,GAAG,OAAO,YAAY,MAAM,QAAQ;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,cAAc,KAA2C;AAC9D,WAAO;AAAA,MACL,UAAU,IAAI,IAAI,OAAO,QAAQ,IAAI,CAAC,CAAC;AAAA,MACvC,UAAU,IAAI,IAAI,OAAO,QAAQ,IAAI,CAAC,CAAC;AAAA,IACzC;AAAA,EACF;AACF;;;AC3PO,IAAM,aAAN,MAAoB;AAAA;AAAA,EAMzB,YAAY,UAAkB;AAH9B,SAAQ,eAAuB;AAC/B;AAAA,SAAQ,eAAuB;AAG7B,QAAI,WAAW,GAAG;AAChB,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AACA,SAAK,YAAY;AACjB,SAAK,SAAS,IAAI,MAAM,QAAQ;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAiB;AACnB,UAAM,WAAW,KAAK;AACtB,UAAM,QAAQ,OAAO,WAAW,OAAO,KAAK,SAAS,CAAC;AAEtD,SAAK,OAAO,KAAK,IAAI;AACrB,SAAK;AAGL,QAAI,KAAK,eAAe,KAAK,eAAe,KAAK,WAAW;AAC1D,WAAK,eAAe,KAAK,eAAe,OAAO,KAAK,SAAS;AAAA,IAC/D;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAAK,UAAiC;AACpC,QAAI,WAAW,KAAK,gBAAgB,YAAY,KAAK,cAAc;AACjE,aAAO;AAAA,IACT;AACA,UAAM,QAAQ,OAAO,WAAW,OAAO,KAAK,SAAS,CAAC;AACtD,WAAO,KAAK,OAAO,KAAK;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,UAAkB,QAAqB;AAC/C,UAAM,QAAa,CAAC;AACpB,UAAM,cAAc,WAAW,KAAK,eAAe,KAAK,eAAe;AACvE,UAAM,YAAY,UAAU,KAAK,eAAe,KAAK,eAAe,KAAK;AAEzE,aAAS,MAAM,aAAa,OAAO,WAAW,OAAO;AACnD,YAAM,OAAO,KAAK,KAAK,GAAG;AAC1B,UAAI,SAAS,QAAW;AACtB,cAAM,KAAK,IAAI;AAAA,MACjB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,UAAkB,QAAgB,KAAU;AACnD,UAAM,SAAS,WAAW,OAAO,KAAK,IAAI;AAC1C,WAAO,KAAK,UAAU,UAAU,MAAM;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,kBAA0B;AACxB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,kBAA0B;AACxB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,OAAe;AACb,WAAO,OAAO,KAAK,eAAe,KAAK,YAAY;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA,EAKA,cAAsB;AACpB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,SAAS,IAAI,MAAM,KAAK,SAAS;AACtC,SAAK,eAAe;AACpB,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,UAA2B;AACrC,WAAO,YAAY,KAAK,gBAAgB,WAAW,KAAK;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA4B;AAC1B,WAAO,KAAK,YAAY,KAAK,KAAK;AAAA,EACpC;AACF;;;AC3DO,IAAM,+BAAmD;AAAA,EAC9D,UAAU;AAAA,EACV,OAAO;AAAA;AAAA,EACP,YAAY;AAAA,EACZ,aAAa,CAAC;AAAA,EACd,aAAa,CAAC;AAChB;AA8CO,IAAM,mBAAN,MAA+C;AAAA,EAMpD,YAAY,SAAsC,CAAC,GAAG;AAHtD,SAAiB,YAAuC,oBAAI,IAAI;AAI9D,SAAK,SAAS,EAAE,GAAG,8BAA8B,GAAG,OAAO;AAC3D,SAAK,SAAS,IAAI,WAAW,KAAK,OAAO,QAAQ;AAEjD,QAAI,KAAK,OAAO,QAAQ,GAAG;AACzB,WAAK,gBAAgB;AAAA,IACvB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAU,WAAkD;AAE1D,QAAI,CAAC,KAAK,cAAc,UAAU,OAAO,GAAG;AAC1C,aAAO,EAAE,GAAG,WAAW,UAAU,CAAC,GAAG;AAAA,IACvC;AAEA,UAAM,QAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,UAAU;AAAA;AAAA,IACZ;AAEA,UAAM,WAAW,KAAK,OAAO,IAAI,KAAK;AACtC,UAAM,WAAW;AAGjB,eAAW,YAAY,KAAK,WAAW;AACrC,UAAI;AACF,iBAAS,KAAK;AAAA,MAChB,SAAS,GAAG;AACV,gBAAQ,MAAM,gCAAgC,CAAC;AAAA,MACjD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,UAAkB,QAAgB,KAAqB;AAC9D,WAAO,KAAK,OAAO,SAAS,UAAU,KAAK;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,UAAkB,QAAgC;AAC1D,WAAO,KAAK,OAAO,UAAU,UAAU,MAAM;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,oBAA4B;AAC1B,UAAM,OAAO,KAAK,OAAO,gBAAgB;AACzC,WAAO,OAAO,KAAK,OAAO,KAAK;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA4B;AAC1B,WAAO,KAAK,OAAO,gBAAgB;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,UACE,UACA,cACY;AAEZ,QAAI,iBAAiB,QAAW;AAC9B,YAAM,SAAS,KAAK,SAAS,cAAc,KAAK,OAAO,QAAQ;AAC/D,iBAAW,SAAS,QAAQ;AAC1B,YAAI;AACF,mBAAS,KAAK;AAAA,QAChB,SAAS,GAAG;AACV,kBAAQ,MAAM,8BAA8B,CAAC;AAAA,QAC/C;AAAA,MACF;AAAA,IACF;AAEA,SAAK,UAAU,IAAI,QAAQ;AAC3B,WAAO,MAAM,KAAK,UAAU,OAAO,QAAQ;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,cAA+C;AAC7C,WAAO;AAAA,MACL,MAAM,KAAK,OAAO,KAAK;AAAA,MACvB,OAAO,KAAK,OAAO,YAAY;AAAA,IACjC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAyB;AAAA,EAI/B;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,SAA0B;AAC9C,UAAM,EAAE,aAAa,YAAY,IAAI,KAAK;AAE1C,QAAI,eAAe,YAAY,SAAS,OAAO,GAAG;AAChD,aAAO;AAAA,IACT;AAEA,QAAI,eAAe,YAAY,SAAS,GAAG;AACzC,aAAO,YAAY,SAAS,OAAO;AAAA,IACrC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAwB;AAC9B,UAAM,WAAW,KAAK,IAAI,KAAK,OAAO,OAAO,GAAK;AAClD,SAAK,WAAW,YAAY,MAAM;AAChC,WAAK,QAAQ;AAAA,IACf,GAAG,QAAQ;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACd,QAAI,KAAK,UAAU;AACjB,oBAAc,KAAK,QAAQ;AAC3B,WAAK,WAAW;AAAA,IAClB;AACA,SAAK,UAAU,MAAM;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,mBAA2B;AACzB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,YAAgC;AAC9B,WAAO,EAAE,GAAG,KAAK,OAAO;AAAA,EAC1B;AACF;;;ACxSA,iBAAkB;AAkBX,IAAM,0BAA0B,aAAE,OAAO;AAAA,EAC9C,MAAM,aAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC/B,MAAM,aAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAK;AAAA;AAAA,EACjC,MAAM,aAAE,QAAQ,EAAE,SAAS;AAC7B,CAAC;AA2CM,IAAM,qBAAqB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMO,SAAS,sBAAsB,MAGpC;AACA,aAAW,WAAW,oBAAoB;AACxC,QAAI,QAAQ,KAAK,IAAI,GAAG;AACtB,aAAO;AAAA,QACL,OAAO;AAAA,QACP,OAAO,+BAA+B,QAAQ,MAAM;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,OAAO,KAAK;AACvB;AAQO,IAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA,EAK/B,WAAW,CAAC,QAAgB,OAA0C;AAAA,IACpE,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,IAKN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,CAAC,QAAgB,OAA0C;AAAA,IACpE,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,IAKN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB,CACf,QAAgB,OAC0D;AAAA,IAC1E,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,CAAC,YAAuD;AAAA,IAChE,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,IAKN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAe,CAAI,cAAgD;AAAA,IACjE,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,CAAI,cAAsD;AAAA,IACjE,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBAAmB,CACjB,eACA,cACmC;AAAA,IACnC,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMN,MAAM,EAAE,UAAU,eAAe,SAAS;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,kBAAkB,CAAI,mBAAqD;AAAA,IACzE,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,CAAI,UAA6C;AAAA,IAC3D,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,IAKN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,OAAiD;AAAA,IAC1D,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,CAAI,UAA8C;AAAA,IAC9D,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAWN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,CACZ,MACA,eAC6B;AAAA,IAC7B,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAWN,MAAM,EAAE,MAAM,OAAO,UAAU;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB,CAAI,UAAiD;AAAA,IACpE,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiBN,MAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAAK,OAA+C;AAAA,IAClD,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA,EAGR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,oBAAoB,CAClB,iBACA,aACmE;AAAA,IACnE,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiBN,MAAM,EAAE,iBAAiB,QAAQ;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,CACL,gBAC6B;AAAA,IAC7B,MAAM;AAAA,IACN,MAAM;AAAA;AAAA;AAAA;AAAA,IAIN,MAAM;AAAA,EACR;AACF;AAqBO,IAAM,gCAA0D;AAAA,EACrE,wBAAwB;AAAA,EACxB,kBAAkB;AAAA;AAAA,EAClB,kBAAkB;AAAA;AACpB;;;ACzZA,IAAAC,cAAkB;AAwFX,IAAM,4BAA4B,cAAE,OAAO;AAAA,EAChD,MAAM,cAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC/B,MAAM,cAAE,OAAO,EAAE,IAAI,GAAK,EAAE,SAAS;AAAA,EACrC,UAAU,cAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAAA,EACrD,YAAY,cAAE,OAAO,EAAE,SAAS;AAClC,CAAC;AAQM,IAAM,8BAA8B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,SAAS,qBAAqB,MAGnC;AACA,aAAW,WAAW,6BAA6B;AACjD,QAAI,QAAQ,KAAK,IAAI,GAAG;AACtB,aAAO;AAAA,QACL,OAAO;AAAA,QACP,OAAO,+BAA+B,QAAQ,MAAM;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,OAAO,KAAK;AACvB;AAkBO,IAAM,+BAAwD;AAAA,EACnE,uBAAuB;AAAA,EACvB,kBAAkB;AAAA;AACpB;AAQO,SAAS,qBAAqB,GAAc,GAAsB;AACvE,SAAO,IAAI,QAAQ,GAAG,CAAC;AACzB;AAMO,SAAS,UAA4B,QAAW,QAAc;AACnE,QAAM,SAAS,EAAE,GAAG,OAAO;AAE3B,aAAW,OAAO,OAAO,KAAK,MAAM,GAAkB;AACpD,UAAM,YAAY,OAAO,GAAG;AAC5B,UAAM,YAAY,OAAO,GAAG;AAE5B,QACE,OAAO,cAAc,YACrB,cAAc,QACd,OAAO,cAAc,YACrB,cAAc,QACd,CAAC,MAAM,QAAQ,SAAS,GACxB;AACA,MAAC,OAAmC,GAAa,IAAI;AAAA,QACnD;AAAA,QACA;AAAA,MACF;AAAA,IACF,OAAO;AACL,MAAC,OAAmC,GAAa,IAAI;AAAA,IACvD;AAAA,EACF;AAEA,SAAO;AACT;AAQO,IAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA,EAI9B,KAAK,OAAkC;AAAA,IACrC,MAAM;AAAA,IACN,IAAI,CAAC,QAAQ;AACX,UAAI,CAAC,IAAI,gBAAgB;AACvB,eAAO,EAAE,QAAQ,UAAU,OAAO,IAAI,YAAY;AAAA,MACpD;AAEA,YAAM,MAAM,qBAAqB,IAAI,iBAAiB,IAAI,cAAc;AACxE,UAAI,MAAM,GAAG;AACX,eAAO,EAAE,QAAQ,UAAU,OAAO,IAAI,YAAY;AAAA,MACpD;AACA,aAAO,EAAE,QAAQ,QAAQ;AAAA,IAC3B;AAAA,IACA,UAAU;AAAA;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,kBAAkB,OAAkC;AAAA,IAClD,MAAM;AAAA,IACN,IAAI,CAAC,QAAQ;AACX,UAAI,IAAI,eAAe,QAAW;AAChC,eAAO,EAAE,QAAQ,UAAU,QAAQ,uBAAuB;AAAA,MAC5D;AACA,aAAO,EAAE,QAAQ,UAAU,OAAO,IAAI,YAAY;AAAA,IACpD;AAAA,IACA,UAAU;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,OAAoC;AAAA,IAC/C,MAAM;AAAA,IACN,IAAI,CAAC,QAAQ;AACX,YAAM,QAAQ,IAAI,cAAc;AAChC,YAAM,SAAS,IAAI;AACnB,aAAO,EAAE,QAAQ,SAAS,OAAO,KAAK,IAAI,OAAO,MAAM,EAAE;AAAA,IAC3D;AAAA,IACA,UAAU;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,OAAoC;AAAA,IAC/C,MAAM;AAAA,IACN,IAAI,CAAC,QAAQ;AACX,YAAM,QAAQ,IAAI,cAAc;AAChC,YAAM,SAAS,IAAI;AACnB,aAAO,EAAE,QAAQ,SAAS,OAAO,KAAK,IAAI,OAAO,MAAM,EAAE;AAAA,IAC3D;AAAA,IACA,UAAU;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,OAAoC;AAAA,IAChD,MAAM;AAAA,IACN,IAAI,CAAC,QAAQ;AACX,UAAI,OAAO,IAAI,gBAAgB,YAAY,IAAI,cAAc,GAAG;AAC9D,eAAO,EAAE,QAAQ,UAAU,QAAQ,2BAA2B;AAAA,MAChE;AACA,aAAO,EAAE,QAAQ,UAAU,OAAO,IAAI,YAAY;AAAA,IACpD;AAAA,IACA,UAAU;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,OAAoC;AAAA,IAC/C,MAAM;AAAA,IACN,IAAI,CAAC,QAAQ;AACX,YAAM,QAAQ,IAAI,cAAc,CAAC;AACjC,YAAM,SAAS,IAAI,eAAe,CAAC;AACnC,YAAM,SAAS,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC;AACjD,aAAO,EAAE,QAAQ,SAAS,OAAO,OAAO;AAAA,IAC1C;AAAA,IACA,UAAU;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,OAAiD;AAAA,IAC3D,MAAM;AAAA,IACN,IAAI,CAAC,QAAQ;AACX,YAAM,QAAS,IAAI,cAAc,CAAC;AAClC,YAAM,SAAS,IAAI;AACnB,YAAM,SAAS,UAAU,OAAO,MAAM;AACtC,aAAO,EAAE,QAAQ,SAAS,OAAO,OAAO;AAAA,IAC1C;AAAA,IACA,UAAU;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,OAAkC;AAAA,IAC7C,MAAM;AAAA,IACN,IAAI,CAAC,QAAQ;AAEX,UAAI,IAAI,MAAM,OAAO,SAAS,QAAQ,KAAK,IAAI,aAAa,WAAW,SAAS,GAAG;AACjF,eAAO,EAAE,QAAQ,UAAU,OAAO,IAAI,YAAY;AAAA,MACpD;AACA,aAAO,EAAE,QAAQ,UAAU,QAAQ,sCAAsC;AAAA,IAC3E;AAAA,IACA,UAAU;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,OAA+D;AAAA,IACzE,MAAM;AAAA,IACN,IAAI,CAAC,QAAQ;AAEX,UAAI,CAAC,IAAI,YAAY;AACnB,eAAO,EAAE,QAAQ,UAAU,OAAO,IAAI,YAAY;AAAA,MACpD;AAGA,YAAM,UAAU,IAAI,WAAW;AAC/B,UAAI,WAAW,IAAI,MAAM,WAAW,SAAS;AAC3C,eAAO,EAAE,QAAQ,UAAU,QAAQ,mCAAmC;AAAA,MACxE;AAEA,aAAO,EAAE,QAAQ,UAAU,OAAO,IAAI,YAAY;AAAA,IACpD;AAAA,IACA,UAAU;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,OAAkC;AAAA,IAC3C,MAAM;AAAA,IACN,IAAI,CAAC,QAAQ;AACX,UAAI,IAAI,eAAe,QAAW;AAChC,eAAO,EAAE,QAAQ,UAAU,QAAQ,qBAAqB;AAAA,MAC1D;AACA,aAAO,EAAE,QAAQ,UAAU,OAAO,IAAI,YAAY;AAAA,IACpD;AAAA,IACA,UAAU;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBAAmB,OAA+D;AAAA,IAChF,MAAM;AAAA,IACN,IAAI,CAAC,QAAQ;AACX,YAAM,eAAe,IAAI,YAAY,WAAW;AAChD,YAAM,gBAAgB,IAAI,aAAa,WAAW;AAElD,UAAI,kBAAkB,eAAe,GAAG;AACtC,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,QAAQ,8BAA8B,eAAe,CAAC,SAAS,aAAa;AAAA,QAC9E;AAAA,MACF;AACA,aAAO,EAAE,QAAQ,UAAU,OAAO,IAAI,YAAY;AAAA,IACpD;AAAA,IACA,UAAU;AAAA,EACZ;AACF;;;ACnVO,IAAM,aAAN,MAAiB;AAAA,EACtB,OAAO,MAAM,WAAmB,OAA2B;AACzD,WAAO,EAAE,IAAI,MAAM,WAAW,MAAM;AAAA,EACtC;AAAA,EAEA,OAAO,SAAS,WAAmB,OAA2B;AAC5D,WAAO,EAAE,IAAI,OAAO,WAAW,MAAM;AAAA,EACvC;AAAA,EAEA,OAAO,YAAY,WAAmB,OAA2B;AAC/D,WAAO,EAAE,IAAI,MAAM,WAAW,MAAM;AAAA,EACtC;AAAA,EAEA,OAAO,mBAAmB,WAAmB,OAA2B;AACtE,WAAO,EAAE,IAAI,OAAO,WAAW,MAAM;AAAA,EACvC;AAAA,EAEA,OAAO,SAAS,WAAmB,OAA2B;AAC5D,WAAO,EAAE,IAAI,MAAM,WAAW,MAAM;AAAA,EACtC;AAAA,EAEA,OAAO,gBAAgB,WAAmB,OAA2B;AACnE,WAAO,EAAE,IAAI,OAAO,WAAW,MAAM;AAAA,EACvC;AAAA,EAEA,OAAO,KAAK,WAAmB,SAAgC;AAC7D,WAAO,EAAE,IAAI,QAAQ,WAAW,OAAO,QAAQ;AAAA,EACjD;AAAA,EAEA,OAAO,MAAM,WAAmB,SAAgC;AAC9D,WAAO,EAAE,IAAI,SAAS,WAAW,OAAO,QAAQ;AAAA,EAClD;AAAA,EAEA,OAAO,QAAQ,WAAmB,MAAW,IAAwB;AACnE,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,UAAU;AAAA,QACR,EAAE,IAAI,OAAO,WAAW,OAAO,KAAK;AAAA,QACpC,EAAE,IAAI,OAAO,WAAW,OAAO,GAAG;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAO,OAAO,YAA4C;AACxD,WAAO,EAAE,IAAI,OAAO,UAAU,WAAW;AAAA,EAC3C;AAAA,EAEA,OAAO,MAAM,YAA4C;AACvD,WAAO,EAAE,IAAI,MAAM,UAAU,WAAW;AAAA,EAC1C;AAAA,EAEA,OAAO,IAAI,WAAyC;AAClD,WAAO,EAAE,IAAI,OAAO,UAAU,CAAC,SAAS,EAAE;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,SAAS,WAAmB,OAA8B;AAC/D,WAAO,EAAE,IAAI,YAAY,WAAW,MAAM;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,YAAY,WAAmB,QAAiC;AACrE,WAAO,EAAE,IAAI,eAAe,WAAW,OAAO,OAAO;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,YAAY,WAAmB,QAAiC;AACrE,WAAO,EAAE,IAAI,eAAe,WAAW,OAAO,OAAO;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBA,OAAO,MAAM,WAAmB,OAAe,SAAuC;AACpF,WAAO,EAAE,IAAI,SAAS,WAAW,OAAO,cAAc,QAAQ;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,OAAO,YAAY,WAAmB,OAAe,MAA8B;AACjF,WAAO,EAAE,IAAI,eAAe,WAAW,OAAO,KAAK;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,OAAO,YAAY,WAAmB,QAAgB,eAAuC;AAC3F,WAAO,EAAE,IAAI,eAAe,WAAW,QAAQ,cAAc;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBA,OAAO,WACL,YACA,OACA,SACe;AACf,UAAM,WAAW,WAAW,IAAI,CAAC,UAAU;AAAA,MACzC,IAAI;AAAA,MACJ,WAAW;AAAA,MACX;AAAA,MACA,cAAc,SAAS,QAAQ,IAAI,IAAI,EAAE,OAAO,QAAQ,MAAM,IAAI,EAAE,IAAI;AAAA,IAC1E,EAAE;AACF,WAAO,EAAE,IAAI,MAAM,SAAS;AAAA,EAC9B;AACF;AAEO,SAAS,kBAAkB,WAA0B,MAAoB;AAC9E,MAAI,CAAC,KAAM,QAAO;AAElB,UAAQ,UAAU,IAAI;AAAA,IACpB,KAAK;AACH,cAAQ,UAAU,YAAY,CAAC,GAAG,MAAM,OAAK,kBAAkB,GAAG,IAAI,CAAC;AAAA,IACzE,KAAK;AACH,cAAQ,UAAU,YAAY,CAAC,GAAG,KAAK,OAAK,kBAAkB,GAAG,IAAI,CAAC;AAAA,IACxE,KAAK,OAAO;AACV,YAAM,SAAS,UAAU,YAAY,CAAC,GAAG,CAAC;AAC1C,UAAI,CAAC,MAAO,QAAO;AACnB,aAAO,CAAC,kBAAkB,OAAO,IAAI;AAAA,IACvC;AAAA,EACF;AAGA,MAAI,CAAC,UAAU,UAAW,QAAO;AAEjC,QAAM,QAAQ,KAAK,UAAU,SAAS;AACtC,QAAM,SAAS,UAAU;AAEzB,UAAQ,UAAU,IAAI;AAAA,IACpB,KAAK;AACH,aAAO,UAAU;AAAA,IACnB,KAAK;AACH,aAAO,UAAU;AAAA,IACnB,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,SAAS;AAAA,IAClB,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,SAAS;AAAA,IAClB,KAAK;AACH,UAAI,OAAO,UAAU,YAAY,OAAO,WAAW,SAAU,QAAO;AACpE,YAAM,UAAU,OACb,QAAQ,qBAAqB,MAAM,EACnC,QAAQ,MAAM,IAAI,EAClB,QAAQ,MAAM,GAAG;AACpB,aAAO,IAAI,OAAO,IAAI,OAAO,KAAK,GAAG,EAAE,KAAK,KAAK;AAAA,IACnD,KAAK;AACH,UAAI,OAAO,UAAU,YAAY,OAAO,WAAW,SAAU,QAAO;AACpE,aAAO,IAAI,OAAO,MAAM,EAAE,KAAK,KAAK;AAAA,IACtC,KAAK;AACH,UAAI,OAAO,UAAU,YAAY,OAAO,WAAW,SAAU,QAAO;AACpE,aAAO,MAAM,YAAY,EAAE,SAAS,OAAO,YAAY,CAAC;AAAA,IAC1D,KAAK;AACH,UAAI,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM,EAAG,QAAO;AAChE,aAAO,OAAO;AAAA,QACZ,CAAC,MAAM,OAAO,MAAM,YAAY,MAAM,YAAY,EAAE,SAAS,EAAE,YAAY,CAAC;AAAA,MAC9E;AAAA,IACF,KAAK;AACH,UAAI,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM,EAAG,QAAO;AAChE,aAAO,OAAO;AAAA,QACZ,CAAC,MAAM,OAAO,MAAM,YAAY,MAAM,YAAY,EAAE,SAAS,EAAE,YAAY,CAAC;AAAA,MAC9E;AAAA,IACF;AACE,aAAO;AAAA,EACX;AACF;;;ACjSA,IAAAC,cAAkB;AAOX,IAAM,qBAAqB,cAAE,KAAK;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMM,IAAM,kBAAkB,cAAE,OAAO;AAAA,EACtC,QAAQ,cAAE,MAAM,CAAC,cAAE,OAAO,GAAG,cAAE,OAAO,CAAC,CAAC,EAAE,UAAU,MAAM;AAAA,EAC1D,SAAS,cAAE,MAAM,CAAC,cAAE,OAAO,GAAG,cAAE,OAAO,CAAC,CAAC,EAAE,UAAU,MAAM;AAAA,EAC3D,QAAQ,cAAE,OAAO;AACnB,CAAC;AAEM,IAAM,kBAAkB,cAAE,OAAO;AAAA,EACtC,OAAO,cAAE,IAAI,EAAE,SAAS;AAAA,EACxB,WAAW;AAAA,EACX,OAAO,cAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAEM,IAAM,oBAAoB,cAAE,OAAO;AAAA,EACxC,OAAO,cAAE,IAAI;AAAA,EACb,WAAW;AAAA,EACX,KAAK,cAAE,OAAO;AAAA,EACd,OAAO,cAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAIM,IAAM,oBAAoB,cAAE,KAAK;AAAA,EACtC;AAAA,EAAM;AAAA,EAAO;AAAA,EAAM;AAAA,EAAO;AAAA,EAAM;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAO;AAAA,EAAM;AACvE,CAAC;AAGM,IAAM,sBAAsC,cAAE,KAAK,MAAM,cAAE,OAAO;AAAA,EACvE,IAAI;AAAA,EACJ,WAAW,cAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,OAAO,cAAE,IAAI,EAAE,SAAS;AAAA,EACxB,UAAU,cAAE,MAAM,mBAAmB,EAAE,SAAS;AAClD,CAAC,CAAC;AAIK,IAAM,cAAc,cAAE,OAAO;AAAA,EAClC,OAAO,cAAE,OAAO,cAAE,OAAO,GAAG,cAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAC9C,WAAW,oBAAoB,SAAS;AAAA,EACxC,MAAM,cAAE,OAAO,cAAE,OAAO,GAAG,cAAE,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC,EAAE,SAAS;AAAA,EAC7D,OAAO,cAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,QAAQ,cAAE,OAAO,EAAE,SAAS;AAAA;AAC9B,CAAC;AAWM,IAAM,qBAAqB,cAAE,KAAK,CAAC,SAAS,WAAW,WAAW,MAAM,CAAC;AAEzE,IAAM,yBAAyB,cAAE,OAAO;AAAA,EAC7C,SAAS,cAAE,OAAO;AAAA,EAClB,SAAS,cAAE,MAAM,cAAE,OAAO;AAAA,IACxB,KAAK,cAAE,OAAO;AAAA,IACd,OAAO,cAAE,QAAQ;AAAA,EACnB,CAAC,CAAC;AAAA,EACF,YAAY,cAAE,OAAO,EAAE,SAAS;AAAA,EAChC,SAAS,cAAE,QAAQ,EAAE,SAAS;AAAA;AAAA,EAE9B,cAAc,mBAAmB,SAAS;AAC5C,CAAC;AAEM,IAAM,yBAAyB,cAAE,OAAO;AAAA,EAC7C,MAAM,cAAE,QAAQ,YAAY;AAAA,EAC5B,SAAS;AACX,CAAC;AAIM,IAAM,iBAAiB,cAAE,OAAO;AAAA,EACrC,IAAI,cAAE,OAAO,EAAE,SAAS;AAAA,EACxB,SAAS,cAAE,OAAO;AAAA,EAClB,KAAK,cAAE,OAAO;AAAA;AAAA;AAAA,EAGd,QAAQ,cAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,QAAQ,gBAAgB,SAAS,EAAE,SAAS;AAAA,EAC5C,UAAU,kBAAkB,SAAS,EAAE,SAAS;AAAA,EAChD,OAAO,cAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA;AAAA,EAEtC,cAAc,mBAAmB,SAAS;AAAA,EAC1C,SAAS,cAAE,OAAO,EAAE,SAAS;AAC/B,CAAC;AAIM,IAAM,oBAAoB,cAAE,OAAO;AAAA,EACxC,MAAM,cAAE,QAAQ,MAAM;AAAA,EACtB,OAAO,cAAE,OAAO;AAClB,CAAC;AAEM,IAAM,wBAAwB,cAAE,OAAO;AAAA,EAC5C,MAAM,cAAE,QAAQ,WAAW;AAAA,EAC3B,SAAS,cAAE,OAAO;AAAA,IAChB,SAAS,cAAE,OAAO;AAAA,IAClB,SAAS,cAAE,OAAO;AAAA,IAClB,OAAO;AAAA,EACT,CAAC;AACH,CAAC;AAEM,IAAM,0BAA0B,cAAE,OAAO;AAAA,EAC9C,MAAM,cAAE,QAAQ,aAAa;AAAA,EAC7B,SAAS,cAAE,OAAO;AAAA,IAChB,SAAS,cAAE,OAAO;AAAA,EACpB,CAAC;AACH,CAAC;AAEM,IAAM,wBAAwB,cAAE,OAAO;AAAA,EAC5C,MAAM,cAAE,QAAQ,WAAW;AAAA,EAC3B,SAAS;AACX,CAAC;AAEM,IAAM,uBAAuB,cAAE,OAAO;AAAA,EAC3C,MAAM,cAAE,QAAQ,UAAU;AAAA,EAC1B,SAAS,cAAE,OAAO;AAAA,IAChB,KAAK,cAAE,MAAM,cAAc;AAAA;AAAA,IAE3B,cAAc,mBAAmB,SAAS;AAAA,IAC1C,SAAS,cAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,CAAC;AACH,CAAC;AAEM,IAAM,wBAAwB,cAAE,OAAO;AAAA,EAC5C,MAAM,cAAE,QAAQ,WAAW;AAAA,EAC3B,SAAS,cAAE,OAAO;AAAA,EAClB,mBAAmB,cAAE,OAAO,EAAE,SAAS;AACzC,CAAC;AAEM,IAAM,4BAA4B,cAAE,OAAO;AAAA,EAChD,MAAM,cAAE,QAAQ,gBAAgB;AAAA,EAChC,SAAS,cAAE,OAAO;AAAA,IAChB,SAAS,cAAE,OAAO;AAAA,IAClB,UAAU,cAAE,OAAO;AAAA,IACnB,WAAW;AAAA,EACb,CAAC;AACH,CAAC;AAEM,IAAM,+BAA+B,cAAE,OAAO;AAAA,EACnD,MAAM,cAAE,QAAQ,mBAAmB;AAAA,EACnC,SAAS,cAAE,OAAO;AAAA,IAChB,SAAS,cAAE,OAAO;AAAA,IAClB,MAAM,cAAE,OAAO;AAAA,IACf,SAAS,cAAE,OAAO,cAAE,OAAO,GAAG,cAAE,OAAO,CAAC;AAAA,EAC1C,CAAC;AACH,CAAC;AAEM,IAAM,4BAA4B,cAAE,OAAO;AAAA,EAChD,MAAM,cAAE,QAAQ,gBAAgB;AAAA,EAChC,SAAS,cAAE,OAAO;AAAA,IAChB,SAAS,cAAE,OAAO;AAAA,IAClB,MAAM,cAAE,OAAO;AAAA,IACf,SAAS,cAAE,MAAM,cAAE,OAAO;AAAA,MACxB,KAAK,cAAE,OAAO;AAAA,MACd,QAAQ;AAAA,IACV,CAAC,CAAC;AAAA,EACJ,CAAC;AACH,CAAC;AAEM,IAAM,+BAA+B,cAAE,OAAO;AAAA,EACnD,MAAM,cAAE,QAAQ,mBAAmB;AAAA,EACnC,SAAS,cAAE,OAAO;AAAA,IAChB,SAAS,cAAE,OAAO;AAAA,IAClB,MAAM,cAAE,OAAO;AAAA,EACjB,CAAC;AACH,CAAC;AAEM,IAAM,oBAAoB,cAAE,OAAO;AAAA,EACxC,MAAM,cAAE,QAAQ,cAAc;AAAA,EAC9B,SAAS,cAAE,OAAO;AAAA,IAChB,WAAW,cAAE,OAAO;AAAA,IACpB,MAAM,cAAE,OAAO;AAAA,IACf,KAAK,cAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,CAAC;AACH,CAAC;AAEM,IAAM,oBAAoB,cAAE,OAAO;AAAA,EACxC,MAAM,cAAE,QAAQ,cAAc;AAAA,EAC9B,SAAS,cAAE,OAAO;AAAA,IAChB,WAAW,cAAE,OAAO,EAAE,SAAS;AAAA,IAC/B,MAAM,cAAE,OAAO;AAAA,IACf,cAAc,cAAE,OAAO;AAAA,EACzB,CAAC;AACH,CAAC;AAIM,IAAM,iBAAiB,cAAE,OAAO;AAAA,EACrC,MAAM,cAAE,QAAQ,WAAW;AAAA,EAC3B,SAAS,cAAE,OAAO;AAAA,IAChB,OAAO,cAAE,OAAO;AAAA,EAClB,CAAC;AACH,CAAC;AAEM,IAAM,mBAAmB,cAAE,OAAO;AAAA,EACvC,MAAM,cAAE,QAAQ,aAAa;AAAA,EAC7B,SAAS,cAAE,OAAO;AAAA,IAChB,OAAO,cAAE,OAAO;AAAA,EAClB,CAAC;AACH,CAAC;AAEM,IAAM,iBAAiB,cAAE,OAAO;AAAA,EACrC,MAAM,cAAE,QAAQ,WAAW;AAAA,EAC3B,SAAS,cAAE,OAAO;AAAA,IAChB,OAAO,cAAE,OAAO;AAAA,IAChB,MAAM,cAAE,IAAI;AAAA,EACd,CAAC;AACH,CAAC;AAEM,IAAM,0BAA0B,cAAE,OAAO;AAAA,EAC9C,MAAM,cAAE,QAAQ,eAAe;AAAA,EAC/B,SAAS,cAAE,OAAO;AAAA,IAChB,OAAO,cAAE,OAAO;AAAA,IAChB,MAAM,cAAE,IAAI;AAAA,IACZ,aAAa,cAAE,OAAO,EAAE,SAAS;AAAA,IACjC,WAAW,cAAE,OAAO;AAAA,EACtB,CAAC;AACH,CAAC;AAIM,IAAM,6BAA6B,cAAE,OAAO;AAAA,EACjD,GAAG,cAAE,OAAO,cAAE,OAAO,GAAG,cAAE,OAAO,CAAC;AAAA;AAAA,EAClC,GAAG,cAAE,OAAO,cAAE,OAAO,GAAG,cAAE,OAAO,CAAC;AAAA;AACpC,CAAC;AAEM,IAAM,uBAAuB,cAAE,OAAO;AAAA,EAC3C,MAAM,cAAE,QAAQ,iBAAiB;AAAA,EACjC,SAAS,cAAE,OAAO;AAAA,IAChB,MAAM,cAAE,OAAO;AAAA,EACjB,CAAC;AACH,CAAC;AAEM,IAAM,oBAAoB,cAAE,OAAO;AAAA,EACxC,MAAM,cAAE,QAAQ,cAAc;AAAA,EAC9B,SAAS,cAAE,OAAO;AAAA,IAChB,MAAM,cAAE,OAAO;AAAA,IACf,OAAO;AAAA,EACT,CAAC;AACH,CAAC;AAEM,IAAM,wBAAwB,cAAE,OAAO;AAAA,EAC5C,MAAM,cAAE,QAAQ,kBAAkB;AAAA,EAClC,SAAS,cAAE,OAAO;AAAA,IAChB,MAAM,cAAE,OAAO;AAAA,IACf,OAAO;AAAA,EACT,CAAC;AACH,CAAC;AAEM,IAAM,sBAAsB,cAAE,OAAO;AAAA,EAC1C,MAAM,cAAE,QAAQ,gBAAgB;AAAA,EAChC,SAAS,cAAE,OAAO;AAAA,IAChB,MAAM,cAAE,OAAO;AAAA,IACf,OAAO;AAAA,EACT,CAAC;AACH,CAAC;AAIM,IAAM,oBAAoB,cAAE,OAAO;AAAA,EACxC,MAAM,cAAE,QAAQ,MAAM;AAAA,EACtB,WAAW,cAAE,OAAO;AAAA;AACtB,CAAC;AAEM,IAAM,oBAAoB,cAAE,OAAO;AAAA,EACxC,MAAM,cAAE,QAAQ,MAAM;AAAA,EACtB,WAAW,cAAE,OAAO;AAAA;AAAA,EACpB,YAAY,cAAE,OAAO;AAAA;AACvB,CAAC;AASM,IAAM,qBAAqB,cAAE,OAAO;AAAA,EACzC,MAAM,cAAE,QAAQ,OAAO;AAAA,EACvB,OAAO,cAAE,OAAO;AAAA,EAChB,MAAM,cAAE,WAAW,UAAU;AAC/B,CAAC;AAQM,IAAM,sBAAsB,cAAE,OAAO;AAAA,EAC1C,MAAM,cAAE,QAAQ,iBAAiB;AAAA,EACjC,SAAS,cAAE,OAAO;AAAA,EAClB,UAAU,cAAE,OAAO;AAAA,EACnB,cAAc,cAAE,OAAO,cAAE,OAAO,GAAG,cAAE,OAAO,CAAC;AAAA;AAAA,EAC7C,mBAAmB,cAAE,OAAO,EAAE,SAAS;AACzC,CAAC;AAKM,IAAM,0BAA0B,cAAE,OAAO;AAAA,EAC9C,MAAM,cAAE,QAAQ,sBAAsB;AAAA,EACtC,SAAS,cAAE,OAAO;AAAA,IAChB,SAAS,cAAE,OAAO;AAAA,IAClB,UAAU,cAAE,OAAO;AAAA,IACnB,WAAW;AAAA,EACb,CAAC;AACH,CAAC;AAKM,IAAM,6BAA6B,cAAE,OAAO;AAAA,EACjD,MAAM,cAAE,QAAQ,yBAAyB;AAAA,EACzC,SAAS,cAAE,OAAO;AAAA,IAChB,SAAS,cAAE,OAAO;AAAA,IAClB,MAAM,cAAE,OAAO;AAAA,IACf,SAAS,cAAE,OAAO,cAAE,OAAO,GAAG,cAAE,OAAO,CAAC;AAAA,EAC1C,CAAC;AACH,CAAC;AAKM,IAAM,6BAA6B,cAAE,OAAO;AAAA,EACjD,MAAM,cAAE,QAAQ,yBAAyB;AAAA,EACzC,SAAS,cAAE,OAAO;AAAA,IAChB,SAAS,cAAE,OAAO;AAAA,IAClB,MAAM,cAAE,OAAO;AAAA,EACjB,CAAC;AACH,CAAC;AAKM,IAAM,0BAA0B,cAAE,OAAO;AAAA,EAC9C,MAAM,cAAE,QAAQ,sBAAsB;AAAA,EACtC,SAAS,cAAE,OAAO;AAAA,IAChB,SAAS,cAAE,OAAO;AAAA,IAClB,MAAM,cAAE,OAAO;AAAA,IACf,SAAS,cAAE,MAAM,cAAE,OAAO;AAAA,MACxB,KAAK,cAAE,OAAO;AAAA,MACd,SAAS,cAAE,MAAM,iBAAiB;AAAA,MAClC,YAAY,cAAE,MAAM,cAAE,OAAO,CAAC;AAAA;AAAA,IAChC,CAAC,CAAC;AAAA,EACJ,CAAC;AACH,CAAC;AAKM,IAAM,yBAAyB,cAAE,OAAO;AAAA,EAC7C,MAAM,cAAE,QAAQ,oBAAoB;AAAA,EACpC,SAAS,cAAE,OAAO;AAAA,IAChB,SAAS,cAAE,OAAO;AAAA,IAClB,MAAM,cAAE,MAAM,cAAE,OAAO,CAAC;AAAA,EAC1B,CAAC;AACH,CAAC;AAKM,IAAM,0BAA0B,cAAE,OAAO;AAAA,EAC9C,MAAM,cAAE,QAAQ,qBAAqB;AAAA,EACrC,SAAS,cAAE,OAAO;AAAA,IAChB,SAAS,cAAE,OAAO;AAAA,IAClB,SAAS,cAAE,MAAM,cAAE,OAAO;AAAA,MACxB,KAAK,cAAE,OAAO;AAAA,MACd,SAAS,cAAE,MAAM,iBAAiB;AAAA,MAClC,YAAY,cAAE,MAAM,cAAE,OAAO,CAAC;AAAA,IAChC,CAAC,CAAC;AAAA,EACJ,CAAC;AACH,CAAC;AAKM,IAAM,sBAAsB,cAAE,OAAO;AAAA,EAC1C,MAAM,cAAE,QAAQ,iBAAiB;AAAA,EACjC,SAAS,cAAE,OAAO;AAAA,IAChB,SAAS,cAAE,OAAO;AAAA,IAClB,SAAS,cAAE,MAAM,cAAE,OAAO;AAAA,MACxB,KAAK,cAAE,OAAO;AAAA,MACd,SAAS,cAAE,MAAM,iBAAiB;AAAA,MAClC,YAAY,cAAE,MAAM,cAAE,OAAO,CAAC;AAAA,IAChC,CAAC,CAAC;AAAA,EACJ,CAAC;AACH,CAAC;AAOM,IAAM,4BAA4B,cAAE,OAAO;AAAA,EAChD,MAAM,cAAE,QAAQ,uBAAuB;AAAA,EACvC,SAAS,cAAE,OAAO;AAAA,IAChB,gBAAgB,cAAE,OAAO,EAAE,SAAS;AAAA,EACtC,CAAC,EAAE,SAAS;AACd,CAAC;AAOM,IAAM,uBAAuB,cAAE,OAAO;AAAA,EAC3C,MAAM,cAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC/B,MAAM,cAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAK;AAAA,EACjC,MAAM,cAAE,QAAQ,EAAE,SAAS;AAC7B,CAAC;AAKM,IAAM,4BAA4B,cAAE,OAAO;AAAA,EAChD,MAAM,cAAE,QAAQ,eAAe;AAAA,EAC/B,WAAW,cAAE,OAAO;AAAA,EACpB,SAAS,cAAE,OAAO;AAAA,EAClB,KAAK,cAAE,OAAO;AAAA,EACd,WAAW;AACb,CAAC;AAKM,IAAM,iCAAiC,cAAE,OAAO;AAAA,EACrD,MAAM,cAAE,QAAQ,qBAAqB;AAAA,EACrC,WAAW,cAAE,OAAO;AAAA,EACpB,SAAS,cAAE,OAAO;AAAA,EAClB,MAAM,cAAE,MAAM,cAAE,OAAO,CAAC;AAAA,EACxB,WAAW;AACb,CAAC;AAKM,IAAM,6BAA6B,cAAE,OAAO;AAAA,EACjD,MAAM,cAAE,QAAQ,wBAAwB;AAAA,EACxC,WAAW,cAAE,OAAO;AAAA,EACpB,SAAS,cAAE,QAAQ;AAAA,EACnB,QAAQ,cAAE,QAAQ,EAAE,SAAS;AAAA,EAC7B,UAAU,cAAE,QAAQ,EAAE,SAAS;AAAA,EAC/B,OAAO,cAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAKM,IAAM,8BAA8B,cAAE,OAAO;AAAA,EAClD,SAAS,cAAE,QAAQ;AAAA,EACnB,QAAQ,cAAE,QAAQ,EAAE,SAAS;AAAA,EAC7B,UAAU,cAAE,QAAQ,EAAE,SAAS;AAAA,EAC/B,OAAO,cAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAKM,IAAM,kCAAkC,cAAE,OAAO;AAAA,EACtD,MAAM,cAAE,QAAQ,8BAA8B;AAAA,EAC9C,WAAW,cAAE,OAAO;AAAA,EACpB,SAAS,cAAE,OAAO,cAAE,OAAO,GAAG,2BAA2B;AAC3D,CAAC;AAOM,IAAM,yBAAyB,cAAE,KAAK,CAAC,OAAO,UAAU,QAAQ,CAAC;AAKjE,IAAM,yBAAyB,cAAE,OAAO;AAAA,EAC7C,UAAU,cAAE,OAAO;AAAA;AAAA,EACnB,MAAM;AAAA,EACN,SAAS,cAAE,OAAO;AAAA,EAClB,KAAK,cAAE,OAAO;AAAA,EACd,OAAO,cAAE,QAAQ,EAAE,SAAS;AAAA,EAC5B,eAAe,cAAE,QAAQ,EAAE,SAAS;AAAA,EACpC,WAAW;AAAA,EACX,QAAQ,cAAE,OAAO;AAAA,EACjB,UAAU,cAAE,OAAO,cAAE,OAAO,GAAG,cAAE,QAAQ,CAAC,EAAE,SAAS;AACvD,CAAC;AAKM,IAAM,gCAAgC,cAAE,OAAO;AAAA,EACpD,MAAM,cAAE,QAAQ,mBAAmB;AAAA,EACnC,WAAW,cAAE,OAAO;AAAA,EACpB,cAAc,cAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAClC,SAAS,cAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,OAAO,cAAE,MAAM,sBAAsB,EAAE,SAAS;AAClD,CAAC;AAKM,IAAM,kCAAkC,cAAE,OAAO;AAAA,EACtD,MAAM,cAAE,QAAQ,qBAAqB;AAAA,EACrC,gBAAgB,cAAE,OAAO;AAC3B,CAAC;AAKM,IAAM,4BAA4B,cAAE,OAAO;AAAA,EAChD,MAAM,cAAE,QAAQ,eAAe;AAAA,EAC/B,OAAO;AACT,CAAC;AAKM,IAAM,2BAA2B,cAAE,OAAO;AAAA,EAC/C,MAAM,cAAE,QAAQ,cAAc;AAAA,EAC9B,WAAW,cAAE,OAAO;AAAA,EACpB,cAAc,cAAE,OAAO;AAAA,EACvB,OAAO,cAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,SAAS,cAAE,OAAO,EAAE,SAAS;AAC/B,CAAC;AAKM,IAAM,4BAA4B,cAAE,OAAO;AAAA,EAChD,MAAM,cAAE,QAAQ,uBAAuB;AAAA,EACvC,WAAW,cAAE,OAAO;AAAA,EACpB,QAAQ,cAAE,MAAM,sBAAsB;AAAA,EACtC,SAAS,cAAE,QAAQ;AACrB,CAAC;AAOM,IAAM,sBAAsB,cAAE,OAAO;AAAA,EAC1C,OAAO,cAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,UAAU,cAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,OAAO,cAAE,OAAO,cAAE,OAAO,GAAG,cAAE,OAAO,CAAC,EAAE,SAAS;AACnD,CAAC;AAKM,IAAM,sBAAsB,cAAE,OAAO;AAAA,EAC1C,WAAW,cAAE,OAAO;AAAA,EACpB,SAAS,cAAE,OAAO;AAAA,EAClB,OAAO,cAAE,OAAO;AAAA,EAChB,SAAS,oBAAoB,SAAS;AACxC,CAAC;AAEM,IAAM,sBAAsB,cAAE,OAAO;AAAA,EAC1C,MAAM,cAAE,QAAQ,QAAQ;AAAA,EACxB,SAAS;AACX,CAAC;AAKM,IAAM,0BAA0B,cAAE,OAAO;AAAA,EAC9C,WAAW,cAAE,OAAO;AAAA,EACpB,SAAS,cAAE,MAAM,cAAE,OAAO;AAAA,IACxB,KAAK,cAAE,OAAO;AAAA,IACd,OAAO,cAAE,QAAQ;AAAA,IACjB,OAAO,cAAE,OAAO;AAAA,IAChB,cAAc,cAAE,MAAM,cAAE,OAAO,CAAC;AAAA,EAClC,CAAC,CAAC;AAAA,EACF,YAAY,cAAE,OAAO;AAAA,EACrB,OAAO,cAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAEM,IAAM,0BAA0B,cAAE,OAAO;AAAA,EAC9C,MAAM,cAAE,QAAQ,aAAa;AAAA,EAC7B,SAAS;AACX,CAAC;AAUM,IAAM,yBAAyB,cAAE,KAAK,CAAC,SAAS,UAAU,OAAO,CAAC;AAKlE,IAAM,yBAAyB,cAAE,OAAO;AAAA,EAC7C,gBAAgB,cAAE,OAAO;AAAA,EACzB,SAAS,cAAE,OAAO;AAAA,EAClB,OAAO,cAAE,OAAO;AAAA,EAChB,SAAS,oBAAoB,SAAS;AACxC,CAAC;AAEM,IAAM,yBAAyB,cAAE,OAAO;AAAA,EAC7C,MAAM,cAAE,QAAQ,YAAY;AAAA,EAC5B,SAAS;AACX,CAAC;AAKM,IAAM,4BAA4B,cAAE,OAAO;AAAA,EAChD,gBAAgB,cAAE,OAAO;AAAA,EACzB,KAAK,cAAE,OAAO;AAAA,EACd,OAAO,cAAE,QAAQ;AAAA,EACjB,OAAO,cAAE,OAAO;AAAA,EAChB,cAAc,cAAE,MAAM,cAAE,OAAO,CAAC;AAAA,EAChC,MAAM;AACR,CAAC;AAEM,IAAM,4BAA4B,cAAE,OAAO;AAAA,EAChD,MAAM,cAAE,QAAQ,eAAe;AAAA,EAC/B,SAAS;AACX,CAAC;AAKM,IAAM,2BAA2B,cAAE,OAAO;AAAA,EAC/C,gBAAgB,cAAE,OAAO;AAC3B,CAAC;AAEM,IAAM,2BAA2B,cAAE,OAAO;AAAA,EAC/C,MAAM,cAAE,QAAQ,cAAc;AAAA,EAC9B,SAAS;AACX,CAAC;AAOM,IAAM,yBAAyB,cAAE,OAAO;AAAA,EAC7C,MAAM,cAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAC/B,MAAM,cAAE,OAAO,EAAE,IAAI,GAAK;AAAA,EAC1B,UAAU,cAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,EACpD,YAAY,cAAE,OAAO,EAAE,SAAS;AAClC,CAAC;AAKM,IAAM,gCAAgC,cAAE,OAAO;AAAA,EACpD,MAAM,cAAE,QAAQ,mBAAmB;AAAA,EACnC,WAAW,cAAE,OAAO;AAAA,EACpB,SAAS,cAAE,OAAO;AAAA,EAClB,UAAU;AACZ,CAAC;AAKM,IAAM,iCAAiC,cAAE,OAAO;AAAA,EACrD,MAAM,cAAE,QAAQ,4BAA4B;AAAA,EAC5C,WAAW,cAAE,OAAO;AAAA,EACpB,SAAS,cAAE,QAAQ;AAAA,EACnB,OAAO,cAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAKM,IAAM,kCAAkC,cAAE,OAAO;AAAA,EACtD,MAAM,cAAE,QAAQ,qBAAqB;AAAA,EACrC,WAAW,cAAE,OAAO;AAAA,EACpB,SAAS,cAAE,OAAO;AAAA,EAClB,cAAc,cAAE,OAAO;AACzB,CAAC;AAKM,IAAM,mCAAmC,cAAE,OAAO;AAAA,EACvD,MAAM,cAAE,QAAQ,8BAA8B;AAAA,EAC9C,WAAW,cAAE,OAAO;AAAA,EACpB,SAAS,cAAE,QAAQ;AAAA,EACnB,OAAO,cAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAKM,IAAM,6BAA6B,cAAE,OAAO;AAAA,EACjD,MAAM,cAAE,QAAQ,gBAAgB;AAAA,EAChC,SAAS,cAAE,OAAO;AAAA,EAClB,KAAK,cAAE,OAAO;AAAA,EACd,gBAAgB,cAAE,QAAQ;AAAA,EAC1B,QAAQ,cAAE,OAAO;AAAA,EACjB,WAAW;AACb,CAAC;AAKM,IAAM,6BAA6B,cAAE,OAAO;AAAA,EACjD,MAAM,cAAE,QAAQ,gBAAgB;AAAA,EAChC,WAAW,cAAE,OAAO;AAAA,EACpB,SAAS,cAAE,OAAO,EAAE,SAAS;AAC/B,CAAC;AAKM,IAAM,8BAA8B,cAAE,OAAO;AAAA,EAClD,MAAM,cAAE,QAAQ,yBAAyB;AAAA,EACzC,WAAW,cAAE,OAAO;AAAA,EACpB,WAAW,cAAE,MAAM,cAAE,OAAO;AAAA,IAC1B,SAAS,cAAE,OAAO;AAAA,IAClB,MAAM,cAAE,OAAO;AAAA,IACf,UAAU,cAAE,OAAO,EAAE,SAAS;AAAA,IAC9B,YAAY,cAAE,OAAO,EAAE,SAAS;AAAA,EAClC,CAAC,CAAC;AACJ,CAAC;AAOM,IAAM,iBAAiB,cAAE,OAAO;AAAA,EACrC,MAAM,cAAE,OAAO;AAAA,EACf,SAAS,cAAE,QAAQ;AAAA,EACnB,eAAe;AAAA,EACf,OAAO,cAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAMM,IAAM,qBAAqB,cAAE,OAAO;AAAA,EACzC,MAAM,cAAE,QAAQ,QAAQ;AAAA,EACxB,SAAS,cAAE,OAAO;AAAA;AAAA,IAEhB,QAAQ,cAAE,OAAO;AAAA;AAAA,IAEjB,eAAe,mBAAmB,SAAS;AAAA;AAAA,IAE3C,SAAS,cAAE,MAAM,cAAc,EAAE,SAAS;AAAA,EAC5C,CAAC;AACH,CAAC;AAKM,IAAM,0BAA0B,cAAE,OAAO;AAAA,EAC9C,MAAM,cAAE,QAAQ,aAAa;AAAA,EAC7B,SAAS,cAAE,OAAO;AAAA;AAAA,IAEhB,MAAM,cAAE,OAAO;AAAA;AAAA,IAEf,QAAQ,cAAE,OAAO;AAAA;AAAA,IAEjB,MAAM,cAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,CAAC;AACH,CAAC;AAQM,IAAM,kCAAkC,cAAE,OAAO;AAAA;AAAA,EAEtD,gBAAgB,cAAE,OAAO;AAAA;AAAA,EAEzB,mBAAmB,cAAE,OAAO;AAAA;AAAA,EAE5B,SAAS,cAAE,OAAO;AAAA;AAAA,EAElB,MAAM,cAAE,KAAK,CAAC,UAAU,OAAO,CAAC;AAAA;AAAA;AAAA,EAIhC,aAAa,cAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAEjC,eAAe,cAAE,OAAO;AAAA,IACtB,OAAO,cAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,IAC5C,UAAU,cAAE,OAAO,EAAE,SAAS;AAAA,IAC9B,OAAO,cAAE,OAAO,cAAE,OAAO,GAAG,cAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACnD,CAAC,EAAE,SAAS;AAAA;AAAA;AAAA,EAIZ,gBAAgB,cAAE,IAAI,EAAE,SAAS;AAAA;AAAA,EAEjC,WAAW,cAAE,OAAO,cAAE,OAAO,GAAG,cAAE,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC,EAAE,SAAS;AACpE,CAAC;AAEM,IAAM,kCAAkC,cAAE,OAAO;AAAA,EACtD,MAAM,cAAE,QAAQ,sBAAsB;AAAA,EACtC,SAAS;AACX,CAAC;AAMM,IAAM,6BAA6B,cAAE,OAAO;AAAA;AAAA,EAEjD,gBAAgB,cAAE,OAAO;AAAA;AAAA,EAEzB,QAAQ,cAAE,OAAO;AAAA;AAAA,EAEjB,SAAS,cAAE,QAAQ;AAAA;AAAA,EAEnB,OAAO,cAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAE3B,gBAAgB,cAAE,MAAM,cAAE,OAAO;AAAA,IAC/B,KAAK,cAAE,OAAO;AAAA,IACd,OAAO,cAAE,QAAQ;AAAA,IACjB,OAAO,cAAE,OAAO,EAAE,SAAS;AAAA,IAC3B,cAAc,cAAE,MAAM,cAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EAC7C,CAAC,CAAC,EAAE,SAAS;AAAA;AAAA,EAEb,WAAW,cAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AACrD,CAAC;AAEM,IAAM,6BAA6B,cAAE,OAAO;AAAA,EACjD,MAAM,cAAE,QAAQ,iBAAiB;AAAA,EACjC,SAAS;AACX,CAAC;AAMM,IAAM,gCAAgC,cAAE,OAAO;AAAA;AAAA,EAEpD,gBAAgB,cAAE,OAAO;AAAA;AAAA,EAEzB,cAAc,cAAE,OAAO;AAAA;AAAA,EAEvB,KAAK,cAAE,OAAO;AAAA;AAAA,EAEd,OAAO,cAAE,QAAQ;AAAA;AAAA,EAEjB,OAAO,cAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAE3B,cAAc,cAAE,MAAM,cAAE,OAAO,CAAC,EAAE,SAAS;AAAA;AAAA,EAE3C,YAAY,cAAE,KAAK,CAAC,SAAS,UAAU,OAAO,CAAC;AAAA;AAAA,EAE/C,WAAW,cAAE,OAAO;AACtB,CAAC;AAEM,IAAM,gCAAgC,cAAE,OAAO;AAAA,EACpD,MAAM,cAAE,QAAQ,oBAAoB;AAAA,EACpC,SAAS;AACX,CAAC;AAMM,IAAM,oCAAoC,cAAE,OAAO;AAAA;AAAA,EAExD,gBAAgB,cAAE,OAAO;AAC3B,CAAC;AAEM,IAAM,oCAAoC,cAAE,OAAO;AAAA,EACxD,MAAM,cAAE,QAAQ,wBAAwB;AAAA,EACxC,SAAS;AACX,CAAC;AAIM,IAAM,gBAAgB,cAAE,mBAAmB,QAAQ;AAAA,EACxD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAoEM,IAAM,gCAAgC,cAAE,OAAO;AAAA;AAAA,EAEpD,WAAW,cAAE,OAAO;AAAA;AAAA,EAEpB,SAAS,cAAE,OAAO;AAAA;AAAA,EAElB,OAAO,cAAE,OAAO;AAAA;AAAA,EAEhB,SAAS,cAAE,OAAO;AAAA;AAAA,IAEhB,OAAO,cAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,GAAI;AAAA;AAAA,IAE3C,UAAU,cAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAE9B,OAAO,cAAE,OAAO,cAAE,OAAO,GAAG,cAAE,OAAO,CAAC,EAAE,SAAS;AAAA;AAAA,IAEjD,qBAAqB,cAAE,QAAQ,EAAE,SAAS;AAAA;AAAA,IAE1C,YAAY,cAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAEhC,UAAU,cAAE,OAAO,EAAE,SAAS;AAAA,EAChC,CAAC;AAAA;AAAA,EAED,WAAW,cAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAClD,CAAC;AAEM,IAAM,gCAAgC,cAAE,OAAO;AAAA,EACpD,MAAM,cAAE,QAAQ,oBAAoB;AAAA,EACpC,SAAS;AACX,CAAC;AAKM,IAAM,iCAAiC,cAAE,OAAO;AAAA;AAAA,EAErD,WAAW,cAAE,OAAO;AAAA;AAAA,EAEpB,QAAQ,cAAE,OAAO;AAAA;AAAA,EAEjB,SAAS,cAAE,MAAM,cAAE,OAAO;AAAA,IACxB,KAAK,cAAE,OAAO;AAAA,IACd,OAAO,cAAE,QAAQ;AAAA,IACjB,OAAO,cAAE,OAAO;AAAA,IAChB,cAAc,cAAE,MAAM,cAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EAC7C,CAAC,CAAC;AAAA;AAAA,EAEF,WAAW,cAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA;AAAA,EAExC,iBAAiB,cAAE,OAAO,EAAE,YAAY;AAAA;AAAA,EAExC,OAAO,cAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAEM,IAAM,iCAAiC,cAAE,OAAO;AAAA,EACrD,MAAM,cAAE,QAAQ,qBAAqB;AAAA,EACrC,SAAS;AACX,CAAC;AAKM,IAAM,sCAAsC,cAAE,OAAO;AAAA,EAC1D,gBAAgB,cAAE,OAAO;AAAA,EACzB,SAAS,cAAE,OAAO;AAAA,EAClB,OAAO,cAAE,OAAO;AAAA,EAChB,SAAS,oBAAoB,SAAS;AACxC,CAAC;AAEM,IAAM,sCAAsC,cAAE,OAAO;AAAA,EAC1D,MAAM,cAAE,QAAQ,0BAA0B;AAAA,EAC1C,SAAS;AACX,CAAC;AAKM,IAAM,wCAAwC,cAAE,OAAO;AAAA,EAC5D,gBAAgB,cAAE,OAAO;AAC3B,CAAC;AAEM,IAAM,wCAAwC,cAAE,OAAO;AAAA,EAC5D,MAAM,cAAE,QAAQ,4BAA4B;AAAA,EAC5C,SAAS;AACX,CAAC;AAKM,IAAM,mCAAmC,cAAE,OAAO;AAAA,EACvD,gBAAgB,cAAE,OAAO;AAAA,EACzB,QAAQ,cAAE,OAAO;AAAA,EACjB,KAAK,cAAE,OAAO;AAAA,EACd,OAAO,cAAE,QAAQ;AAAA,EACjB,OAAO,cAAE,OAAO;AAAA,EAChB,cAAc,cAAE,MAAM,cAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EAC3C,MAAM;AACR,CAAC;AAEM,IAAM,mCAAmC,cAAE,OAAO;AAAA,EACvD,MAAM,cAAE,QAAQ,uBAAuB;AAAA,EACvC,SAAS;AACX,CAAC;;;AC9lCM,IAAK,eAAL,kBAAKC,kBAAL;AAQL,EAAAA,cAAA,qBAAkB;AAQlB,EAAAA,cAAA,YAAS;AAQT,EAAAA,cAAA,aAAU;AAQV,EAAAA,cAAA,gBAAa;AAQb,EAAAA,cAAA,eAAY;AAxCF,SAAAA;AAAA,GAAA;AA8CL,IAAM,gCAAgC;AAwEtC,IAAM,sBAA+C;AAAA,EAC1D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AASO,SAAS,uBACd,UACA,QACS;AACT,QAAM,cAAc,oBAAoB,QAAQ,MAAM;AACtD,QAAM,gBAAgB,KAAK;AAAA,IACzB,GAAG,MAAM,KAAK,QAAQ,EAAE,IAAI,CAAC,MAAM,oBAAoB,QAAQ,CAAC,CAAC;AAAA,EACnE;AACA,SAAO,iBAAiB;AAC1B;AAQO,SAAS,4BACd,UACc;AACd,WAAS,IAAI,oBAAoB,SAAS,GAAG,KAAK,GAAG,KAAK;AACxD,QAAI,SAAS,IAAI,oBAAoB,CAAC,CAAC,GAAG;AACxC,aAAO,oBAAoB,CAAC;AAAA,IAC9B;AAAA,EACF;AACA,SAAO;AACT;;;ACvDO,IAAM,iCAAuD;AAAA,EAClE,uBAAuB;AAAA,EACvB,qBAAqB;AAAA,EACrB,uBAAuB;AAAA,EACvB,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,sBAAsB;AACxB;AAeO,IAAM,kCAAyD;AAAA,EACpE,cAAc;AAAA,EACd,sBAAsB;AAAA,EACtB,mBAAmB;AACrB;AAgBO,IAAM,iCAAuD;AAAA,EAClE,kBAAkB;AAAA,EAClB,gBAAgB;AAClB;AAuDO,IAAK,iBAAL,kBAAKC,oBAAL;AACL,EAAAA,gBAAA,YAAS;AACT,EAAAA,gBAAA,eAAY;AACZ,EAAAA,gBAAA,UAAO;AACP,EAAAA,gBAAA,YAAS;AAJC,SAAAA;AAAA,GAAA;AAiCL,IAAM,2BAA4C;AAAA,EACvD,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,mBAAmB;AAAA;AAAA,EACnB,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,mBAAmB;AACrB;AAmFO,IAAK,mBAAL,kBAAKC,sBAAL;AAEL,EAAAA,kBAAA,YAAS;AAET,EAAAA,kBAAA,YAAS;AAET,EAAAA,kBAAA,cAAW;AAND,SAAAA;AAAA,GAAA;AAyCL,IAAM,6BAAgD;AAAA,EAC3D,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,YAAY;AACd;AAkFO,IAAM,kBAAkB;AACxB,IAAM,uBAAuB;;;AC9cpC,0BAAkB;;;ACaX,SAAS,kBAAqB,GAAM,GAAc;AACvD,MAAI,IAAI,EAAG,QAAO;AAClB,MAAI,IAAI,EAAG,QAAO;AAClB,SAAO;AACT;;;ADPO,IAAM,YAAN,MAAM,WAAgB;AAAA,EAI3B,YAAY,YAA4B;AACtC,SAAK,aAAa,cAAe;AACjC,SAAK,OAAO,IAAI,oBAAAC,QAAY,QAAW,KAAK,UAAU;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,KAAQ,OAAgB;AAC1B,SAAK,KAAK,IAAI,KAAK,KAAK;AACxB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,KAAuB;AACzB,WAAO,KAAK,KAAK,IAAI,GAAG;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,KAAiB;AACtB,WAAO,KAAK,KAAK,OAAO,GAAG;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,KAAiB;AACnB,WAAO,KAAK,KAAK,IAAI,GAAG;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,UAAmB;AACrB,WAAO,KAAK,KAAK,SAAS;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAwB;AACtB,WAAO,KAAK,KAAK,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAwB;AACtB,WAAO,KAAK,KAAK,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,CAAC,MAAM,MAAS,IAAO,UAAwB,CAAC,GAA6B;AAC3E,UAAM,EAAE,gBAAgB,MAAM,cAAc,MAAM,IAAI;AAGtD,QAAI,KAAK,WAAW,MAAM,EAAE,IAAI,GAAG;AACjC;AAAA,IACF;AAIA,UAAM,UAAU,KAAK,KAAK,SAAS,MAAM,IAAI,WAAW;AAExD,eAAW,CAAC,KAAK,KAAK,KAAK,SAAS;AAElC,UAAI,CAAC,iBAAiB,KAAK,WAAW,KAAK,IAAI,MAAM,GAAG;AACtD;AAAA,MACF;AACA,YAAM,CAAC,KAAK,KAAK;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,CAAC,YAAY,KAAQ,YAAqB,OAAiC;AAEzE,UAAM,UAAU,KAAK,KAAK,QAAQ,GAAG;AAErC,QAAI,QAAQ;AACZ,eAAW,CAAC,GAAG,CAAC,KAAK,SAAS;AAC5B,UAAI,OAAO;AACT,gBAAQ;AAER,YAAI,CAAC,aAAa,KAAK,WAAW,GAAG,GAAG,MAAM,GAAG;AAC/C;AAAA,QACF;AAAA,MACF;AACA,YAAM,CAAC,GAAG,CAAC;AAAA,IACb;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,CAAC,SAAS,KAAQ,YAAqB,OAAiC;AAEtE,UAAM,WAAW,YAAY,KAAK,SAAS,GAAG,IAAI,KAAK,SAAS,GAAG;AAEnE,QAAI,aAAa,QAAW;AAC1B;AAAA,IACF;AAGA,UAAM,SAAS,KAAK,KAAK,OAAO;AAChC,QAAI,WAAW,QAAW;AACxB;AAAA,IACF;AAGA,UAAM,UAAU,KAAK,KAAK,SAAS,QAAQ,UAAU,IAAI;AACzD,eAAW,SAAS,SAAS;AAC3B,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,CAAC,UAAoC;AACnC,eAAW,SAAS,KAAK,KAAK,QAAQ,GAAG;AACvC,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,CAAC,OAA4B;AAC3B,eAAW,OAAO,KAAK,KAAK,KAAK,GAAG;AAClC,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,CAAC,SAA8B;AAC7B,eAAW,SAAS,KAAK,KAAK,OAAO,GAAG;AACtC,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,CAAC,kBAA4C;AAC3C,eAAW,SAAS,KAAK,KAAK,gBAAgB,GAAG;AAC/C,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,KAAK,MAAM;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,UAAuD;AAC7D,SAAK,KAAK,QAAQ,CAAC,OAAO,QAAQ;AAChC,eAAS,OAAO,KAAK,IAAI;AAAA,IAC3B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,KACL,SACA,YACiB;AACjB,UAAM,MAAM,IAAI,WAAgB,UAAU;AAC1C,eAAW,CAAC,KAAK,KAAK,KAAK,SAAS;AAClC,UAAI,IAAI,KAAK,KAAK;AAAA,IACpB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,KAAQ,SAAqB;AACpC,UAAM,WAAW,KAAK,KAAK,IAAI,GAAG;AAClC,QAAI,aAAa,QAAW;AAC1B,aAAO;AAAA,IACT;AACA,UAAM,QAAQ,QAAQ;AACtB,SAAK,KAAK,IAAI,KAAK,KAAK;AACxB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,KAAQ,SAAmC;AAChD,UAAM,WAAW,KAAK,KAAK,IAAI,GAAG;AAClC,QAAI,aAAa,QAAW;AAC1B,aAAO;AAAA,IACT;AACA,SAAK,KAAK,IAAI,KAAK,QAAQ,QAAQ,CAAC;AACpC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,GAAG,OAAmC;AACpC,QAAI,QAAQ,KAAK,SAAS,KAAK,KAAK,MAAM;AACxC,aAAO;AAAA,IACT;AAEA,QAAI,IAAI;AACR,eAAW,SAAS,KAAK,KAAK,QAAQ,GAAG;AACvC,UAAI,MAAM,OAAO;AACf,eAAO;AAAA,MACT;AACA;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,KAAuB;AAC9B,WAAO,KAAK,KAAK,aAAa,GAAG;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,KAAuB;AAE9B,QAAI,KAAK,KAAK,IAAI,GAAG,GAAG;AACtB,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,KAAK,aAAa,GAAG;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,KAAuB;AAC/B,eAAW,CAAC,CAAC,KAAK,KAAK,KAAK,QAAQ,GAAG,GAAG;AACxC,UAAI,KAAK,WAAW,GAAG,GAAG,IAAI,GAAG;AAC/B,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,KAAuB;AAChC,eAAW,CAAC,CAAC,KAAK,KAAK,KAAK,QAAQ,GAAG,GAAG;AACxC,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,CAAC,OAAO,QAAQ,IAA8B;AAC5C,WAAO,KAAK,QAAQ;AAAA,EACtB;AACF;;;AErTO,IAAM,kBAAN,MAAuD;AAAA,EAG5D,YACW,MACQ,WACjB;AAFS;AACQ;AAJnB,SAAS,OAAO;AAAA,EAKb;AAAA,EAEH,SAAS,QAA0B;AACjC,WAAO,KAAK,UAAU,MAAM;AAAA,EAC9B;AAAA,EAEA,UAAU,QAAgB;AACxB,UAAM,QAAQ,KAAK,SAAS,MAAM;AAClC,WAAO,UAAU,SAAY,CAAC,KAAK,IAAI,CAAC;AAAA,EAC1C;AACF;AAKO,SAAS,gBACd,MACA,WACuB;AACvB,SAAO,IAAI,gBAAgB,MAAM,SAAS;AAC5C;AAMO,IAAM,sBAAN,MAA2D;AAAA,EAGhE,YACW,MACQ,WACjB;AAFS;AACQ;AAJnB,SAAS,OAAO;AAAA,EAKb;AAAA,EAEH,SAAS,QAA0B;AACjC,UAAM,SAAS,KAAK,UAAU,MAAM;AACpC,WAAO,OAAO,SAAS,IAAI,OAAO,CAAC,IAAI;AAAA,EACzC;AAAA,EAEA,UAAU,QAAgB;AACxB,WAAO,KAAK,UAAU,MAAM;AAAA,EAC9B;AACF;AAKO,SAAS,eACd,MACA,WAC2B;AAC3B,SAAO,IAAI,oBAAoB,MAAM,SAAS;AAChD;;;AChFO,IAAM,eAAN,MAA8C;AAAA,EACnD,YACmB,MACA,eACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAEH,CAAC,OAAO,QAAQ,IAAiB;AAC/B,WAAO,KAAK,KAAK,OAAO,QAAQ,EAAE;AAAA,EACpC;AAAA,EAEA,mBAA2B;AACzB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,eAAuB;AACrB,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA,EAEA,SAAS,KAAiB;AACxB,WAAO,KAAK,KAAK,IAAI,GAAG;AAAA,EAC1B;AAAA,EAEA,OAAe;AACb,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA,EAEA,UAAe;AACb,WAAO,MAAM,KAAK,KAAK,IAAI;AAAA,EAC7B;AAAA,EAEA,UAAmB;AACjB,WAAO,KAAK,KAAK,SAAS;AAAA,EAC5B;AACF;;;ACxBO,IAAM,aAAN,MAAM,WAA6C;AAAA,EAYxD,YAAqB,WAA4B;AAA5B;AAXrB,SAAS,OAAO;AAGhB;AAAA,SAAQ,OAAuB,oBAAI,IAAI;AAGvC;AAAA,SAAQ,UAAkB,oBAAI,IAAI;AAAA,EAKgB;AAAA,EAElD,mBAA2B;AACzB,WAAO,WAAU;AAAA,EACnB;AAAA,EAEA,cAAc,WAA4B;AACxC,WAAO,WAAU,kBAAkB,SAAS,SAAS;AAAA,EACvD;AAAA,EAEA,SAAS,OAAoC;AAC3C,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,eAAO,KAAK,cAAc,MAAM,KAAU;AAAA,MAC5C,KAAK;AACH,eAAO,KAAK,WAAW,MAAM,MAAa;AAAA,MAC5C,KAAK;AACH,eAAO,KAAK,YAAY;AAAA,MAC1B;AACE,cAAM,IAAI,MAAM,0CAA0C,MAAM,IAAI,EAAE;AAAA,IAC1E;AAAA,EACF;AAAA,EAEQ,cAAc,OAAwB;AAC5C,UAAM,OAAO,KAAK,KAAK,IAAI,KAAK;AAChC,WAAO,IAAI,aAAa,OAAO,IAAI,IAAI,IAAI,IAAI,oBAAI,IAAI,GAAG,WAAU,cAAc;AAAA,EACpF;AAAA,EAEQ,WAAW,QAA2B;AAC5C,UAAM,SAAS,oBAAI,IAAO;AAC1B,eAAW,SAAS,QAAQ;AAC1B,YAAM,OAAO,KAAK,KAAK,IAAI,KAAK;AAChC,UAAI,MAAM;AACR,mBAAW,OAAO,MAAM;AACtB,iBAAO,IAAI,GAAG;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AACA,WAAO,IAAI,aAAa,QAAQ,WAAU,cAAc;AAAA,EAC1D;AAAA,EAEQ,cAA4B;AAClC,WAAO,IAAI,aAAa,IAAI,IAAI,KAAK,OAAO,GAAG,WAAU,cAAc;AAAA,EACzE;AAAA,EAEA,IAAI,KAAQ,QAAiB;AAC3B,UAAM,SAAS,KAAK,UAAU,UAAU,MAAM;AAC9C,QAAI,OAAO,WAAW,EAAG;AAEzB,eAAW,SAAS,QAAQ;AAC1B,UAAI,OAAO,KAAK,KAAK,IAAI,KAAK;AAC9B,UAAI,CAAC,MAAM;AACT,eAAO,oBAAI,IAAI;AACf,aAAK,KAAK,IAAI,OAAO,IAAI;AAAA,MAC3B;AACA,WAAK,IAAI,GAAG;AAAA,IACd;AAEA,SAAK,QAAQ,IAAI,GAAG;AAAA,EACtB;AAAA,EAEA,OAAO,KAAQ,QAAiB;AAC9B,UAAM,SAAS,KAAK,UAAU,UAAU,MAAM;AAE9C,eAAW,SAAS,QAAQ;AAC1B,YAAM,OAAO,KAAK,KAAK,IAAI,KAAK;AAChC,UAAI,MAAM;AACR,aAAK,OAAO,GAAG;AACf,YAAI,KAAK,SAAS,GAAG;AACnB,eAAK,KAAK,OAAO,KAAK;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAEA,SAAK,QAAQ,OAAO,GAAG;AAAA,EACzB;AAAA,EAEA,OAAO,KAAQ,WAAc,WAAoB;AAC/C,UAAM,YAAY,KAAK,UAAU,UAAU,SAAS;AACpD,UAAM,YAAY,KAAK,UAAU,UAAU,SAAS;AAGpD,QAAI,KAAK,YAAY,WAAW,SAAS,GAAG;AAC1C;AAAA,IACF;AAEA,SAAK,OAAO,KAAK,SAAS;AAC1B,SAAK,IAAI,KAAK,SAAS;AAAA,EACzB;AAAA,EAEA,QAAc;AACZ,SAAK,KAAK,MAAM;AAChB,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA,EAEA,WAAuB;AACrB,QAAI,eAAe;AACnB,eAAW,QAAQ,KAAK,KAAK,OAAO,GAAG;AACrC,sBAAgB,KAAK;AAAA,IACvB;AAEA,WAAO;AAAA,MACL,gBAAgB,KAAK,KAAK;AAAA,MAC1B;AAAA,MACA,oBAAoB,KAAK,KAAK,OAAO,IAAI,eAAe,KAAK,KAAK,OAAO;AAAA,IAC3E;AAAA,EACF;AAAA,EAEQ,YAAY,GAAQ,GAAiB;AAC3C,QAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,aAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,UAAI,EAAE,CAAC,MAAM,EAAE,CAAC,EAAG,QAAO;AAAA,IAC5B;AACA,WAAO;AAAA,EACT;AACF;AA/Ha,WASa,iBAAiB;AAT9B,WAUa,oBAAoB,CAAC,SAAS,MAAM,KAAK;AAV5D,IAAM,YAAN;;;ACDA,IAAM,gBAAN,MAA+C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWpD,YACmB,iBACA,eACA,eACjB;AAHiB;AACA;AACA;AAZnB;AAAA,SAAQ,SAAqB;AAAA,EAa1B;AAAA,EAEH,EAAE,OAAO,QAAQ,IAAkB;AACjC,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK;AACZ;AAAA,IACF;AAEA,WAAO,KAAK,gBAAgB;AAAA,EAC9B;AAAA,EAEA,mBAA2B;AACzB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,eAAuB;AAErB,WAAO,KAAK,QAAQ,UAAU,KAAK;AAAA,EACrC;AAAA,EAEA,SAAS,KAAiB;AAExB,WAAO,KAAK,QAAQ,EAAE,SAAS,GAAG;AAAA,EACpC;AAAA,EAEA,OAAe;AACb,WAAO,KAAK,QAAQ,EAAE;AAAA,EACxB;AAAA,EAEA,UAAe;AACb,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,CAAC,GAAG,KAAK,gBAAgB,CAAC;AAAA,IAC1C;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,UAAmB;AAEjB,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK,OAAO,WAAW;AAAA,IAChC;AAGA,UAAM,OAAO,KAAK,gBAAgB;AAClC,UAAM,QAAQ,KAAK,KAAK;AACxB,WAAO,MAAM,SAAS;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAA0B;AACxB,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAmB;AACjB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,mBAA2B;AACzB,WAAO,KAAK;AAAA,EACd;AACF;;;ACjFO,IAAM,kBAAN,MAAM,gBAEb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8BE,YACW,WACT,YACA;AAFS;AA9BX,SAAS,OAAO;AAMhB;AAAA,SAAQ,UAAkB,oBAAI,IAAI;AA2BhC,SAAK,OAAO,IAAI,UAAqB,UAAU;AAAA,EACjD;AAAA,EAEA,mBAA2B;AACzB,WAAO,gBAAe;AAAA,EACxB;AAAA,EAEA,cAAc,WAA4B;AACxC,WAAO,gBAAe,kBAAkB,SAAS,SAAS;AAAA,EAC5D;AAAA,EAEA,SAAS,OAAoC;AAC3C,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,eAAO,KAAK,cAAc,MAAM,KAAU;AAAA,MAC5C,KAAK;AACH,eAAO,KAAK,WAAW,MAAM,MAAa;AAAA,MAC5C,KAAK;AACH,eAAO,KAAK,YAAY;AAAA,MAC1B,KAAK;AACH,eAAO,KAAK,oBAAoB,MAAM,OAAY,KAAK;AAAA,MACzD,KAAK;AACH,eAAO,KAAK,oBAAoB,MAAM,OAAY,IAAI;AAAA,MACxD,KAAK;AACH,eAAO,KAAK,iBAAiB,MAAM,OAAY,KAAK;AAAA,MACtD,KAAK;AACH,eAAO,KAAK,iBAAiB,MAAM,OAAY,IAAI;AAAA,MACrD,KAAK;AACH,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,MAAM;AAAA,UACN,MAAM,iBAAiB;AAAA,UACvB,MAAM,eAAe;AAAA,QACvB;AAAA,MACF;AACE,cAAM,IAAI;AAAA,UACR,+CAA+C,MAAM,IAAI;AAAA,QAC3D;AAAA,IACJ;AAAA,EACF;AAAA;AAAA,EAIQ,cAAc,OAAwB;AAC5C,UAAM,OAAO,KAAK,KAAK,IAAI,KAAK;AAChC,WAAO,IAAI;AAAA,MACT,OAAO,IAAI,IAAI,IAAI,IAAI,oBAAI,IAAI;AAAA,MAC/B,gBAAe;AAAA,IACjB;AAAA,EACF;AAAA,EAEQ,WAAW,QAA2B;AAC5C,UAAM,SAAS,oBAAI,IAAO;AAC1B,eAAW,SAAS,QAAQ;AAC1B,YAAM,OAAO,KAAK,KAAK,IAAI,KAAK;AAChC,UAAI,MAAM;AACR,mBAAW,OAAO,MAAM;AACtB,iBAAO,IAAI,GAAG;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AACA,WAAO,IAAI,aAAa,QAAQ,gBAAe,cAAc;AAAA,EAC/D;AAAA,EAEQ,cAA4B;AAClC,WAAO,IAAI;AAAA,MACT,IAAI,IAAI,KAAK,OAAO;AAAA,MACpB,gBAAe;AAAA,IACjB;AAAA,EACF;AAAA;AAAA,EAIQ,oBAAoB,OAAU,WAAkC;AACtE,WAAO,IAAI;AAAA,MACT,MAAM,KAAK,mBAAmB,OAAO,SAAS;AAAA,MAC9C,gBAAe;AAAA,MACf,KAAK,wBAAwB;AAAA,IAC/B;AAAA,EACF;AAAA,EAEQ,iBAAiB,OAAU,WAAkC;AACnE,WAAO,IAAI;AAAA,MACT,MAAM,KAAK,gBAAgB,OAAO,SAAS;AAAA,MAC3C,gBAAe;AAAA,MACf,KAAK,qBAAqB;AAAA,IAC5B;AAAA,EACF;AAAA,EAEQ,gBACN,MACA,IACA,eACA,aACc;AACd,WAAO,IAAI;AAAA,MACT,MAAM,KAAK,eAAe,MAAM,IAAI,eAAe,WAAW;AAAA,MAC9D,gBAAe;AAAA,MACf,KAAK,oBAAoB;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA,EAIA,CAAS,mBAAmB,OAAU,WAAkC;AACtE,eAAW,CAAC,EAAE,IAAI,KAAK,KAAK,KAAK,YAAY,OAAO,SAAS,GAAG;AAC9D,iBAAW,OAAO,MAAM;AACtB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAEA,CAAS,gBAAgB,OAAU,WAAkC;AACnE,eAAW,CAAC,EAAE,IAAI,KAAK,KAAK,KAAK,SAAS,OAAO,SAAS,GAAG;AAC3D,iBAAW,OAAO,MAAM;AACtB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAEA,CAAS,eACP,MACA,IACA,eACA,aACc;AACd,eAAW,CAAC,EAAE,IAAI,KAAK,KAAK,KAAK,MAAM,MAAM,IAAI;AAAA,MAC/C;AAAA,MACA;AAAA,IACF,CAAC,GAAG;AACF,iBAAW,OAAO,MAAM;AACtB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,0BAAkC;AACxC,WAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,QAAQ,OAAO,CAAC,CAAC;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,uBAA+B;AACrC,WAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,QAAQ,OAAO,CAAC,CAAC;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,sBAA8B;AACpC,WAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,QAAQ,OAAO,CAAC,CAAC;AAAA,EACtD;AAAA;AAAA,EAIA,IAAI,KAAQ,QAAiB;AAC3B,UAAM,SAAS,KAAK,UAAU,UAAU,MAAM;AAC9C,QAAI,OAAO,WAAW,EAAG;AAEzB,eAAW,SAAS,QAAQ;AAC1B,UAAI,OAAO,KAAK,KAAK,IAAI,KAAK;AAC9B,UAAI,CAAC,MAAM;AACT,eAAO,oBAAI,IAAI;AACf,aAAK,KAAK,IAAI,OAAO,IAAI;AAAA,MAC3B;AACA,WAAK,IAAI,GAAG;AAAA,IACd;AAEA,SAAK,QAAQ,IAAI,GAAG;AAAA,EACtB;AAAA,EAEA,OAAO,KAAQ,QAAiB;AAC9B,UAAM,SAAS,KAAK,UAAU,UAAU,MAAM;AAE9C,eAAW,SAAS,QAAQ;AAC1B,YAAM,OAAO,KAAK,KAAK,IAAI,KAAK;AAChC,UAAI,MAAM;AACR,aAAK,OAAO,GAAG;AACf,YAAI,KAAK,SAAS,GAAG;AACnB,eAAK,KAAK,OAAO,KAAK;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAEA,SAAK,QAAQ,OAAO,GAAG;AAAA,EACzB;AAAA,EAEA,OAAO,KAAQ,WAAc,WAAoB;AAC/C,UAAM,YAAY,KAAK,UAAU,UAAU,SAAS;AACpD,UAAM,YAAY,KAAK,UAAU,UAAU,SAAS;AAGpD,QAAI,KAAK,YAAY,WAAW,SAAS,GAAG;AAC1C;AAAA,IACF;AAEA,SAAK,OAAO,KAAK,SAAS;AAC1B,SAAK,IAAI,KAAK,SAAS;AAAA,EACzB;AAAA,EAEA,QAAc;AACZ,SAAK,KAAK,MAAM;AAChB,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA,EAEA,WAAuB;AACrB,QAAI,eAAe;AACnB,eAAW,CAAC,EAAE,IAAI,KAAK,KAAK,KAAK,QAAQ,GAAG;AAC1C,sBAAgB,KAAK;AAAA,IACvB;AAEA,WAAO;AAAA,MACL,gBAAgB,KAAK,KAAK;AAAA,MAC1B;AAAA,MACA,oBACE,KAAK,KAAK,OAAO,IAAI,eAAe,KAAK,KAAK,OAAO;AAAA,IACzD;AAAA,EACF;AAAA;AAAA,EAIQ,YAAY,GAAQ,GAAiB;AAC3C,QAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,aAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,UAAI,EAAE,CAAC,MAAM,EAAE,CAAC,EAAG,QAAO;AAAA,IAC5B;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAA6B;AAC3B,WAAO,KAAK,KAAK,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAA6B;AAC3B,WAAO,KAAK,KAAK,OAAO;AAAA,EAC1B;AACF;AAAA;AAjSa,gBAYa,iBAAiB;AAAA;AAZ9B,gBAea,oBAAoB;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAxBK,IAAM,iBAAN;;;ACNA,IAAM,iBAAN,MAAM,eAAoD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgB/D,YACmB,YACA,WACA,kBACjB;AAHiB;AACA;AACA;AAlBnB,SAAS,OAAO;AAGhB;AAAA,SAAS,YAAY,gBAA4B,KAAK,MAAM,MAAS;AAAA,EAgBlE;AAAA,EAEH,mBAA2B;AACzB,WAAO,eAAc;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAyB;AACvB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,OAA0C;AACjD,UAAM,SAAS,oBAAI,IAAO;AAE1B,eAAW,OAAO,KAAK,WAAW,GAAG;AACnC,YAAM,SAAS,KAAK,UAAU,GAAG;AACjC,UAAI,UAAU,KAAK,iBAAiB,QAAQ,KAAK,GAAG;AAClD,eAAO,IAAI,GAAG;AAAA,MAChB;AAAA,IACF;AAEA,WAAO,IAAI,aAAa,QAAQ,eAAc,cAAc;AAAA,EAC9D;AAAA;AAAA,EAGA,MAAY;AAAA,EAAC;AAAA,EACb,SAAe;AAAA,EAAC;AAAA,EAChB,SAAe;AAAA,EAAC;AAAA,EAChB,QAAc;AAAA,EAAC;AAAA,EAEf,WAAuB;AACrB,WAAO;AAAA,MACL,gBAAgB;AAAA,MAChB,cAAc;AAAA,MACd,oBAAoB;AAAA,IACtB;AAAA,EACF;AACF;AAAA;AA9Da,eAOa,iBAAiB,OAAO;AAP3C,IAAM,gBAAN;AAsEA,SAAS,uBACd,cACoD;AACpD,SAAO,CAAC,QAAW,UAAwC;AAEzD,QAAK,MAAiC,cAAc,KAAK;AACvD,aAAO;AAAA,IACT;AAEA,UAAM,WAAY,MAAiC;AACnD,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,IACT;AAEA,UAAM,QAAQ,aAAa,QAAQ,QAAQ;AAE3C,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,eAAO,UAAU,MAAM;AAAA,MAEzB,KAAK;AACH,eAAO,MAAM,QAAQ,SAAS,KAAK,KAAK;AAAA,MAE1C,KAAK;AACH,eAAO,UAAU,UAAa,UAAU;AAAA,MAE1C,KAAK;AACH,eAAO,OAAO,UAAU,YAAY,OAAO,MAAM,UAAU,WACvD,QAAQ,MAAM,QACd,OAAO,UAAU,YAAY,OAAO,MAAM,UAAU,WAClD,QAAQ,MAAM,QACd;AAAA,MAER,KAAK;AACH,eAAO,OAAO,UAAU,YAAY,OAAO,MAAM,UAAU,WACvD,SAAS,MAAM,QACf,OAAO,UAAU,YAAY,OAAO,MAAM,UAAU,WAClD,SAAS,MAAM,QACf;AAAA,MAER,KAAK;AACH,eAAO,OAAO,UAAU,YAAY,OAAO,MAAM,UAAU,WACvD,QAAQ,MAAM,QACd,OAAO,UAAU,YAAY,OAAO,MAAM,UAAU,WAClD,QAAQ,MAAM,QACd;AAAA,MAER,KAAK;AACH,eAAO,OAAO,UAAU,YAAY,OAAO,MAAM,UAAU,WACvD,SAAS,MAAM,QACf,OAAO,UAAU,YAAY,OAAO,MAAM,UAAU,WAClD,SAAS,MAAM,QACf;AAAA,MAER,KAAK,WAAW;AACd,YAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;AAC1D,iBAAO;AAAA,QACT;AACA,cAAM,gBAAgB,MAAM,iBAAiB;AAC7C,cAAM,cAAc,MAAM,eAAe;AACzC,cAAM,OAAO,MAAM;AACnB,cAAM,KAAK,MAAM;AAEjB,YAAI,SAAS,UAAa,SAAS,QAAQ,OAAO,UAAa,OAAO,MAAM;AAC1E,iBAAO;AAAA,QACT;AAEA,cAAM,YAAY,gBAAgB,SAAS,OAAO,QAAQ;AAC1D,cAAM,UAAU,cAAc,SAAS,KAAK,QAAQ;AACpD,eAAO,aAAa;AAAA,MACtB;AAAA,MAEA;AACE,eAAO;AAAA,IACX;AAAA,EACF;AACF;;;AC2FO,SAAS,cAAc,OAAwC;AACpE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,SAAS,MAAM,IAAI;AACvB;AAKO,SAAS,eAAe,OAAyC;AACtE,SAAO,MAAM,SAAS,SAAS,MAAM,SAAS,QAAQ,MAAM,SAAS;AACvE;AAKO,SAAS,WAAW,OAAqC;AAC9D,SAAO,MAAM,SAAS,WAAW,MAAM,SAAS,iBAAiB,MAAM,SAAS;AAClF;;;ACpPO,IAAM,sBAAN,MAAM,oBAAyD;AAAA,EAwBpE,YAAY,SAA0C;AAvBtD,SAAS,OAAO;AAMhB;AAAA;AAAA;AAAA;AAAA,SAAS,YAAmC;AAAA,MAC1C;AAAA,MACA,MAAM;AAAA,IACR;AAGA;AAAA,SAAQ,UAAkB,oBAAI,IAAI;AAYhC,SAAK,QAAQ,QAAQ;AACrB,SAAK,YAAY,QAAQ;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,WAAkB;AAChB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,OAAuB;AAClC,WAAO,KAAK,aAAa,KAAK,OAAO,KAAK;AAAA,EAC5C;AAAA,EAEA,mBAA2B;AACzB,WAAO,oBAAmB;AAAA,EAC5B;AAAA,EAEA,cAAc,YAA6B;AAGzC,WAAO;AAAA,EACT;AAAA,EAEA,SAAS,QAA2C;AAElD,WAAO,IAAI,aAAa,IAAI,IAAI,KAAK,OAAO,GAAG,oBAAmB,cAAc;AAAA,EAClF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAqB;AACnB,WAAO,IAAI,IAAI,KAAK,OAAO;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAyB;AACvB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,KAAiB;AACxB,WAAO,KAAK,QAAQ,IAAI,GAAG;AAAA,EAC7B;AAAA,EAEA,IAAI,KAAQ,QAAiB;AAE3B,QAAI,KAAK,eAAe,MAAM,GAAG;AAC/B,WAAK,QAAQ,IAAI,GAAG;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,OAAO,KAAQ,SAAkB;AAE/B,SAAK,QAAQ,OAAO,GAAG;AAAA,EACzB;AAAA,EAEA,OAAO,KAAQ,WAAc,WAAoB;AAC/C,UAAM,WAAW,KAAK,eAAe,SAAS;AAC9C,UAAM,UAAU,KAAK,eAAe,SAAS;AAE7C,QAAI,YAAY,CAAC,SAAS;AAExB,WAAK,QAAQ,OAAO,GAAG;AAAA,IACzB,WAAW,CAAC,YAAY,SAAS;AAE/B,WAAK,QAAQ,IAAI,GAAG;AAAA,IACtB;AAAA,EAGF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,gBACE,MACA,WACA,WACqB;AACrB,UAAM,WAAW,YAAY,KAAK,eAAe,SAAS,IAAI;AAC9D,UAAM,UAAU,YAAY,KAAK,eAAe,SAAS,IAAI;AAE7D,QAAI,CAAC,YAAY,SAAS;AACxB,aAAO;AAAA,IACT,WAAW,YAAY,CAAC,SAAS;AAC/B,aAAO;AAAA,IACT,WAAW,YAAY,SAAS;AAC9B,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EAEA,QAAc;AACZ,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA,EAEA,WAAuB;AACrB,WAAO;AAAA,MACL,gBAAgB;AAAA;AAAA,MAChB,cAAc,KAAK,QAAQ;AAAA,MAC3B,oBAAoB,KAAK,QAAQ;AAAA,IACnC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cAAc,SAAiC;AAC7C,SAAK,QAAQ,MAAM;AACnB,eAAW,CAAC,KAAK,MAAM,KAAK,SAAS;AACnC,UAAI,KAAK,eAAe,MAAM,GAAG;AAC/B,aAAK,QAAQ,IAAI,GAAG;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,eAAe,QAAoB;AACzC,QAAI;AACF,aAAO,KAAK,cAAc,KAAK,OAAO,MAAM;AAAA,IAC9C,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,cAAc,OAAc,QAAoB;AACtD,QAAI,cAAc,KAAK,GAAG;AACxB,aAAO,KAAK,oBAAoB,OAAO,MAAM;AAAA,IAC/C,WAAW,eAAe,KAAK,GAAG;AAChC,aAAO,KAAK,qBAAqB,OAAO,MAAM;AAAA,IAChD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAoB,OAAwB,QAAoB;AACtE,UAAM,QAAQ,KAAK,kBAAkB,QAAQ,MAAM,SAAS;AAE5D,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,eAAO,UAAU,MAAM;AAAA,MAEzB,KAAK;AACH,eAAO,UAAU,MAAM;AAAA,MAEzB,KAAK;AACH,eACE,UAAU,UACV,UAAU,QACT,QAAoB,MAAM;AAAA,MAG/B,KAAK;AACH,eACE,UAAU,UACV,UAAU,QACT,SAAqB,MAAM;AAAA,MAGhC,KAAK;AACH,eACE,UAAU,UACV,UAAU,QACT,QAAoB,MAAM;AAAA,MAG/B,KAAK;AACH,eACE,UAAU,UACV,UAAU,QACT,SAAqB,MAAM;AAAA,MAGhC,KAAK;AACH,eAAO,MAAM,WAAW,UAAa,MAAM,OAAO,SAAS,KAAK;AAAA,MAElE,KAAK;AACH,eAAO,UAAU,UAAa,UAAU;AAAA,MAE1C,KAAK;AACH,YAAI,OAAO,UAAU,YAAY,OAAO,MAAM,UAAU,UAAU;AAChE,iBAAO;AAAA,QACT;AACA,eAAO,KAAK,UAAU,OAAO,MAAM,KAAK;AAAA,MAE1C,KAAK;AACH,YAAI,OAAO,UAAU,YAAY,OAAO,MAAM,UAAU,UAAU;AAChE,iBAAO;AAAA,QACT;AACA,YAAI;AACF,iBAAO,IAAI,OAAO,MAAM,KAAK,EAAE,KAAK,KAAK;AAAA,QAC3C,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MAEF,KAAK;AACH,YAAI,UAAU,UAAa,UAAU,MAAM;AACzC,iBAAO;AAAA,QACT;AACA,cAAM,MAAM;AACZ,cAAM,OAAO,MAAM;AACnB,cAAM,KAAK,MAAM;AACjB,cAAM,SAAS,MAAM,kBAAkB,QAAQ,OAAO,OAAO,MAAM;AACnE,cAAM,OAAO,MAAM,gBAAgB,QAAQ,OAAO,KAAK,MAAM;AAC7D,eAAO,UAAU;AAAA,MAEnB,KAAK;AACH,YAAI,OAAO,UAAU,YAAY,OAAO,MAAM,UAAU,UAAU;AAChE,iBAAO;AAAA,QACT;AACA,eAAO,MAAM,YAAY,EAAE,SAAU,MAAM,MAAiB,YAAY,CAAC;AAAA,MAE3E,KAAK;AACH,YAAI,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ;AAC9C,iBAAO;AAAA,QACT;AACA,eAAO,MAAM,OAAO;AAAA,UAClB,CAAC,MAAM,OAAO,MAAM,YAAY,MAAM,YAAY,EAAE,SAAS,EAAE,YAAY,CAAC;AAAA,QAC9E;AAAA,MAEF,KAAK;AACH,YAAI,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ;AAC9C,iBAAO;AAAA,QACT;AACA,eAAO,MAAM,OAAO;AAAA,UAClB,CAAC,MAAM,OAAO,MAAM,YAAY,MAAM,YAAY,EAAE,SAAS,EAAE,YAAY,CAAC;AAAA,QAC9E;AAAA,MAEF;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,OAAyB,QAAoB;AACxE,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,YAAI,CAAC,MAAM,YAAY,MAAM,SAAS,WAAW,GAAG;AAClD,iBAAO;AAAA,QACT;AACA,eAAO,MAAM,SAAS,MAAM,CAAC,UAAU,KAAK,cAAc,OAAO,MAAM,CAAC;AAAA,MAE1E,KAAK;AACH,YAAI,CAAC,MAAM,YAAY,MAAM,SAAS,WAAW,GAAG;AAClD,iBAAO;AAAA,QACT;AACA,eAAO,MAAM,SAAS,KAAK,CAAC,UAAU,KAAK,cAAc,OAAO,MAAM,CAAC;AAAA,MAEzE,KAAK;AACH,YAAI,CAAC,MAAM,OAAO;AAChB,iBAAO;AAAA,QACT;AACA,eAAO,CAAC,KAAK,cAAc,MAAM,OAAO,MAAM;AAAA,MAEhD;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,QAAW,MAAuB;AAC1D,QAAI,WAAW,QAAQ,WAAW,QAAW;AAC3C,aAAO;AAAA,IACT;AAEA,UAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,QAAI,UAAmB;AAEvB,eAAW,QAAQ,OAAO;AACxB,UAAI,YAAY,QAAQ,YAAY,QAAW;AAC7C,eAAO;AAAA,MACT;AACA,UAAI,OAAO,YAAY,UAAU;AAC/B,eAAO;AAAA,MACT;AACA,gBAAW,QAAoC,IAAI;AAAA,IACrD;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,UAAU,OAAe,SAA0B;AAEzD,UAAM,UAAU,QAAQ,QAAQ,qBAAqB,MAAM;AAC3D,UAAM,QAAQ,QAAQ,QAAQ,MAAM,IAAI,EAAE,QAAQ,MAAM,GAAG;AAC3D,WAAO,IAAI,OAAO,IAAI,KAAK,KAAK,GAAG,EAAE,KAAK,KAAK;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,GAAU,GAAmB;AAChD,WAAO,KAAK,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC;AAAA,EAC/C;AACF;AAAA;AArWa,oBAsBa,iBAAiB;AAtBpC,IAAM,qBAAN;;;ACfA,IAAM,sBAAN,MAA+C;AAAA,EACpD,SAAS,MAAwB;AAC/B,QAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,aAAO,CAAC;AAAA,IACV;AACA,WAAO,KAAK,MAAM,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAAA,EACrD;AACF;AAQO,IAAM,wBAAN,MAAiD;AAAA,EACtD,SAAS,MAAwB;AAC/B,QAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,aAAO,CAAC;AAAA,IACV;AACA,WAAO,KAAK,MAAM,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAAA,EACrD;AACF;AAaO,IAAM,iBAAN,MAA0C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM/C,YAA6B,IAAY,GAAG;AAAf;AAC3B,QAAI,IAAI,GAAG;AACT,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,SAAS,MAAwB;AAC/B,QAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,aAAO,CAAC;AAAA,IACV;AAGA,UAAM,aAAa,KAAK,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAElD,QAAI,WAAW,SAAS,KAAK,GAAG;AAE9B,aAAO,WAAW,SAAS,IAAI,CAAC,UAAU,IAAI,CAAC;AAAA,IACjD;AAEA,UAAM,SAAmB,CAAC;AAC1B,aAAS,IAAI,GAAG,KAAK,WAAW,SAAS,KAAK,GAAG,KAAK;AACpD,aAAO,KAAK,WAAW,UAAU,GAAG,IAAI,KAAK,CAAC,CAAC;AAAA,IACjD;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK;AAAA,EACd;AACF;;;AC1EO,IAAM,kBAAN,MAA6C;AAAA,EAClD,MAAM,QAA4B;AAChC,WAAO,OAAO,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC;AAAA,EAC1C;AACF;AAMO,IAAM,qBAAqB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQO,IAAM,iBAAN,MAA4C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjD,YAAY,YAAsB,oBAAoB;AAEpD,SAAK,YAAY,IAAI,IAAI,UAAU,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAAA,EAChE;AAAA,EAEA,MAAM,QAA4B;AAChC,WAAO,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,UAAU,IAAI,EAAE,YAAY,CAAC,CAAC;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA,EAKA,eAA4B;AAC1B,WAAO,IAAI,IAAI,KAAK,SAAS;AAAA,EAC/B;AACF;AAQO,IAAM,kBAAN,MAA6C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlD,YAA6B,YAAoB,GAAG;AAAvB;AAC3B,QAAI,YAAY,GAAG;AACjB,YAAM,IAAI,MAAM,mCAAmC;AAAA,IACrD;AAAA,EACF;AAAA,EAEA,MAAM,QAA4B;AAChC,WAAO,OAAO,OAAO,CAAC,MAAM,EAAE,UAAU,KAAK,SAAS;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA,EAKA,eAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AACF;AAQO,IAAM,kBAAN,MAA6C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlD,YAA6B,YAAoB,IAAI;AAAxB;AAC3B,QAAI,YAAY,GAAG;AACjB,YAAM,IAAI,MAAM,mCAAmC;AAAA,IACrD;AAAA,EACF;AAAA,EAEA,MAAM,QAA4B;AAChC,WAAO,OAAO,OAAO,CAAC,MAAM,EAAE,UAAU,KAAK,SAAS;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA,EAKA,eAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AACF;AAMO,IAAM,aAAN,MAAwC;AAAA,EAC7C,MAAM,QAA4B;AAChC,WAAO,OAAO,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAAA,EAC/D;AACF;AAQO,IAAM,eAAN,MAA0C;AAAA,EAC/C,MAAM,QAA4B;AAChC,WAAO,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC;AAAA,EAC5B;AACF;;;ACrJO,IAAM,uBAAN,MAAM,sBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAShC,YAAY,SAAsC;AAChD,SAAK,YAAY,QAAQ;AACzB,SAAK,UAAU,QAAQ,WAAW,CAAC;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,QAAQ,MAAwB;AAC9B,QAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,aAAO,CAAC;AAAA,IACV;AAGA,QAAI,SAAS,KAAK,UAAU,SAAS,IAAI;AAGzC,eAAW,UAAU,KAAK,SAAS;AACjC,eAAS,OAAO,MAAM,MAAM;AAAA,IAC9B;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,eAA0B;AACxB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,aAA4B;AAC1B,WAAO,CAAC,GAAG,KAAK,OAAO;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,OAAO,SAA+B;AACpC,WAAO,IAAI,sBAAqB;AAAA,MAC9B,WAAW,IAAI,sBAAsB;AAAA,MACrC,SAAS,CAAC,IAAI,gBAAgB,GAAG,IAAI,gBAAgB,CAAC,CAAC;AAAA,IACzD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,OAAO,SAA+B;AACpC,WAAO,IAAI,sBAAqB;AAAA,MAC9B,WAAW,IAAI,sBAAsB;AAAA,MACrC,SAAS,CAAC,IAAI,gBAAgB,GAAG,IAAI,gBAAgB,CAAC,GAAG,IAAI,eAAe,CAAC;AAAA,IAC/E,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,OAAO,UAAgC;AACrC,WAAO,IAAI,sBAAqB;AAAA,MAC9B,WAAW,IAAI,sBAAsB;AAAA,MACrC,SAAS,CAAC,IAAI,gBAAgB,CAAC;AAAA,IACjC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,OAAO,WAAsB,UAAyB,CAAC,GAAyB;AACrF,WAAO,IAAI,sBAAqB,EAAE,WAAW,QAAQ,CAAC;AAAA,EACxD;AACF;;;AC/GO,IAAM,iBAAN,MAAM,eAAyE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBpF,YACW,WACQ,WAAiC,qBAAqB,OAAO,GAC9E;AAFS;AACQ;AAtBnB,SAAS,OAAO;AAGhB;AAAA,SAAQ,aAAkC,oBAAI,IAAI;AAGlD;AAAA,SAAQ,eAAoC,oBAAI,IAAI;AAGpD;AAAA,SAAQ,UAAkB,oBAAI,IAAI;AAAA,EAc/B;AAAA,EAEH,mBAA2B;AACzB,WAAO,eAAc;AAAA,EACvB;AAAA,EAEA,cAAc,WAA4B;AACxC,WAAO,eAAc,kBAAkB,SAAS,SAAS;AAAA,EAC3D;AAAA,EAEA,SAAS,OAAoC;AAC3C,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,eAAO,KAAK,iBAAiB,MAAM,KAAU;AAAA,MAC/C,KAAK;AACH,eAAO,KAAK,oBAAoB,MAAM,MAAa;AAAA,MACrD,KAAK;AACH,eAAO,KAAK,oBAAoB,MAAM,MAAa;AAAA,MACrD,KAAK;AACH,eAAO,KAAK,YAAY;AAAA,MAC1B;AACE,cAAM,IAAI,MAAM,8CAA8C,MAAM,IAAI,EAAE;AAAA,IAC9E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAAiB,YAA6B;AACpD,QAAI,CAAC,YAAY;AACf,aAAO,IAAI,aAAa,oBAAI,IAAI,GAAG,eAAc,cAAc;AAAA,IACjE;AAEA,UAAM,eAAe,KAAK,SAAS,QAAQ,OAAO,UAAU,CAAC;AAC7D,QAAI,aAAa,WAAW,GAAG;AAC7B,aAAO,IAAI,aAAa,oBAAI,IAAI,GAAG,eAAc,cAAc;AAAA,IACjE;AAGA,UAAM,eAAe,CAAC,GAAG,YAAY,EAAE,KAAK,CAAC,GAAG,MAAM;AACpD,YAAM,QAAQ,KAAK,WAAW,IAAI,CAAC,GAAG,QAAQ;AAC9C,YAAM,QAAQ,KAAK,WAAW,IAAI,CAAC,GAAG,QAAQ;AAC9C,aAAO,QAAQ;AAAA,IACjB,CAAC;AAGD,UAAM,iBAAiB,KAAK,WAAW,IAAI,aAAa,CAAC,CAAC;AAC1D,QAAI,CAAC,kBAAkB,eAAe,SAAS,GAAG;AAChD,aAAO,IAAI,aAAa,oBAAI,IAAI,GAAG,eAAc,cAAc;AAAA,IACjE;AAEA,UAAM,SAAS,IAAI,IAAI,cAAc;AAGrC,aAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,YAAM,YAAY,KAAK,WAAW,IAAI,aAAa,CAAC,CAAC;AACrD,UAAI,CAAC,aAAa,UAAU,SAAS,GAAG;AACtC,eAAO,IAAI,aAAa,oBAAI,IAAI,GAAG,eAAc,cAAc;AAAA,MACjE;AAEA,iBAAW,OAAO,QAAQ;AACxB,YAAI,CAAC,UAAU,IAAI,GAAG,GAAG;AACvB,iBAAO,OAAO,GAAG;AAAA,QACnB;AAAA,MACF;AAEA,UAAI,OAAO,SAAS,GAAG;AACrB,eAAO,IAAI,aAAa,oBAAI,IAAI,GAAG,eAAc,cAAc;AAAA,MACjE;AAAA,IACF;AAEA,WAAO,IAAI,aAAa,QAAQ,eAAc,cAAc;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,oBAAoB,QAA2B;AACrD,QAAI,CAAC,UAAU,OAAO,WAAW,GAAG;AAClC,aAAO,IAAI,aAAa,oBAAI,IAAI,GAAG,eAAc,cAAc;AAAA,IACjE;AAGA,UAAM,YAAY,oBAAI,IAAY;AAClC,eAAW,SAAS,QAAQ;AAC1B,YAAM,SAAS,KAAK,SAAS,QAAQ,OAAO,KAAK,CAAC;AAClD,aAAO,QAAQ,CAAC,MAAM,UAAU,IAAI,CAAC,CAAC;AAAA,IACxC;AAEA,QAAI,UAAU,SAAS,GAAG;AACxB,aAAO,IAAI,aAAa,oBAAI,IAAI,GAAG,eAAc,cAAc;AAAA,IACjE;AAGA,UAAM,eAAe,CAAC,GAAG,SAAS,EAAE,KAAK,CAAC,GAAG,MAAM;AACjD,YAAM,QAAQ,KAAK,WAAW,IAAI,CAAC,GAAG,QAAQ;AAC9C,YAAM,QAAQ,KAAK,WAAW,IAAI,CAAC,GAAG,QAAQ;AAC9C,aAAO,QAAQ;AAAA,IACjB,CAAC;AAGD,UAAM,iBAAiB,KAAK,WAAW,IAAI,aAAa,CAAC,CAAC;AAC1D,QAAI,CAAC,kBAAkB,eAAe,SAAS,GAAG;AAChD,aAAO,IAAI,aAAa,oBAAI,IAAI,GAAG,eAAc,cAAc;AAAA,IACjE;AAEA,UAAM,SAAS,IAAI,IAAI,cAAc;AAGrC,aAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,YAAM,YAAY,KAAK,WAAW,IAAI,aAAa,CAAC,CAAC;AACrD,UAAI,CAAC,aAAa,UAAU,SAAS,GAAG;AACtC,eAAO,IAAI,aAAa,oBAAI,IAAI,GAAG,eAAc,cAAc;AAAA,MACjE;AAEA,iBAAW,OAAO,QAAQ;AACxB,YAAI,CAAC,UAAU,IAAI,GAAG,GAAG;AACvB,iBAAO,OAAO,GAAG;AAAA,QACnB;AAAA,MACF;AAEA,UAAI,OAAO,SAAS,GAAG;AACrB,eAAO,IAAI,aAAa,oBAAI,IAAI,GAAG,eAAc,cAAc;AAAA,MACjE;AAAA,IACF;AAEA,WAAO,IAAI,aAAa,QAAQ,eAAc,cAAc;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,oBAAoB,QAA2B;AACrD,QAAI,CAAC,UAAU,OAAO,WAAW,GAAG;AAClC,aAAO,IAAI,aAAa,oBAAI,IAAI,GAAG,eAAc,cAAc;AAAA,IACjE;AAEA,UAAM,SAAS,oBAAI,IAAO;AAE1B,eAAW,SAAS,QAAQ;AAC1B,YAAM,SAAS,KAAK,SAAS,QAAQ,OAAO,KAAK,CAAC;AAClD,iBAAW,SAAS,QAAQ;AAC1B,cAAM,OAAO,KAAK,WAAW,IAAI,KAAK;AACtC,YAAI,MAAM;AACR,qBAAW,OAAO,MAAM;AACtB,mBAAO,IAAI,GAAG;AAAA,UAChB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO,IAAI,aAAa,QAAQ,eAAc,cAAc;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAKQ,cAA4B;AAClC,WAAO,IAAI,aAAa,IAAI,IAAI,KAAK,OAAO,GAAG,eAAc,cAAc;AAAA,EAC7E;AAAA;AAAA,EAIA,IAAI,KAAQ,QAAiB;AAC3B,UAAM,SAAS,KAAK,UAAU,UAAU,MAAM;AAC9C,QAAI,OAAO,WAAW,EAAG;AAEzB,UAAM,YAAY,oBAAI,IAAY;AAGlC,eAAW,SAAS,QAAQ;AAC1B,UAAI,UAAU,UAAa,UAAU,KAAM;AAC3C,YAAM,SAAS,KAAK,SAAS,QAAQ,OAAO,KAAK,CAAC;AAClD,aAAO,QAAQ,CAAC,MAAM,UAAU,IAAI,CAAC,CAAC;AAAA,IACxC;AAEA,QAAI,UAAU,SAAS,EAAG;AAG1B,eAAW,SAAS,WAAW;AAC7B,UAAI,OAAO,KAAK,WAAW,IAAI,KAAK;AACpC,UAAI,CAAC,MAAM;AACT,eAAO,oBAAI,IAAI;AACf,aAAK,WAAW,IAAI,OAAO,IAAI;AAAA,MACjC;AACA,WAAK,IAAI,GAAG;AAAA,IACd;AAGA,SAAK,aAAa,IAAI,KAAK,SAAS;AACpC,SAAK,QAAQ,IAAI,GAAG;AAAA,EACtB;AAAA,EAEA,OAAO,KAAQ,SAAkB;AAC/B,UAAM,SAAS,KAAK,aAAa,IAAI,GAAG;AACxC,QAAI,CAAC,OAAQ;AAGb,eAAW,SAAS,QAAQ;AAC1B,YAAM,OAAO,KAAK,WAAW,IAAI,KAAK;AACtC,UAAI,MAAM;AACR,aAAK,OAAO,GAAG;AACf,YAAI,KAAK,SAAS,GAAG;AACnB,eAAK,WAAW,OAAO,KAAK;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAGA,SAAK,aAAa,OAAO,GAAG;AAC5B,SAAK,QAAQ,OAAO,GAAG;AAAA,EACzB;AAAA,EAEA,OAAO,KAAQ,WAAc,WAAoB;AAE/C,UAAM,YAAY,KAAK,UAAU,UAAU,SAAS;AACpD,UAAM,YAAY,KAAK,UAAU,UAAU,SAAS;AAGpD,QAAI,KAAK,YAAY,WAAW,SAAS,GAAG;AAC1C;AAAA,IACF;AAGA,SAAK,OAAO,KAAK,SAAS;AAC1B,SAAK,IAAI,KAAK,SAAS;AAAA,EACzB;AAAA,EAEA,QAAc;AACZ,SAAK,WAAW,MAAM;AACtB,SAAK,aAAa,MAAM;AACxB,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA;AAAA,EAIA,WAAuB;AACrB,WAAO;AAAA,MACL,gBAAgB,KAAK,WAAW;AAAA,MAChC,cAAc,KAAK,QAAQ;AAAA,MAC3B,oBACE,KAAK,WAAW,OAAO,IAAI,KAAK,QAAQ,OAAO,KAAK,WAAW,OAAO;AAAA,IAC1E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAuC;AACrC,QAAI,eAAe;AACnB,QAAI,oBAAoB;AAExB,eAAW,QAAQ,KAAK,WAAW,OAAO,GAAG;AAC3C,UAAI,KAAK,OAAO,cAAc;AAC5B,uBAAe,KAAK;AAAA,MACtB;AAAA,IACF;AAEA,eAAW,UAAU,KAAK,aAAa,OAAO,GAAG;AAC/C,2BAAqB,OAAO;AAAA,IAC9B;AAEA,WAAO;AAAA,MACL,GAAG,KAAK,SAAS;AAAA,MACjB,aAAa,KAAK,WAAW;AAAA,MAC7B,sBACE,KAAK,aAAa,OAAO,IAAI,oBAAoB,KAAK,aAAa,OAAO;AAAA,MAC5E,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,cAAoC;AAClC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,OAAwB;AAC/B,WAAO,KAAK,WAAW,IAAI,KAAK;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,OAAuB;AAC3C,WAAO,KAAK,WAAW,IAAI,KAAK,GAAG,QAAQ;AAAA,EAC7C;AAAA;AAAA,EAIQ,YAAY,GAAQ,GAAiB;AAC3C,QAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,aAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,UAAI,EAAE,CAAC,MAAM,EAAE,CAAC,EAAG,QAAO;AAAA,IAC5B;AACA,WAAO;AAAA,EACT;AACF;AAxUa,eAYa,iBAAiB;AAZ9B,eAaa,oBAAoB,CAAC,YAAY,eAAe,eAAe,KAAK;AAbvF,IAAM,gBAAN;;;ACQA,IAAM,iBAAN,MAAM,eAAoD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgC/D,YACE,YACA,UAAgC,CAAC,GACjC;AAlCF,SAAS,OAAO;AAMhB;AAAA,SAAQ,OAA4B,oBAAI,IAAI;AAG5C;AAAA,SAAQ,UAAkB,oBAAI,IAAI;AA0BhC,QAAI,WAAW,SAAS,GAAG;AACzB,YAAM,IAAI,MAAM,8CAA8C;AAAA,IAChE;AACA,SAAK,cAAc;AACnB,SAAK,YAAY,QAAQ,aAAa;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,YAAmC;AACrC,WAAO,KAAK,YAAY,CAAC;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,aAAsC;AACxC,WAAO,CAAC,GAAG,KAAK,WAAW;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,eAAuB;AACzB,WAAO,KAAK,YAAY,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG;AAAA,EACrD;AAAA,EAEA,mBAA2B;AACzB,WAAO,eAAc;AAAA,EACvB;AAAA,EAEA,cAAc,WAA4B;AACxC,WAAO,cAAc;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,SAAS,OAA0C;AACjD,QAAI,MAAM,SAAS,YAAY;AAC7B,YAAM,IAAI,MAAM,2DAA2D,MAAM,IAAI,EAAE;AAAA,IACzF;AAEA,UAAM,gBAAgB;AACtB,UAAM,SAAS,cAAc;AAE7B,QAAI,OAAO,WAAW,KAAK,YAAY,QAAQ;AAC7C,YAAM,IAAI;AAAA,QACR,0BAA0B,KAAK,YAAY,MAAM,gBAAgB,OAAO,MAAM;AAAA,MAChF;AAAA,IACF;AAEA,UAAM,eAAe,KAAK,kBAAkB,MAAM;AAClD,UAAM,OAAO,KAAK,KAAK,IAAI,YAAY;AAEvC,WAAO,IAAI;AAAA,MACT,OAAO,IAAI,IAAI,IAAI,IAAI,oBAAI,IAAI;AAAA,MAC/B,eAAc;AAAA,IAChB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,oBAAoB,QAAiC;AACnD,WAAO,KAAK,SAAS,EAAE,MAAM,YAAY,OAAO,CAAwB;AAAA,EAC1E;AAAA,EAEA,IAAI,KAAQ,QAAiB;AAC3B,UAAM,eAAe,KAAK,4BAA4B,MAAM;AAC5D,QAAI,iBAAiB,KAAM;AAE3B,QAAI,OAAO,KAAK,KAAK,IAAI,YAAY;AACrC,QAAI,CAAC,MAAM;AACT,aAAO,oBAAI,IAAI;AACf,WAAK,KAAK,IAAI,cAAc,IAAI;AAAA,IAClC;AACA,SAAK,IAAI,GAAG;AACZ,SAAK,QAAQ,IAAI,GAAG;AAAA,EACtB;AAAA,EAEA,OAAO,KAAQ,QAAiB;AAC9B,UAAM,eAAe,KAAK,4BAA4B,MAAM;AAC5D,QAAI,iBAAiB,KAAM;AAE3B,UAAM,OAAO,KAAK,KAAK,IAAI,YAAY;AACvC,QAAI,MAAM;AACR,WAAK,OAAO,GAAG;AACf,UAAI,KAAK,SAAS,GAAG;AACnB,aAAK,KAAK,OAAO,YAAY;AAAA,MAC/B;AAAA,IACF;AACA,SAAK,QAAQ,OAAO,GAAG;AAAA,EACzB;AAAA,EAEA,OAAO,KAAQ,WAAc,WAAoB;AAC/C,UAAM,SAAS,KAAK,4BAA4B,SAAS;AACzD,UAAM,SAAS,KAAK,4BAA4B,SAAS;AAGzD,QAAI,WAAW,QAAQ;AACrB;AAAA,IACF;AAEA,SAAK,OAAO,KAAK,SAAS;AAC1B,SAAK,IAAI,KAAK,SAAS;AAAA,EACzB;AAAA,EAEA,QAAc;AACZ,SAAK,KAAK,MAAM;AAChB,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA,EAEA,WAAuB;AACrB,QAAI,eAAe;AACnB,eAAW,QAAQ,KAAK,KAAK,OAAO,GAAG;AACrC,sBAAgB,KAAK;AAAA,IACvB;AAEA,WAAO;AAAA,MACL,gBAAgB,KAAK,KAAK;AAAA,MAC1B;AAAA,MACA,oBAAoB,KAAK,KAAK,OAAO,IAAI,eAAe,KAAK,KAAK,OAAO;AAAA,IAC3E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAuC;AACrC,UAAM,QAAQ,KAAK,SAAS;AAC5B,WAAO;AAAA,MACL,GAAG;AAAA,MACH,gBAAgB,KAAK,YAAY;AAAA,MACjC,gBAAgB,KAAK,YAAY,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,MAClD,mBAAmB,KAAK,KAAK;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,eAAe,gBAAmC;AAChD,QAAI,eAAe,WAAW,KAAK,YAAY,QAAQ;AACrD,aAAO;AAAA,IACT;AAGA,aAAS,IAAI,GAAG,IAAI,eAAe,QAAQ,KAAK;AAC9C,UAAI,eAAe,CAAC,MAAM,KAAK,YAAY,CAAC,EAAE,MAAM;AAClD,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,QAA2B;AACnD,WAAO,OAAO,IAAI,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC,EAAE,KAAK,KAAK,SAAS;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,4BAA4B,QAA0B;AAC5D,UAAM,SAAoB,CAAC;AAE3B,eAAW,QAAQ,KAAK,aAAa;AACnC,YAAM,QAAQ,KAAK,SAAS,MAAM;AAClC,UAAI,UAAU,QAAW;AACvB,eAAO;AAAA,MACT;AACA,aAAO,KAAK,KAAK;AAAA,IACnB;AAEA,WAAO,KAAK,kBAAkB,MAAM;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAY,OAAwB;AAC1C,QAAI,UAAU,KAAM,QAAO;AAC3B,QAAI,UAAU,OAAW,QAAO;AAEhC,UAAM,MAAM,OAAO,KAAK;AAExB,WAAO,IAAI;AAAA,MACT,IAAI,OAAO,KAAK,YAAY,KAAK,SAAS,GAAG,GAAG;AAAA,MAChD,KAAK,KAAK,SAAS;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAY,KAAqB;AACvC,WAAO,IAAI,QAAQ,uBAAuB,MAAM;AAAA,EAClD;AACF;AAAA;AArQa,eAgBa,iBAAiB;AAhBpC,IAAM,gBAAN;AAsRA,SAAS,gBAAsB,OAA2D;AAC/F,SAAO,MAAM,SAAS;AACxB;;;AC5SO,IAAM,gBAAN,MAA2D;AAAA,EAmBhE,YACW,WACT,UAA4B,CAAC,GAC7B;AAFS;AAnBX,SAAS,OAAO;AAChB,SAAS,SAAS;AAGlB;AAAA,SAAQ,aAAwC;AAGhD;AAAA,SAAQ,iBAA4B,oBAAI,IAAI;AAG5C;AAAA,SAAQ,QAAQ;AAYd,SAAK,aAAa,QAAQ;AAC1B,SAAK,oBAAoB,QAAQ,qBAAqB;AAAA,EACxD;AAAA,EAEA,IAAI,UAAmB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,eAAuB;AACzB,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA,EAEA,mBAA2B;AAEzB,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,WAA4B;AACxC,WAAO,CAAC,SAAS,MAAM,KAAK,EAAE,SAAS,SAAS;AAAA,EAClD;AAAA,EAEA,SAAS,OAAoC;AAE3C,QAAI,CAAC,KAAK,OAAO;AACf,WAAK,YAAY;AAAA,IACnB;AACA,WAAO,KAAK,WAAY,SAAS,KAAK;AAAA,EACxC;AAAA,EAEA,IAAI,KAAQ,QAAiB;AAC3B,QAAI,KAAK,OAAO;AACd,WAAK,WAAY,IAAI,KAAK,MAAM;AAAA,IAClC,OAAO;AACL,WAAK,eAAe,IAAI,KAAK,MAAM;AAAA,IACrC;AAAA,EACF;AAAA,EAEA,OAAO,KAAQ,QAAiB;AAC9B,QAAI,KAAK,OAAO;AACd,WAAK,WAAY,OAAO,KAAK,MAAM;AAAA,IACrC,OAAO;AACL,WAAK,eAAe,OAAO,GAAG;AAAA,IAChC;AAAA,EACF;AAAA,EAEA,OAAO,KAAQ,WAAc,WAAoB;AAC/C,QAAI,KAAK,OAAO;AACd,WAAK,WAAY,OAAO,KAAK,WAAW,SAAS;AAAA,IACnD,OAAO;AAEL,WAAK,eAAe,IAAI,KAAK,SAAS;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,QAAI,KAAK,OAAO;AACd,WAAK,WAAY,MAAM;AAAA,IACzB;AACA,SAAK,eAAe,MAAM;AAAA,EAC5B;AAAA,EAEA,WAAuB;AACrB,QAAI,KAAK,OAAO;AACd,aAAO,KAAK,WAAY,SAAS;AAAA,IACnC;AAEA,WAAO;AAAA,MACL,gBAAgB;AAAA,MAChB,cAAc,KAAK,eAAe;AAAA,MAClC,oBAAoB;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,kBAAqD;AAC/D,QAAI,KAAK,MAAO;AAEhB,UAAM,WAAW,oBAAoB,KAAK;AAC1C,UAAM,QAAQ,KAAK,eAAe;AAGlC,SAAK,aAAa,IAAI,UAAmB,KAAK,SAAS;AAGvD,QAAI,YAAY;AAChB,eAAW,CAAC,KAAK,MAAM,KAAK,KAAK,gBAAgB;AAC/C,WAAK,WAAW,IAAI,KAAK,MAAM;AAC/B;AAGA,UAAI,YAAY,YAAY,KAAK,sBAAsB,GAAG;AACxD,cAAM,WAAW,KAAK,MAAO,YAAY,QAAS,GAAG;AACrD,iBAAS,KAAK,UAAU,MAAM,UAAU,WAAW,KAAK;AAAA,MAC1D;AAAA,IACF;AAGA,QAAI,YAAY,QAAQ,GAAG;AACzB,eAAS,KAAK,UAAU,MAAM,KAAK,OAAO,KAAK;AAAA,IACjD;AAGA,SAAK,eAAe,MAAM;AAC1B,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAA2C;AACzC,WAAO,KAAK;AAAA,EACd;AACF;;;AC1IO,IAAM,qBAAN,MAEP;AAAA,EAsBE,YACW,WACT,YACA,UAA4B,CAAC,GAC7B;AAHS;AAtBX,SAAS,OAAO;AAChB,SAAS,SAAS;AAGlB;AAAA,SAAQ,aAA6C;AAGrD;AAAA,SAAQ,iBAA4B,oBAAI,IAAI;AAG5C;AAAA,SAAQ,QAAQ;AAgBd,SAAK,aAAa;AAClB,SAAK,aAAa,QAAQ;AAC1B,SAAK,oBAAoB,QAAQ,qBAAqB;AAAA,EACxD;AAAA,EAEA,IAAI,UAAmB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,eAAuB;AACzB,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA,EAEA,mBAA2B;AAEzB,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,WAA4B;AACxC,WAAO,CAAC,SAAS,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,SAAS,EAAE,SAAS,SAAS;AAAA,EACvF;AAAA,EAEA,SAAS,OAAoC;AAE3C,QAAI,CAAC,KAAK,OAAO;AACf,WAAK,YAAY;AAAA,IACnB;AACA,WAAO,KAAK,WAAY,SAAS,KAAK;AAAA,EACxC;AAAA,EAEA,IAAI,KAAQ,QAAiB;AAC3B,QAAI,KAAK,OAAO;AACd,WAAK,WAAY,IAAI,KAAK,MAAM;AAAA,IAClC,OAAO;AACL,WAAK,eAAe,IAAI,KAAK,MAAM;AAAA,IACrC;AAAA,EACF;AAAA,EAEA,OAAO,KAAQ,QAAiB;AAC9B,QAAI,KAAK,OAAO;AACd,WAAK,WAAY,OAAO,KAAK,MAAM;AAAA,IACrC,OAAO;AACL,WAAK,eAAe,OAAO,GAAG;AAAA,IAChC;AAAA,EACF;AAAA,EAEA,OAAO,KAAQ,WAAc,WAAoB;AAC/C,QAAI,KAAK,OAAO;AACd,WAAK,WAAY,OAAO,KAAK,WAAW,SAAS;AAAA,IACnD,OAAO;AAEL,WAAK,eAAe,IAAI,KAAK,SAAS;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,QAAI,KAAK,OAAO;AACd,WAAK,WAAY,MAAM;AAAA,IACzB;AACA,SAAK,eAAe,MAAM;AAAA,EAC5B;AAAA,EAEA,WAAuB;AACrB,QAAI,KAAK,OAAO;AACd,aAAO,KAAK,WAAY,SAAS;AAAA,IACnC;AAEA,WAAO;AAAA,MACL,gBAAgB;AAAA,MAChB,cAAc,KAAK,eAAe;AAAA,MAClC,oBAAoB;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,kBAAqD;AAC/D,QAAI,KAAK,MAAO;AAEhB,UAAM,WAAW,oBAAoB,KAAK;AAC1C,UAAM,QAAQ,KAAK,eAAe;AAGlC,SAAK,aAAa,IAAI,eAAwB,KAAK,WAAW,KAAK,UAAU;AAG7E,QAAI,YAAY;AAChB,eAAW,CAAC,KAAK,MAAM,KAAK,KAAK,gBAAgB;AAC/C,WAAK,WAAW,IAAI,KAAK,MAAM;AAC/B;AAGA,UAAI,YAAY,YAAY,KAAK,sBAAsB,GAAG;AACxD,cAAM,WAAW,KAAK,MAAO,YAAY,QAAS,GAAG;AACrD,iBAAS,KAAK,UAAU,MAAM,UAAU,WAAW,KAAK;AAAA,MAC1D;AAAA,IACF;AAGA,QAAI,YAAY,QAAQ,GAAG;AACzB,eAAS,KAAK,UAAU,MAAM,KAAK,OAAO,KAAK;AAAA,IACjD;AAGA,SAAK,eAAe,MAAM;AAC1B,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgD;AAC9C,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAA6B;AAC3B,QAAI,CAAC,KAAK,OAAO;AACf,WAAK,YAAY;AAAA,IACnB;AACA,WAAO,KAAK,WAAY,YAAY;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAA6B;AAC3B,QAAI,CAAC,KAAK,OAAO;AACf,WAAK,YAAY;AAAA,IACnB;AACA,WAAO,KAAK,WAAY,YAAY;AAAA,EACtC;AACF;;;ACxKO,IAAM,oBAAN,MAEP;AAAA,EAsBE,YACW,WACT,UACA,UAA4B,CAAC,GAC7B;AAHS;AAtBX,SAAS,OAAO;AAChB,SAAS,SAAS;AAGlB;AAAA,SAAQ,aAA4C;AAGpD;AAAA,SAAQ,iBAA4B,oBAAI,IAAI;AAG5C;AAAA,SAAQ,QAAQ;AAgBd,SAAK,WAAW,YAAY,qBAAqB,OAAO;AACxD,SAAK,aAAa,QAAQ;AAC1B,SAAK,oBAAoB,QAAQ,qBAAqB;AAAA,EACxD;AAAA,EAEA,IAAI,UAAmB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,eAAuB;AACzB,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA,EAEA,mBAA2B;AAEzB,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,WAA4B;AACxC,WAAO,CAAC,YAAY,eAAe,eAAe,KAAK,EAAE,SAAS,SAAS;AAAA,EAC7E;AAAA,EAEA,SAAS,OAAoC;AAE3C,QAAI,CAAC,KAAK,OAAO;AACf,WAAK,YAAY;AAAA,IACnB;AACA,WAAO,KAAK,WAAY,SAAS,KAAK;AAAA,EACxC;AAAA,EAEA,IAAI,KAAQ,QAAiB;AAC3B,QAAI,KAAK,OAAO;AACd,WAAK,WAAY,IAAI,KAAK,MAAM;AAAA,IAClC,OAAO;AACL,WAAK,eAAe,IAAI,KAAK,MAAM;AAAA,IACrC;AAAA,EACF;AAAA,EAEA,OAAO,KAAQ,QAAiB;AAC9B,QAAI,KAAK,OAAO;AACd,WAAK,WAAY,OAAO,KAAK,MAAM;AAAA,IACrC,OAAO;AACL,WAAK,eAAe,OAAO,GAAG;AAAA,IAChC;AAAA,EACF;AAAA,EAEA,OAAO,KAAQ,WAAc,WAAoB;AAC/C,QAAI,KAAK,OAAO;AACd,WAAK,WAAY,OAAO,KAAK,WAAW,SAAS;AAAA,IACnD,OAAO;AAEL,WAAK,eAAe,IAAI,KAAK,SAAS;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,QAAI,KAAK,OAAO;AACd,WAAK,WAAY,MAAM;AAAA,IACzB;AACA,SAAK,eAAe,MAAM;AAAA,EAC5B;AAAA,EAEA,WAAuB;AACrB,QAAI,KAAK,OAAO;AACd,aAAO,KAAK,WAAY,SAAS;AAAA,IACnC;AAEA,WAAO;AAAA,MACL,gBAAgB;AAAA,MAChB,cAAc,KAAK,eAAe;AAAA,MAClC,oBAAoB;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBAAuC;AACrC,QAAI,CAAC,KAAK,OAAO;AACf,WAAK,YAAY;AAAA,IACnB;AACA,WAAO,KAAK,WAAY,iBAAiB;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,kBAAqD;AAC/D,QAAI,KAAK,MAAO;AAEhB,UAAM,WAAW,oBAAoB,KAAK;AAC1C,UAAM,QAAQ,KAAK,eAAe;AAGlC,SAAK,aAAa,IAAI,cAAuB,KAAK,WAAW,KAAK,QAAQ;AAG1E,QAAI,YAAY;AAChB,eAAW,CAAC,KAAK,MAAM,KAAK,KAAK,gBAAgB;AAC/C,WAAK,WAAW,IAAI,KAAK,MAAM;AAC/B;AAGA,UAAI,YAAY,YAAY,KAAK,sBAAsB,GAAG;AACxD,cAAM,WAAW,KAAK,MAAO,YAAY,QAAS,GAAG;AACrD,iBAAS,KAAK,UAAU,MAAM,UAAU,WAAW,KAAK;AAAA,MAC1D;AAAA,IACF;AAGA,QAAI,YAAY,QAAQ,GAAG;AACzB,eAAS,KAAK,UAAU,MAAM,KAAK,OAAO,KAAK;AAAA,IACjD;AAGA,SAAK,eAAe,MAAM;AAC1B,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAA+C;AAC7C,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,cAAoC;AAClC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,OAAwB;AAC/B,QAAI,CAAC,KAAK,OAAO;AACf,WAAK,YAAY;AAAA,IACnB;AACA,WAAO,KAAK,WAAY,SAAS,KAAK;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,sBAAsB,OAAuB;AAC3C,QAAI,CAAC,KAAK,OAAO;AACf,WAAK,YAAY;AAAA,IACnB;AACA,WAAO,KAAK,WAAY,sBAAsB,KAAK;AAAA,EACrD;AACF;;;ACpMO,IAAM,wBAAN,MAAuD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAY5D,YAAY,YAA4B;AAVxC;AAAA,SAAQ,SAAqB;AAY3B,SAAK,mBAAmB,CAAC,GAAG,UAAU,EAAE;AAAA,MACtC,CAAC,GAAG,MAAM,EAAE,aAAa,IAAI,EAAE,aAAa;AAAA,IAC9C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,EAAE,OAAO,QAAQ,IAAkB;AAEjC,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK;AACZ;AAAA,IACF;AAGA,QAAI,KAAK,iBAAiB,WAAW,GAAG;AACtC;AAAA,IACF;AAGA,UAAM,CAAC,UAAU,GAAG,IAAI,IAAI,KAAK;AAGjC,eAAW,OAAO,UAAU;AAC1B,UAAI,KAAK,MAAM,CAAC,OAAO,GAAG,SAAS,GAAG,CAAC,GAAG;AACxC,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,mBAA2B;AACzB,QAAI,KAAK,iBAAiB,WAAW,GAAG;AACtC,aAAO;AAAA,IACT;AACA,WAAO,KAAK,IAAI,GAAG,KAAK,iBAAiB,IAAI,CAAC,OAAO,GAAG,iBAAiB,CAAC,CAAC;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA,EAKA,eAAuB;AACrB,QAAI,KAAK,iBAAiB,WAAW,GAAG;AACtC,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,iBAAiB,CAAC,EAAE,aAAa;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,KAAiB;AACxB,WAAO,KAAK,iBAAiB,MAAM,CAAC,OAAO,GAAG,SAAS,GAAG,CAAC;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,OAAe;AACb,WAAO,KAAK,QAAQ,EAAE;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAe;AACb,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,CAAC,GAAG,IAAI;AAAA,IACxB;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,UAAmB;AAEjB,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK,OAAO,WAAW;AAAA,IAChC;AAGA,QAAI,KAAK,iBAAiB,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC,GAAG;AACpD,aAAO;AAAA,IACT;AAGA,eAAW,KAAK,MAAM;AACpB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,iBAA0B;AACxB,WAAO,KAAK,WAAW;AAAA,EACzB;AACF;;;ACvHO,IAAM,iBAAN,MAAgD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASrD,YAA6B,YAA4B;AAA5B;AAP7B;AAAA,SAAQ,SAAqB;AAAA,EAO6B;AAAA;AAAA;AAAA;AAAA,EAK1D,EAAE,OAAO,QAAQ,IAAkB;AAEjC,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK;AACZ;AAAA,IACF;AAGA,UAAM,OAAO,oBAAI,IAAO;AAExB,eAAW,MAAM,KAAK,YAAY;AAChC,iBAAW,OAAO,IAAI;AACpB,YAAI,CAAC,KAAK,IAAI,GAAG,GAAG;AAClB,eAAK,IAAI,GAAG;AACZ,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,mBAA2B;AACzB,WAAO,KAAK,WAAW,OAAO,CAAC,KAAK,OAAO;AACzC,YAAM,OAAO,GAAG,iBAAiB;AAEjC,UAAI,SAAS,OAAO,oBAAoB,QAAQ,OAAO,kBAAkB;AACvE,eAAO,OAAO;AAAA,MAChB;AACA,aAAO,KAAK,IAAI,MAAM,MAAM,OAAO,gBAAgB;AAAA,IACrD,GAAG,CAAC;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAKA,eAAuB;AACrB,WAAO,KAAK,WAAW,OAAO,CAAC,KAAK,OAAO,MAAM,GAAG,aAAa,GAAG,CAAC;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,KAAiB;AACxB,WAAO,KAAK,WAAW,KAAK,CAAC,OAAO,GAAG,SAAS,GAAG,CAAC;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKA,OAAe;AACb,WAAO,KAAK,QAAQ,EAAE;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAe;AACb,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,CAAC,GAAG,IAAI;AAAA,IACxB;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,UAAmB;AAEjB,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK,OAAO,WAAW;AAAA,IAChC;AAGA,WAAO,KAAK,WAAW,MAAM,CAAC,OAAO,GAAG,QAAQ,CAAC;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,iBAA0B;AACxB,WAAO,KAAK,WAAW;AAAA,EACzB;AACF;;;AC7FO,IAAM,qBAAN,MAAuD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW5D,YACmB,QACA,WACA,WACjB;AAHiB;AACA;AACA;AAZnB;AAAA,SAAQ,SAAqB;AAAA,EAa1B;AAAA;AAAA;AAAA;AAAA,EAKH,EAAE,OAAO,QAAQ,IAAkB;AAEjC,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK;AACZ;AAAA,IACF;AAEA,eAAW,OAAO,KAAK,QAAQ;AAC7B,YAAM,SAAS,KAAK,UAAU,GAAG;AACjC,UAAI,WAAW,UAAa,KAAK,UAAU,MAAM,GAAG;AAClD,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,mBAA2B;AACzB,WAAO,KAAK,OAAO,iBAAiB,IAAI;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,eAAuB;AACrB,WAAO,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,OAAO,aAAa,IAAI,CAAC,CAAC;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,KAAiB;AACxB,QAAI,CAAC,KAAK,OAAO,SAAS,GAAG,GAAG;AAC9B,aAAO;AAAA,IACT;AACA,UAAM,SAAS,KAAK,UAAU,GAAG;AACjC,WAAO,WAAW,UAAa,KAAK,UAAU,MAAM;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKA,OAAe;AACb,WAAO,KAAK,QAAQ,EAAE;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAe;AACb,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,CAAC,GAAG,IAAI;AAAA,IACxB;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,UAAmB;AAEjB,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK,OAAO,WAAW;AAAA,IAChC;AAGA,eAAW,KAAK,MAAM;AACpB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,iBAA0B;AACxB,WAAO,KAAK,WAAW;AAAA,EACzB;AACF;;;ACnGO,IAAM,kBAAN,MAAoD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAazD,YACmB,QACA,WACA,WACA,WACA,cAAuB,OACxC;AALiB;AACA;AACA;AACA;AACA;AAhBnB;AAAA,SAAQ,SAAqB;AAAA,EAiB1B;AAAA;AAAA;AAAA;AAAA,EAKH,EAAE,OAAO,QAAQ,IAAkB;AAEjC,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK;AACZ;AAAA,IACF;AAGA,QAAI,KAAK,aAAa;AACpB,UAAI,KAAK,cAAc,QAAQ;AAE7B,cAAM,OAAO,CAAC,GAAG,KAAK,MAAM;AAC5B,iBAAS,IAAI,KAAK,SAAS,GAAG,KAAK,GAAG,KAAK;AACzC,gBAAM,KAAK,CAAC;AAAA,QACd;AAAA,MACF,OAAO;AAEL,eAAO,KAAK;AAAA,MACd;AACA;AAAA,IACF;AAGA,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAe;AACb,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,OAAO,CAAC,GAAG,KAAK,MAAM;AAE5B,QAAI,CAAC,KAAK,aAAa;AAErB,WAAK,KAAK,CAAC,GAAG,MAAM;AAClB,cAAM,OAAO,KAAK,UAAU,CAAC;AAC7B,cAAM,OAAO,KAAK,UAAU,CAAC;AAE7B,YAAI,SAAS,UAAa,SAAS,OAAW,QAAO;AACrD,YAAI,SAAS,OAAW,QAAO,KAAK,cAAc,QAAQ,IAAI;AAC9D,YAAI,SAAS,OAAW,QAAO,KAAK,cAAc,QAAQ,KAAK;AAE/D,cAAM,OAAQ,KAAiC,KAAK,SAAS;AAC7D,cAAM,OAAQ,KAAiC,KAAK,SAAS;AAE7D,YAAI,MAAM;AACV,YAAI,SAAS,UAAa,SAAS,MAAM;AACvC,cAAI,SAAS,UAAa,SAAS,MAAM;AACvC,kBAAM;AAAA,UACR,OAAO;AACL,kBAAM;AAAA,UACR;AAAA,QACF,WAAW,SAAS,UAAa,SAAS,MAAM;AAC9C,gBAAM;AAAA,QACR,WAAW,OAAO,MAAM;AACtB,gBAAM;AAAA,QACR,WAAW,OAAO,MAAM;AACtB,gBAAM;AAAA,QACR;AAEA,eAAO,KAAK,cAAc,SAAS,CAAC,MAAM;AAAA,MAC5C,CAAC;AAAA,IACH,WAAW,KAAK,cAAc,QAAQ;AAEpC,WAAK,QAAQ;AAAA,IACf;AAEA,SAAK,SAAS;AACd,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBAA2B;AACzB,UAAM,WAAW,KAAK,OAAO,iBAAiB;AAG9C,UAAM,eAAe,KAAK,cAAc,IAAI;AAC5C,WAAO,WAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKA,eAAuB;AACrB,WAAO,KAAK,OAAO,aAAa;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,KAAiB;AACxB,WAAO,KAAK,OAAO,SAAS,GAAG;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAe;AACb,WAAO,KAAK,OAAO,KAAK;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,UAAmB;AACjB,WAAO,KAAK,OAAO,QAAQ;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,iBAA0B;AACxB,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAyB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,eAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmC;AACjC,WAAO,KAAK;AAAA,EACd;AACF;AAQO,SAAS,sBACd,OACA,WACc;AACd,SAAO,CAAC,GAAM,MAAiB;AAC7B,UAAM,OAAQ,EAA8B,KAAK;AACjD,UAAM,OAAQ,EAA8B,KAAK;AAEjD,QAAI,MAAM;AACV,QAAI,SAAS,UAAa,SAAS,MAAM;AACvC,UAAI,SAAS,UAAa,SAAS,MAAM;AACvC,cAAM;AAAA,MACR,OAAO;AACL,cAAM;AAAA,MACR;AAAA,IACF,WAAW,SAAS,UAAa,SAAS,MAAM;AAC9C,YAAM;AAAA,IACR,WAAW,OAAO,MAAM;AACtB,YAAM;AAAA,IACR,WAAW,OAAO,MAAM;AACtB,YAAM;AAAA,IACR;AAGA,QAAI,QAAQ,EAAG,QAAO;AACtB,WAAO,cAAc,SAAS,CAAC,MAAM;AAAA,EACvC;AACF;;;ACrMO,IAAM,iBAAN,MAAgD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWrD,YACmB,QACA,SAAiB,GACjB,QAAgB,UACjC;AAHiB;AACA;AACA;AAZnB;AAAA,SAAQ,SAAqB;AAAA,EAa1B;AAAA;AAAA;AAAA;AAAA,EAKH,EAAE,OAAO,QAAQ,IAAkB;AAEjC,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK;AACZ;AAAA,IACF;AAGA,QAAI,KAAK,WAAW,KAAK,KAAK,UAAU,UAAU;AAChD,aAAO,KAAK;AACZ;AAAA,IACF;AAEA,QAAI,UAAU;AACd,QAAI,WAAW;AAEf,eAAW,OAAO,KAAK,QAAQ;AAE7B,UAAI,UAAU,KAAK,QAAQ;AACzB;AACA;AAAA,MACF;AAGA,UAAI,YAAY,KAAK,OAAO;AAC1B;AAAA,MACF;AAEA,YAAM;AACN;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,mBAA2B;AACzB,WAAO,KAAK,OAAO,iBAAiB;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,eAAuB;AACrB,UAAM,aAAa,KAAK,OAAO,aAAa;AAC5C,QAAI,KAAK,UAAU,UAAU;AAC3B,aAAO,KAAK,IAAI,GAAG,aAAa,KAAK,MAAM;AAAA,IAC7C;AACA,WAAO,KAAK,IAAI,YAAY,KAAK,SAAS,KAAK,KAAK;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,KAAiB;AAExB,QAAI,CAAC,KAAK,OAAO,SAAS,GAAG,GAAG;AAC9B,aAAO;AAAA,IACT;AAGA,WAAO,KAAK,QAAQ,EAAE,SAAS,GAAG;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAe;AACb,WAAO,KAAK,QAAQ,EAAE;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAe;AACb,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,CAAC,GAAG,IAAI;AAAA,IACxB;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,UAAmB;AAEjB,QAAI,KAAK,QAAQ;AACf,aAAO,KAAK,OAAO,WAAW;AAAA,IAChC;AAGA,QAAI,KAAK,UAAU,GAAG;AACpB,aAAO;AAAA,IACT;AAGA,eAAW,KAAK,MAAM;AACpB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,iBAA0B;AACxB,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,YAAoB;AAClB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,WAAmB;AACjB,WAAO,KAAK;AAAA,EACd;AACF;;;ACtJO,IAAM,gBAAN,MAA0B;AAAA,EAA1B;AAEL;AAAA,SAAQ,mBAAwD,oBAAI,IAAI;AAGxE;AAAA,SAAQ,kBAAoD,oBAAI,IAAI;AAGpE;AAAA,SAAQ,gBAA6C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQrD,SAAY,OAA6B;AAEvC,QAAI,gBAAgB,KAAK,GAAG;AAC1B,WAAK,iBAAiB,KAAuC;AAC7D;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,UAAU;AACjC,QAAI,UAAU,KAAK,iBAAiB,IAAI,QAAQ;AAEhD,QAAI,CAAC,SAAS;AACZ,gBAAU,CAAC;AACX,WAAK,iBAAiB,IAAI,UAAU,OAAO;AAAA,IAC7C;AAGA,QAAI,CAAC,QAAQ,SAAS,KAA6B,GAAG;AACpD,cAAQ,KAAK,KAA6B;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAiB,OAAkC;AACjD,UAAM,MAAM,KAAK,gBAAgB,MAAM,WAAW,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AACpE,SAAK,gBAAgB,IAAI,KAAK,KAAK;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAe,OAAgC;AAE7C,QAAI,gBAAgB,KAAK,GAAG;AAC1B,aAAO,KAAK,oBAAoB,KAAuC;AAAA,IACzE;AAEA,UAAM,WAAW,MAAM,UAAU;AACjC,UAAM,UAAU,KAAK,iBAAiB,IAAI,QAAQ;AAElD,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,QAAQ,QAAQ,KAA6B;AACzD,QAAI,QAAQ,IAAI;AACd,aAAO;AAAA,IACT;AAEA,YAAQ,OAAO,KAAK,CAAC;AAGrB,QAAI,QAAQ,WAAW,GAAG;AACxB,WAAK,iBAAiB,OAAO,QAAQ;AAAA,IACvC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,oBAAoB,OAAqC;AACvD,UAAM,MAAM,KAAK,gBAAgB,MAAM,WAAW,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AACpE,WAAO,KAAK,gBAAgB,OAAO,GAAG;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,eAA+C;AACxD,WAAO,KAAK,iBAAiB,IAAI,aAAa,KAAK,CAAC;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBAAwC;AACtC,UAAM,MAA8B,CAAC;AACrC,eAAW,WAAW,KAAK,iBAAiB,OAAO,GAAG;AACpD,UAAI,KAAK,GAAG,OAAO;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,uBAAiC;AAC/B,WAAO,MAAM,KAAK,KAAK,iBAAiB,KAAK,CAAC;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,eAAgC;AACvC,UAAM,UAAU,KAAK,iBAAiB,IAAI,aAAa;AACvD,WAAO,YAAY,UAAa,QAAQ,SAAS;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,cACE,eACA,WAC6B;AAC7B,UAAM,UAAU,KAAK,WAAW,aAAa;AAC7C,QAAI,OAAoC;AACxC,QAAI,WAAW;AAEf,eAAW,SAAS,SAAS;AAC3B,UAAI,MAAM,cAAc,SAAS,KAAK,MAAM,iBAAiB,IAAI,UAAU;AACzE,eAAO;AACP,mBAAW,MAAM,iBAAiB;AAAA,MACpC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YACE,eACA,WACwB;AACxB,UAAM,UAAU,KAAK,WAAW,aAAa;AAC7C,WAAO,QACJ,OAAO,CAAC,UAAU,MAAM,cAAc,SAAS,CAAC,EAChD,KAAK,CAAC,GAAG,MAAM,EAAE,iBAAiB,IAAI,EAAE,iBAAiB,CAAC;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,kBAAkB,gBAAsD;AACtE,QAAI,eAAe,SAAS,GAAG;AAC7B,aAAO;AAAA,IACT;AAGA,UAAM,MAAM,KAAK,gBAAgB,cAAc;AAC/C,UAAM,aAAa,KAAK,gBAAgB,IAAI,GAAG;AAC/C,QAAI,YAAY;AACd,aAAO;AAAA,IACT;AAIA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,iBAAiB,gBAAmC;AAClD,WAAO,KAAK,kBAAkB,cAAc,MAAM;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,qBAA4C;AAC1C,WAAO,MAAM,KAAK,KAAK,gBAAgB,OAAO,CAAC;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,gBAAkC;AACxD,WAAO,CAAC,GAAG,cAAc,EAAE,KAAK,EAAE,KAAK,GAAG;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,iBAAiB,UAAsC;AACrD,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBAAgD;AAC9C,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,cAAc,KAAQ,QAAiB;AACrC,eAAW,WAAW,KAAK,iBAAiB,OAAO,GAAG;AACpD,iBAAW,SAAS,SAAS;AAC3B,cAAM,IAAI,KAAK,MAAM;AAAA,MACvB;AAAA,IACF;AAEA,eAAW,iBAAiB,KAAK,gBAAgB,OAAO,GAAG;AACzD,oBAAc,IAAI,KAAK,MAAM;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,gBAAgB,KAAQ,WAAc,WAAoB;AACxD,eAAW,WAAW,KAAK,iBAAiB,OAAO,GAAG;AACpD,iBAAW,SAAS,SAAS;AAC3B,cAAM,OAAO,KAAK,WAAW,SAAS;AAAA,MACxC;AAAA,IACF;AAEA,eAAW,iBAAiB,KAAK,gBAAgB,OAAO,GAAG;AACzD,oBAAc,OAAO,KAAK,WAAW,SAAS;AAAA,IAChD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,gBAAgB,KAAQ,QAAiB;AACvC,eAAW,WAAW,KAAK,iBAAiB,OAAO,GAAG;AACpD,iBAAW,SAAS,SAAS;AAC3B,cAAM,OAAO,KAAK,MAAM;AAAA,MAC1B;AAAA,IACF;AAEA,eAAW,iBAAiB,KAAK,gBAAgB,OAAO,GAAG;AACzD,oBAAc,OAAO,KAAK,MAAM;AAAA,IAClC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAc;AACZ,eAAW,WAAW,KAAK,iBAAiB,OAAO,GAAG;AACpD,iBAAW,SAAS,SAAS;AAC3B,cAAM,MAAM;AAAA,MACd;AAAA,IACF;AAEA,eAAW,iBAAiB,KAAK,gBAAgB,OAAO,GAAG;AACzD,oBAAc,MAAM;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,QAAI,QAAQ;AACZ,eAAW,WAAW,KAAK,iBAAiB,OAAO,GAAG;AACpD,eAAS,QAAQ;AAAA,IACnB;AAEA,aAAS,KAAK,gBAAgB;AAC9B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,WAA+B;AAC7B,UAAM,UAAU,KAAK,cAAc;AACnC,UAAM,aAAa,QAAQ,IAAI,CAAC,WAAW;AAAA,MACzC,WAAW,MAAM,UAAU;AAAA,MAC3B,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM,SAAS;AAAA,IACxB,EAAE;AAGF,eAAW,iBAAiB,KAAK,gBAAgB,OAAO,GAAG;AACzD,iBAAW,KAAK;AAAA,QACd,WAAW,cAAc;AAAA,QACzB,MAAM;AAAA,QACN,OAAO,cAAc,SAAS;AAAA,MAChC,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL,cAAc,QAAQ,SAAS,KAAK,gBAAgB;AAAA,MACpD,mBAAmB,KAAK,qBAAqB,EAAE;AAAA,MAC/C,iBAAiB,KAAK,gBAAgB;AAAA,MACtC,SAAS;AAAA,IACX;AAAA,EACF;AACF;;;AC3TO,IAAM,iBAAN,MAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWhC,YACE,wBACA,uBACA;AACA,QAAI,mBAAmB,wBAAwB;AAE7C,WAAK,gBAAgB,uBAAuB;AAC5C,WAAK,wBAAwB,uBAAuB;AACpD,WAAK,kBAAkB,uBAAuB,mBAAmB,oBAAI,IAAI;AAAA,IAC3E,OAAO;AAEL,WAAK,gBAAgB;AACrB,WAAK,wBAAwB;AAC7B,WAAK,kBAAkB,oBAAI,IAAI;AAAA,IACjC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,sBAAsB,OAAe,OAA4B;AAC/D,SAAK,gBAAgB,IAAI,OAAO,KAAK;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,wBAAwB,OAAqB;AAC3C,SAAK,gBAAgB,OAAO,KAAK;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,iBAAiB,OAA0C;AACzD,WAAO,KAAK,gBAAgB,IAAI,KAAK;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,iBAAiB,OAAwB;AACvC,WAAO,KAAK,gBAAgB,IAAI,KAAK;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,SAAS,OAAyB;AAEhC,QAAI,KAAK,uBAAuB;AAC9B,YAAM,gBAAgB,KAAK,sBAAsB,SAAS,KAAK;AAC/D,UAAI,eAAe;AACjB,eAAO;AAAA,UACL,MAAM;AAAA,YACJ,MAAM;AAAA,YACN,OAAO;AAAA,YACP,OAAO,EAAE,MAAM,SAAS,OAAO,KAAK;AAAA;AAAA,UACtC;AAAA,UACA,eAAe,cAAc,iBAAiB;AAAA,UAC9C,aAAa;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAGA,UAAM,OAAO,KAAK,aAAa,KAAK;AACpC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,eAAe,KAAK,aAAa,IAAI;AAAA,MACrC,aAAa,KAAK,YAAY,IAAI;AAAA,IACpC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,oBAAoB,OAAc,SAAkC;AAClE,UAAM,WAAW,KAAK,SAAS,KAAK;AAGpC,QAAI,CAAC,QAAQ,QAAQ,QAAQ,UAAU,UAAa,QAAQ,WAAW,QAAW;AAChF,aAAO;AAAA,IACT;AAEA,QAAI,cAAc;AAClB,QAAI;AACJ,QAAI;AAGJ,QAAI,QAAQ,MAAM;AAChB,YAAM,aAAa,OAAO,KAAK,QAAQ,IAAI;AAC3C,UAAI,WAAW,SAAS,GAAG;AACzB,oBAAY,WAAW,CAAC;AACxB,wBAAgB,QAAQ,KAAK,SAAS;AAGtC,cAAM,YAAY,KAAK,cAAc,cAAc,WAAW,KAAK;AACnE,YAAI,WAAW,SAAS,aAAa;AACnC,wBAAc;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA,MACE,aAAa,gBACT,EAAE,OAAO,WAAW,WAAW,cAAc,IAC7C;AAAA,MACN,OAAO,QAAQ;AAAA,MACf,QAAQ,QAAQ;AAAA;AAAA,IAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,OAAwB;AAC3C,QAAI,eAAe,KAAK,GAAG;AACzB,aAAO,KAAK,gBAAgB,KAAK;AAAA,IACnC,WAAW,WAAW,KAAK,GAAG;AAC5B,aAAO,KAAK,YAAY,KAAK;AAAA,IAC/B,WAAW,cAAc,KAAK,GAAG;AAC/B,aAAO,KAAK,eAAe,KAAK;AAAA,IAClC,OAAO;AAEL,aAAO,EAAE,MAAM,aAAa,WAAW,MAAM;AAAA,IAC/C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAY,OAA+B;AACjD,UAAM,QAAQ,MAAM;AAGpB,QAAI,CAAC,KAAK,iBAAiB,KAAK,GAAG;AAEjC,aAAO,EAAE,MAAM,aAAa,WAAW,MAAM;AAAA,IAC/C;AAGA,WAAO,KAAK,iBAAiB,KAAK;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,OAAkC;AACzD,UAAM,QAAQ,MAAM;AAEpB,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN;AAAA,UACA,OAAO,MAAM;AAAA,UACb,SAAS;AAAA,UACT,SAAS,MAAM;AAAA,UACf,eAAe;AAAA,UACf,eAAe,KAAK,gBAAgB,KAAK;AAAA,QAC3C;AAAA,MAEF,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN;AAAA,UACA,OAAO,MAAM;AAAA,UACb,SAAS;AAAA,UACT,SAAS,MAAM,SAAS,SAAY,EAAE,WAAW,MAAM,KAAK,IAAI;AAAA,UAChE,eAAe;AAAA,UACf,eAAe,KAAK,gBAAgB,KAAK;AAAA,QAC3C;AAAA,MAEF,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN;AAAA,UACA,OAAO,MAAM;AAAA,UACb,SAAS;AAAA,UACT,SAAS,MAAM,kBAAkB,SAAY,EAAE,WAAW,MAAM,cAAc,IAAI;AAAA,UAClF,eAAe;AAAA,UACf,eAAe,KAAK,gBAAgB,KAAK;AAAA,QAC3C;AAAA,MAEF;AACE,cAAM,IAAI,MAAM,2BAA4B,MAAuB,IAAI,EAAE;AAAA,IAC7E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,OAAuB;AAC7C,UAAM,QAAQ,KAAK,gBAAgB,IAAI,KAAK;AAC5C,QAAI,CAAC,OAAO;AACV,aAAO,OAAO;AAAA,IAChB;AAIA,UAAM,WAAW,MAAM,QAAQ;AAG/B,WAAO,KAAK,KAAK,KAAK,WAAW,CAAC,IAAI;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,mBAAmB,YAA2C;AAC5D,UAAM,SAA+B;AAAA,MACnC,iBAAiB,CAAC;AAAA,MAClB,iBAAiB,CAAC;AAAA,MAClB,eAAe,CAAC;AAAA,MAChB,iBAAiB,CAAC;AAAA,IACpB;AAEA,eAAW,QAAQ,YAAY;AAC7B,UAAI,WAAW,IAAI,GAAG;AACpB,eAAO,cAAc,KAAK,IAAI;AAAA,MAChC,WAAW,cAAc,IAAI,GAAG;AAC9B,gBAAQ,KAAK,MAAM;AAAA,UACjB,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AACH,mBAAO,gBAAgB,KAAK,IAAI;AAChC;AAAA,UACF,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AACH,mBAAO,gBAAgB,KAAK,IAAI;AAChC;AAAA,UACF;AACE,mBAAO,gBAAgB,KAAK,IAAI;AAAA,QACpC;AAAA,MACF,WAAW,eAAe,IAAI,GAAG;AAE/B,eAAO,gBAAgB,KAAK,IAAI;AAAA,MAClC,OAAO;AACL,eAAO,gBAAgB,KAAK,IAAI;AAAA,MAClC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,wBAAwB,OAAmC;AACzD,UAAM,YAAY,MAAM,KAAK,CAAC,MAAM,KAAK,kBAAkB,CAAC,CAAC;AAC7D,UAAM,YAAY,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,kBAAkB,CAAC,CAAC;AAE9D,QAAI,aAAa,WAAW;AAE1B,aAAO;AAAA,IACT,WAAW,WAAW;AAEpB,aAAO;AAAA,IACT,OAAO;AAEL,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,MAAyB;AACjD,YAAQ,KAAK,MAAM;AAAA,MACjB,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO,KAAK;AAAA,MACd;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,OAAkC;AAEvD,UAAM,iBAAiB,KAAK,aAAa,MAAM,IAAI;AAGnD,UAAM,QAAQ,KAAK,cAAc,cAAc,MAAM,WAAW,cAAc;AAE9E,QAAI,OAAO;AAET,YAAM,aAAa,KAAK,gBAAgB,KAAK;AAC7C,aAAO,EAAE,MAAM,cAAc,OAAO,OAAO,WAAW;AAAA,IACxD;AAGA,WAAO,EAAE,MAAM,aAAa,WAAW,MAAM;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,OAAmC;AACzD,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,eAAO,KAAK,YAAY,KAAK;AAAA,MAC/B,KAAK;AACH,eAAO,KAAK,WAAW,KAAK;AAAA,MAC9B,KAAK;AACH,eAAO,KAAK,YAAY,KAAK;AAAA,MAC/B;AACE,cAAM,IAAI,MAAM,+BAA+B,MAAM,IAAI,EAAE;AAAA,IAC/D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,YAAY,OAAmC;AACrD,QAAI,CAAC,MAAM,YAAY,MAAM,SAAS,WAAW,GAAG;AAClD,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAGA,QAAI,MAAM,SAAS,WAAW,GAAG;AAC/B,aAAO,KAAK,aAAa,MAAM,SAAS,CAAC,CAAC;AAAA,IAC5C;AAGA,UAAM,eAAe,KAAK,iBAAiB,MAAM,QAAQ;AACzD,QAAI,cAAc;AAChB,aAAO;AAAA,IACT;AAGA,UAAM,aAAa,MAAM,SAAS,IAAI,CAAC,UAAU,KAAK,aAAa,KAAK,CAAC;AAGzE,UAAM,kBAAkB,WACrB,IAAI,CAAC,MAAM,WAAW,EAAE,MAAM,eAAe,MAAM,EAAE,EACrD,KAAK,CAAC,GAAG,MAAM,KAAK,aAAa,EAAE,IAAI,IAAI,KAAK,aAAa,EAAE,IAAI,CAAC;AAEvE,UAAM,cAAc,gBAAgB,IAAI,CAAC,MAAM,EAAE,IAAI;AAGrD,UAAM,eAAe,YAAY,OAAO,CAAC,MAAM,EAAE,SAAS,YAAY;AACtE,UAAM,gBAAgB,YAAY,OAAO,CAAC,MAAM,EAAE,SAAS,WAAW;AAGtE,QAAI,aAAa,WAAW,GAAG;AAC7B,aAAO,EAAE,MAAM,aAAa,WAAW,MAAM;AAAA,IAC/C;AAGA,QAAI,aAAa,WAAW,GAAG;AAC7B,YAAM,CAAC,SAAS,IAAI;AAEpB,UAAI,cAAc,WAAW,GAAG;AAC9B,eAAO;AAAA,MACT;AAGA,YAAM,sBAAsB,cAAc,IAAI,CAAC,MAAM;AACnD,YAAI,EAAE,SAAS,aAAa;AAC1B,iBAAO,EAAE;AAAA,QACX;AACA,cAAM,IAAI,MAAM,8CAA8C;AAAA,MAChE,CAAC;AAED,YAAM,kBACJ,oBAAoB,WAAW,IAC3B,oBAAoB,CAAC,IACrB,EAAE,MAAM,OAAO,UAAU,oBAAoB;AAEnD,aAAO,EAAE,MAAM,UAAU,QAAQ,WAAW,WAAW,gBAAgB;AAAA,IACzE;AAIA,WAAO,EAAE,MAAM,gBAAgB,OAAO,aAAa;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,iBAAiB,UAAoC;AAE3D,UAAM,YAA+B,CAAC;AACtC,UAAM,eAAwB,CAAC;AAE/B,eAAW,SAAS,UAAU;AAC5B,UAAI,cAAc,KAAK,KAAK,MAAM,SAAS,MAAM;AAC/C,kBAAU,KAAK,KAAK;AAAA,MACtB,OAAO;AACL,qBAAa,KAAK,KAAK;AAAA,MACzB;AAAA,IACF;AAGA,QAAI,UAAU,SAAS,GAAG;AACxB,aAAO;AAAA,IACT;AAGA,UAAM,iBAAiB,UAAU,IAAI,CAAC,MAAM,EAAE,SAAS;AAGvD,UAAM,gBAAgB,KAAK,cAAc,kBAAkB,cAAc;AACzE,QAAI,CAAC,eAAe;AAClB,aAAO;AAAA,IACT;AAGA,UAAM,SAAS,KAAK,oBAAoB,eAAe,SAAS;AAChE,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,IACT;AAGA,UAAM,eAAyB;AAAA,MAC7B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,EAAE,MAAM,YAAY,OAAO;AAAA,IACpC;AAGA,QAAI,aAAa,SAAS,GAAG;AAC3B,YAAM,kBACJ,aAAa,WAAW,IACpB,aAAa,CAAC,IACd,EAAE,MAAM,OAAO,UAAU,aAAa;AAE5C,aAAO,EAAE,MAAM,UAAU,QAAQ,cAAc,WAAW,gBAAgB;AAAA,IAC5E;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,oBACN,eACA,WACkB;AAClB,UAAM,iBAAiB,cAAc,WAAW,IAAI,CAAC,MAAM,EAAE,IAAI;AACjE,UAAM,SAAoB,CAAC;AAG3B,UAAM,WAAW,oBAAI,IAAqB;AAC1C,eAAW,KAAK,WAAW;AACzB,eAAS,IAAI,EAAE,WAAW,EAAE,KAAK;AAAA,IACnC;AAGA,eAAW,YAAY,gBAAgB;AACrC,UAAI,CAAC,SAAS,IAAI,QAAQ,GAAG;AAC3B,eAAO;AAAA,MACT;AACA,aAAO,KAAK,SAAS,IAAI,QAAQ,CAAC;AAAA,IACpC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,WAAW,OAAmC;AACpD,QAAI,CAAC,MAAM,YAAY,MAAM,SAAS,WAAW,GAAG;AAClD,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AAGA,QAAI,MAAM,SAAS,WAAW,GAAG;AAC/B,aAAO,KAAK,aAAa,MAAM,SAAS,CAAC,CAAC;AAAA,IAC5C;AAEA,UAAM,aAAa,MAAM,SAAS,IAAI,CAAC,UAAU,KAAK,aAAa,KAAK,CAAC;AAGzE,QAAI,WAAW,MAAM,CAAC,MAAM,EAAE,SAAS,WAAW,GAAG;AACnD,aAAO,EAAE,MAAM,aAAa,WAAW,MAAM;AAAA,IAC/C;AAGA,WAAO,EAAE,MAAM,SAAS,OAAO,WAAW;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAY,OAAmC;AACrD,QAAI,CAAC,MAAM,OAAO;AAChB,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AAEA,UAAM,YAAY,KAAK,aAAa,MAAM,KAAK;AAE/C,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,SAAS,MAAM,oBAAI,IAAI;AAAA;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,aAAa,MAAsB;AACzC,UAAM,UAAkC;AAAA,MACtC,IAAI;AAAA,MACJ,KAAK;AAAA;AAAA,MACL,IAAI;AAAA,MACJ,KAAK;AAAA,MACL,IAAI;AAAA,MACJ,KAAK;AAAA,MACL,IAAI;AAAA,MACJ,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,UAAU;AAAA,MACV,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AACA,WAAO,QAAQ,IAAI,KAAK;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,OAA6C;AACnE,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AAAA,MACL,KAAK;AACH,eAAO,EAAE,MAAM,SAAS,OAAO,MAAM,MAAM;AAAA,MAC7C,KAAK;AACH,eAAO,EAAE,MAAM,MAAM,OAAO,MAAM,MAAM;AAAA,MAC1C,KAAK;AACH,eAAO,EAAE,MAAM,OAAO,OAAO,MAAM,MAAM;AAAA,MAC3C,KAAK;AACH,eAAO,EAAE,MAAM,MAAM,OAAO,MAAM,MAAM;AAAA,MAC1C,KAAK;AACH,eAAO,EAAE,MAAM,OAAO,OAAO,MAAM,MAAM;AAAA,MAC3C,KAAK;AACH,eAAO,EAAE,MAAM,MAAM,QAAQ,MAAM,OAAO;AAAA,MAC5C,KAAK;AACH,eAAO,EAAE,MAAM,MAAM;AAAA,MACvB,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM,MAAM;AAAA,UACZ,IAAI,MAAM;AAAA,UACV,eAAe,MAAM;AAAA,UACrB,aAAa,MAAM;AAAA,QACrB;AAAA,MACF,KAAK;AACH,eAAO,EAAE,MAAM,YAAY,OAAO,MAAM,MAAM;AAAA,MAChD,KAAK;AACH,eAAO,EAAE,MAAM,eAAe,QAAQ,MAAM,OAAO;AAAA,MACrD,KAAK;AACH,eAAO,EAAE,MAAM,eAAe,QAAQ,MAAM,OAAO;AAAA,MACrD;AACE,cAAM,IAAI,MAAM,sCAAsC,MAAM,IAAI,EAAE;AAAA,IACtE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,MAAwB;AAC3C,YAAQ,KAAK,MAAM;AAAA,MACjB,KAAK;AACH,eAAO,KAAK,MAAM,iBAAiB;AAAA,MAErC,KAAK;AACH,eAAO,OAAO;AAAA,MAEhB,KAAK;AAEH,eAAO,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC;AAAA,MAEhE,KAAK;AAEH,eAAO,KAAK,MAAM,OAAO,CAAC,KAAK,MAAM;AACnC,gBAAM,OAAO,KAAK,aAAa,CAAC;AAEhC,cAAI,SAAS,OAAO,kBAAkB;AACpC,mBAAO,OAAO;AAAA,UAChB;AACA,iBAAO,KAAK,IAAI,MAAM,MAAM,OAAO,gBAAgB;AAAA,QACrD,GAAG,CAAC;AAAA,MAEN,KAAK;AAEH,eAAO,KAAK,aAAa,KAAK,MAAM,IAAI;AAAA,MAE1C,KAAK;AAEH,eAAO,KAAK,aAAa,KAAK,MAAM,IAAI;AAAA;AAAA,MAG1C,KAAK;AACH,eAAO,KAAK;AAAA,MAEd,KAAK;AAEH,eAAO,KAAK,MAAM,OAAO,CAAC,KAAK,MAAM;AACnC,gBAAM,OAAO,KAAK,aAAa,CAAC;AAChC,cAAI,SAAS,OAAO,kBAAkB;AACpC,mBAAO,OAAO;AAAA,UAChB;AACA,iBAAO,KAAK,IAAI,MAAM,MAAM,OAAO,gBAAgB;AAAA,QACrD,GAAG,CAAC,IAAI;AAAA;AAAA,MAEV;AACE,eAAO,OAAO;AAAA,IAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAY,MAAyB;AAC3C,YAAQ,KAAK,MAAM;AAAA,MACjB,KAAK;AACH,eAAO;AAAA,MAET,KAAK;AACH,eAAO;AAAA,MAET,KAAK;AAAA,MACL,KAAK;AACH,eAAO,KAAK,MAAM,KAAK,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC;AAAA,MAEnD,KAAK;AACH,eAAO,KAAK,YAAY,KAAK,MAAM;AAAA,MAErC,KAAK;AACH,eAAO,KAAK,YAAY,KAAK,MAAM;AAAA;AAAA,MAGrC,KAAK;AACH,eAAO;AAAA;AAAA,MAET,KAAK;AACH,eAAO,KAAK,MAAM,KAAK,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC;AAAA,MAEnD;AACE,eAAO;AAAA,IACX;AAAA,EACF;AACF;;;ACxuBO,IAAM,wBAAN,MAAkC;AAAA,EAavC,YAAY,SAA6C;AAXzD;AAAA,SAAQ,UAAiD,oBAAI,IAAI;AAGjE;AAAA,SAAQ,YAAiC,oBAAI,IAAI;AAS/C,SAAK,YAAY,QAAQ;AACzB,SAAK,gBAAgB,QAAQ;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,SAAS,OAAwC;AAC/C,UAAM,OAAO,KAAK,UAAU,KAAK;AAEjC,QAAI,QAAQ,KAAK,QAAQ,IAAI,IAAI;AACjC,QAAI,OAAO;AAET,WAAK,UAAU,IAAI,OAAO,KAAK,UAAU,IAAI,IAAI,KAAK,KAAK,CAAC;AAC5D,aAAO;AAAA,IACT;AAGA,UAAM,UAA2C;AAAA,MAC/C;AAAA,MACA,WAAW,KAAK;AAAA,IAClB;AACA,YAAQ,IAAI,mBAAmB,OAAO;AAGtC,UAAM,cAAc,KAAK,cAAc,CAAC;AAExC,SAAK,QAAQ,IAAI,MAAM,KAAK;AAC5B,SAAK,UAAU,IAAI,MAAM,CAAC;AAE1B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,WAAW,OAAuB;AAChC,UAAM,OAAO,KAAK,UAAU,KAAK;AACjC,UAAM,WAAW,KAAK,UAAU,IAAI,IAAI,KAAK;AAE7C,QAAI,YAAY,GAAG;AACjB,WAAK,QAAQ,OAAO,IAAI;AACxB,WAAK,UAAU,OAAO,IAAI;AAC1B,aAAO;AAAA,IACT;AAEA,SAAK,UAAU,IAAI,MAAM,WAAW,CAAC;AACrC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,OAAoD;AAC3D,UAAM,OAAO,KAAK,UAAU,KAAK;AACjC,WAAO,KAAK,QAAQ,IAAI,IAAI;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAe,MAAoD;AACjE,WAAO,KAAK,QAAQ,IAAI,IAAI;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,OAAuB;AAC9B,UAAM,OAAO,KAAK,UAAU,KAAK;AACjC,WAAO,KAAK,QAAQ,IAAI,IAAI;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,OAAsB;AAChC,UAAM,OAAO,KAAK,UAAU,KAAK;AACjC,WAAO,KAAK,UAAU,IAAI,IAAI,KAAK;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,cAAc,KAAQ,QAA6C;AACjE,UAAM,UAAU,oBAAI,IAAiC;AAErD,eAAW,CAAC,MAAM,KAAK,KAAK,KAAK,SAAS;AACxC,YAAM,SAAS,MAAM,gBAAgB,KAAK,QAAW,MAAM;AAC3D,UAAI,WAAW,aAAa;AAC1B,cAAM,IAAI,KAAK,MAAM;AACrB,gBAAQ,IAAI,MAAM,MAAM;AAAA,MAC1B;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,gBACE,KACA,WACA,WACkC;AAClC,UAAM,UAAU,oBAAI,IAAiC;AAErD,eAAW,CAAC,MAAM,KAAK,KAAK,KAAK,SAAS;AACxC,YAAM,SAAS,MAAM,gBAAgB,KAAK,WAAW,SAAS;AAC9D,UAAI,WAAW,aAAa;AAC1B,cAAM,OAAO,KAAK,WAAW,SAAS;AACtC,gBAAQ,IAAI,MAAM,MAAM;AAAA,MAC1B;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,gBAAgB,KAAQ,QAA6C;AACnE,UAAM,UAAU,oBAAI,IAAiC;AAErD,eAAW,CAAC,MAAM,KAAK,KAAK,KAAK,SAAS;AACxC,YAAM,SAAS,MAAM,gBAAgB,KAAK,QAAQ,MAAS;AAC3D,UAAI,WAAW,aAAa;AAC1B,cAAM,OAAO,KAAK,MAAM;AACxB,gBAAQ,IAAI,MAAM,MAAM;AAAA,MAC1B;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,uBAAgC;AAC9B,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAI,CAAC,QAAQ,IAAI,SAAS,CAAC;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAA2B;AACzB,WAAO,MAAM,KAAK,KAAK,QAAQ,KAAK,CAAC;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAuC;AACrC,WAAO;AAAA,MACL,YAAY,KAAK,QAAQ;AAAA,MACzB,eAAe,MAAM,KAAK,KAAK,UAAU,OAAO,CAAC,EAAE;AAAA,QACjD,CAAC,GAAG,MAAM,IAAI;AAAA,QACd;AAAA,MACF;AAAA,MACA,cAAc,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE;AAAA,QAC9C,CAAC,KAAK,QAAQ,MAAM,IAAI,eAAe;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,eAAW,SAAS,KAAK,QAAQ,OAAO,GAAG;AACzC,YAAM,MAAM;AAAA,IACd;AACA,SAAK,QAAQ,MAAM;AACnB,SAAK,UAAU,MAAM;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,OAAsB;AAC9B,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B;AACF;;;ACnOO,IAAM,mBAAN,MAA6B;AAAA,EAMlC,YAAY,SAAwC;AAFpD;AAAA,SAAQ,gBAA2D,oBAAI,IAAI;AAGzE,UAAM,kBAAsD;AAAA,MAC1D,WAAW,QAAQ;AAAA,MACnB,eAAe,QAAQ;AAAA,IACzB;AACA,SAAK,WAAW,IAAI,sBAAsB,eAAe;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,UAAU,OAAc,UAA+C;AACrE,UAAM,OAAO,KAAK,SAAS,UAAU,KAAK;AAG1C,UAAM,QAAQ,KAAK,SAAS,SAAS,KAAK;AAG1C,QAAI,YAAY,KAAK,cAAc,IAAI,IAAI;AAC3C,QAAI,CAAC,WAAW;AACd,kBAAY,oBAAI,IAAI;AACpB,WAAK,cAAc,IAAI,MAAM,SAAS;AAAA,IACxC;AACA,cAAU,IAAI,QAAQ;AAGtB,UAAM,iBAAiB,MAAM,KAAK,MAAM,WAAW,CAAC;AACpD,QAAI;AACF,eAAS;AAAA,QACP,MAAM;AAAA,QACN;AAAA,QACA,SAAS;AAAA,MACX,CAAC;AAAA,IACH,SAAS,OAAO;AACd,cAAQ,MAAM,4CAA4C,KAAK;AAAA,IACjE;AAGA,WAAO,MAAM;AACX,iBAAW,OAAO,QAAQ;AAC1B,UAAI,WAAW,SAAS,GAAG;AACzB,aAAK,cAAc,OAAO,IAAI;AAAA,MAChC;AACA,WAAK,SAAS,WAAW,KAAK;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,WAAW,OAAmB;AAC5B,UAAM,QAAQ,KAAK,SAAS,SAAS,KAAK;AAC1C,WAAO,QAAQ,MAAM,KAAK,MAAM,WAAW,CAAC,IAAI,CAAC;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAe,OAAuB;AACpC,UAAM,OAAO,KAAK,SAAS,UAAU,KAAK;AAC1C,UAAM,YAAY,KAAK,cAAc,IAAI,IAAI;AAC7C,WAAO,cAAc,UAAa,UAAU,OAAO;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,mBAAmB,OAAsB;AACvC,UAAM,OAAO,KAAK,SAAS,UAAU,KAAK;AAC1C,UAAM,YAAY,KAAK,cAAc,IAAI,IAAI;AAC7C,WAAO,WAAW,QAAQ;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,cAAc,KAAQ,QAAiB;AACrC,UAAM,UAAU,KAAK,SAAS,cAAc,KAAK,MAAM;AACvD,SAAK,kBAAkB,KAAK,QAAQ,SAAS,OAAO;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,gBAAgB,KAAQ,WAAc,WAAoB;AACxD,UAAM,UAAU,KAAK,SAAS,gBAAgB,KAAK,WAAW,SAAS;AACvE,SAAK,kBAAkB,KAAK,WAAW,SAAS,SAAS;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,gBAAgB,KAAQ,QAAiB;AACvC,UAAM,UAAU,KAAK,SAAS,gBAAgB,KAAK,MAAM;AACzD,SAAK,kBAAkB,KAAK,QAAQ,SAAS,SAAS;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA,EAKQ,kBACN,KACA,QACA,SACA,WACM;AACN,eAAW,CAAC,MAAM,MAAM,KAAK,SAAS;AACpC,YAAM,YAAY,KAAK,cAAc,IAAI,IAAI;AAC7C,UAAI,CAAC,aAAa,UAAU,SAAS,EAAG;AAExC,YAAM,QAAQ,KAAK,SAAS,eAAe,IAAI;AAC/C,UAAI,CAAC,MAAO;AAEZ,YAAM,QAAQ,MAAM,SAAS;AAE7B,iBAAW,YAAY,WAAW;AAChC,YAAI;AACF,mBAAS;AAAA,YACP,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,gBAAgB,MAAM,eAAe;AAAA,UACvC,CAAC;AAAA,QACH,SAAS,OAAO;AAEd,kBAAQ,MAAM,oCAAoC,KAAK;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAA2C;AACzC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBAA6B;AAC3B,WAAO,MAAM,KAAK,KAAK,cAAc,KAAK,CAAC;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAkC;AAChC,UAAM,gBAAgB,KAAK,SAAS,SAAS;AAC7C,UAAM,mBAAmB,MAAM,KAAK,KAAK,cAAc,OAAO,CAAC,EAAE;AAAA,MAC/D,CAAC,KAAK,cAAc,MAAM,UAAU;AAAA,MACpC;AAAA,IACF;AAEA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,eAAe,KAAK,cAAc;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,cAAc,MAAM;AACzB,SAAK,SAAS,MAAM;AAAA,EACtB;AACF;;;AClFO,IAAM,6BAA6B;AAAA,EACxC,SAAS;AAAA,IACP,SAAS;AAAA,IACT,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACA,WAAW;AAAA,IACT,SAAS;AAAA,IACT,WAAW;AAAA,IACX,YAAY;AAAA,EACd;AACF;AAMO,IAAM,uBAAuB;AAK7B,IAAM,4BAA4B;AAAA;AAAA,EAEvC,MAAM;AAAA;AAAA,EAEN,WAAW;AAAA;AAAA,EAEX,UAAU;AAAA;AAAA,EAEV,UAAU;AACZ;;;ACrLA,SAAS,aAAa,WAAmB,WAAuC;AAC9E,SAAO,GAAG,SAAS,IAAI,SAAS;AAClC;AAKA,SAAS,cAAc,KAAmE;AACxF,QAAM,aAAa,IAAI,YAAY,GAAG;AACtC,SAAO;AAAA,IACL,WAAW,IAAI,MAAM,GAAG,UAAU;AAAA,IAClC,WAAW,IAAI,MAAM,aAAa,CAAC;AAAA,EACrC;AACF;AAqBO,IAAM,sBAAN,MAA0B;AAAA,EAQ/B,YAAY,UAAsC,CAAC,GAAG;AAPtD,SAAQ,QAAQ,oBAAI,IAA+B;AACnD,SAAQ,gBAAgB,oBAAI,IAAqC;AACjE,SAAQ,eAAe;AAMrB,SAAK,eAAe,QAAQ,gBAAgB;AAC5C,SAAK,qBAAqB,QAAQ,sBAAsB;AACxD,SAAK,WAAW,QAAQ,YAAY,KAAK,KAAK,KAAK;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,YACE,WACA,WACA,eACA,YACA,UACM;AAEN,SAAK;AACL,QAAI,KAAK,eAAe,KAAK,KAAK,eAAe,KAAK,iBAAiB,GAAG;AACxE;AAAA,IACF;AAEA,UAAM,MAAM,aAAa,WAAW,SAAS;AAC7C,UAAM,WAAW,KAAK,MAAM,IAAI,GAAG;AACnC,UAAM,MAAM,KAAK,IAAI;AAErB,QAAI,UAAU;AAEZ,eAAS;AACT,eAAS,aAAa;AACtB,eAAS,cAAc,SAAS,YAAY,SAAS;AACrD,eAAS,cAAc;AACvB,eAAS,uBAAuB,KAAK,IAAI,SAAS,sBAAsB,UAAU;AAClF,eAAS,WAAW;AAAA,IACtB,OAAO;AAEL,UAAI,KAAK,MAAM,QAAQ,KAAK,oBAAoB;AAC9C,aAAK,YAAY;AAAA,MACnB;AAGA,WAAK,MAAM,IAAI,KAAK;AAAA,QAClB;AAAA,QACA;AAAA,QACA,YAAY,KAAK;AAAA;AAAA,QACjB,WAAW,gBAAgB,KAAK;AAAA,QAChC,aAAa;AAAA,QACb,aAAa;AAAA,QACb,sBAAsB;AAAA,QACtB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,oBACE,YACA,eACA,YACA,kBACM;AAEN,QAAI,WAAW,SAAS,EAAG;AAG3B,SAAK;AACL,QAAI,KAAK,eAAe,KAAK,KAAK,eAAe,KAAK,iBAAiB,GAAG;AACxE;AAAA,IACF;AAGA,UAAM,cAAc,CAAC,GAAG,UAAU,EAAE,KAAK;AACzC,UAAM,cAAc,YAAY,KAAK,GAAG;AACxC,UAAM,WAAW,KAAK,cAAc,IAAI,WAAW;AACnD,UAAM,MAAM,KAAK,IAAI;AAErB,QAAI,UAAU;AAEZ,eAAS;AACT,eAAS,aAAa;AACtB,eAAS,cAAc,SAAS,YAAY,SAAS;AACrD,eAAS,cAAc;AACvB,eAAS,mBAAmB;AAAA,IAC9B,OAAO;AAEL,UAAI,KAAK,cAAc,QAAQ,KAAK,oBAAoB;AACtD,aAAK,oBAAoB;AAAA,MAC3B;AAGA,WAAK,cAAc,IAAI,aAAa;AAAA,QAClC,YAAY;AAAA,QACZ;AAAA,QACA,YAAY,KAAK;AAAA;AAAA,QACjB,WAAW,gBAAgB,KAAK;AAAA,QAChC,aAAa;AAAA,QACb,aAAa;AAAA,QACb;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,wBAAmD;AACjD,SAAK,mBAAmB;AACxB,WAAO,MAAM,KAAK,KAAK,cAAc,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU;AAAA,EAC3F;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,iBAAiB,YAA2D;AAC1E,UAAM,cAAc,CAAC,GAAG,UAAU,EAAE,KAAK;AACzC,UAAM,cAAc,YAAY,KAAK,GAAG;AACxC,WAAO,KAAK,cAAc,IAAI,WAAW;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,oBAAoB,WAA4B;AAC9C,eAAW,QAAQ,KAAK,cAAc,OAAO,GAAG;AAC9C,UAAI,KAAK,WAAW,SAAS,SAAS,GAAG;AACvC,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,0BAA0B,YAAsB,kBAAiC;AAC/E,UAAM,cAAc,CAAC,GAAG,UAAU,EAAE,KAAK;AACzC,UAAM,cAAc,YAAY,KAAK,GAAG;AACxC,UAAM,OAAO,KAAK,cAAc,IAAI,WAAW;AAC/C,QAAI,MAAM;AACR,WAAK,mBAAmB;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBAAmC;AACjC,SAAK,WAAW;AAChB,WAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU;AAAA,EACnF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,kBAAkB,WAAsC;AACtD,WAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,cAAc,SAAS;AAAA,EAChF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,SAAS,WAAmB,WAA0D;AACpF,UAAM,MAAM,aAAa,WAAW,SAAS;AAC7C,WAAO,KAAK,MAAM,IAAI,GAAG;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,SAAS,WAA4B;AACnC,eAAW,OAAO,KAAK,MAAM,KAAK,GAAG;AACnC,UAAI,IAAI,WAAW,YAAY,GAAG,GAAG;AACnC,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,qBAA6B;AAC3B,QAAI,QAAQ;AACZ,eAAW,QAAQ,KAAK,MAAM,OAAO,GAAG;AACtC,eAAS,KAAK;AAAA,IAChB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,kBAA0B;AACxB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,kBAAkB,WAAmB,UAAyB;AAC5D,eAAW,CAAC,KAAK,IAAI,KAAK,KAAK,MAAM,QAAQ,GAAG;AAC9C,YAAM,SAAS,cAAc,GAAG;AAChC,UAAI,OAAO,cAAc,WAAW;AAClC,aAAK,WAAW;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,oBAAoB,WAAyB;AAC3C,eAAW,OAAO,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,GAAG;AAC/C,YAAM,SAAS,cAAc,GAAG;AAChC,UAAI,OAAO,cAAc,WAAW;AAClC,aAAK,MAAM,OAAO,GAAG;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,MAAM,MAAM;AACjB,SAAK,cAAc,MAAM;AACzB,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,kBAME;AAEA,UAAM,iBAAiB,KAAK,MAAM,OAAO,MAAM,KAAK,cAAc,OAAO;AAEzE,WAAO;AAAA,MACL,iBAAiB,KAAK,MAAM;AAAA,MAC5B,yBAAyB,KAAK,cAAc;AAAA,MAC5C,cAAc,KAAK;AAAA,MACnB,cAAc,KAAK;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAoB;AAC1B,QAAI,YAA6B;AACjC,QAAI,aAAa;AAEjB,eAAW,CAAC,KAAK,IAAI,KAAK,KAAK,MAAM,QAAQ,GAAG;AAC9C,UAAI,KAAK,cAAc,YAAY;AACjC,qBAAa,KAAK;AAClB,oBAAY;AAAA,MACd;AAAA,IACF;AAEA,QAAI,WAAW;AACb,WAAK,MAAM,OAAO,SAAS;AAAA,IAC7B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAmB;AACzB,UAAM,SAAS,KAAK,IAAI,IAAI,KAAK;AAEjC,eAAW,CAAC,KAAK,IAAI,KAAK,KAAK,MAAM,QAAQ,GAAG;AAC9C,UAAI,KAAK,cAAc,QAAQ;AAC7B,aAAK,MAAM,OAAO,GAAG;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,sBAA4B;AAClC,QAAI,YAA2B;AAC/B,QAAI,aAAa;AAEjB,eAAW,CAAC,KAAK,IAAI,KAAK,KAAK,cAAc,QAAQ,GAAG;AACtD,UAAI,KAAK,cAAc,YAAY;AACjC,qBAAa,KAAK;AAClB,oBAAY;AAAA,MACd;AAAA,IACF;AAEA,QAAI,WAAW;AACb,WAAK,cAAc,OAAO,SAAS;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAA2B;AACjC,UAAM,SAAS,KAAK,IAAI,IAAI,KAAK;AAEjC,eAAW,CAAC,KAAK,IAAI,KAAK,KAAK,cAAc,QAAQ,GAAG;AACtD,UAAI,KAAK,cAAc,QAAQ;AAC7B,aAAK,cAAc,OAAO,GAAG;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AACF;;;AC1ZO,IAAM,eAAN,MAAmB;AAAA,EACxB,YAA6B,SAA8B;AAA9B;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ5D,eAAe,UAAkC,CAAC,GAAsB;AACtE,UAAM;AAAA,MACJ,gBAAgB,2BAA2B,QAAQ;AAAA,MACnD,iBAAiB,2BAA2B,QAAQ;AAAA,MACpD,yBAAyB;AAAA,MACzB;AAAA,IACF,IAAI;AAEJ,UAAM,QAAQ,KAAK,QAAQ,cAAc;AACzC,UAAM,cAAiC,CAAC;AAGxC,UAAM,iBAAiB,KAAK,iBAAiB,KAAK;AAElD,eAAW,CAAC,WAAW,SAAS,KAAK,eAAe,QAAQ,GAAG;AAE7D,YAAM,WAAW,KAAK,gBAAgB,WAAW,sBAAsB;AACvE,UAAI,CAAC,SAAU;AAGf,UAAI,SAAS,aAAa,cAAe;AACzC,UAAI,SAAS,cAAc,eAAgB;AAG3C,YAAM,aAAa,KAAK,mBAAmB,UAAU,SAAS;AAC9D,UAAI,YAAY;AACd,oBAAY,KAAK,UAAU;AAAA,MAC7B;AAAA,IACF;AAGA,UAAM,sBAAsB,KAAK,uBAAuB;AAAA,MACtD;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,gBAAY,KAAK,GAAG,mBAAmB;AAGvC,gBAAY,KAAK,CAAC,GAAG,MAAM;AACzB,YAAM,gBAAgB,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,EAAE;AACnD,YAAM,eAAe,cAAc,EAAE,QAAQ,IAAI,cAAc,EAAE,QAAQ;AACzE,UAAI,iBAAiB,EAAG,QAAO;AAC/B,aAAO,EAAE,mBAAmB,EAAE;AAAA,IAChC,CAAC;AAGD,QAAI,mBAAmB,UAAa,YAAY,SAAS,gBAAgB;AACvE,aAAO,YAAY,MAAM,GAAG,cAAc;AAAA,IAC5C;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,0BAA0B,WAA2C;AACnE,UAAM,YAAY,KAAK,QAAQ,kBAAkB,SAAS;AAC1D,QAAI,UAAU,WAAW,EAAG,QAAO;AAEnC,UAAM,WAAW,KAAK,gBAAgB,WAAW,IAAI;AACrD,QAAI,CAAC,SAAU,QAAO;AAEtB,WAAO,KAAK,mBAAmB,UAAU,SAAS;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YAAY,WAAmB,YAAoB,2BAA2B,UAAU,WAAqB;AAC3G,UAAM,YAAY,KAAK,QAAQ,kBAAkB,SAAS;AAC1D,QAAI,UAAU,WAAW,EAAG,QAAO;AAGnC,eAAW,QAAQ,WAAW;AAC5B,UAAI,CAAC,KAAK,YAAY,KAAK,cAAc,WAAW;AAClD,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,wBAAwB,WAA0D;AAChF,WAAO,KAAK,gBAAgB,SAAS;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,OAA0D;AACjF,UAAM,UAAU,oBAAI,IAA+B;AAEnD,eAAW,QAAQ,OAAO;AACxB,YAAM,WAAW,QAAQ,IAAI,KAAK,SAAS;AAC3C,UAAI,UAAU;AACZ,iBAAS,KAAK,IAAI;AAAA,MACpB,OAAO;AACL,gBAAQ,IAAI,KAAK,WAAW,CAAC,IAAI,CAAC;AAAA,MACpC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,gBACN,OACA,wBACwB;AACxB,QAAI,OAA+B;AACnC,QAAI,YAAY;AAEhB,eAAW,QAAQ,OAAO;AAExB,UAAI,0BAA0B,KAAK,SAAU;AAG7C,UAAI,CAAC,KAAK,gBAAgB,KAAK,SAAS,EAAG;AAG3C,YAAM,QAAQ,KAAK,aAAa,KAAK;AACrC,UAAI,QAAQ,WAAW;AACrB,oBAAY;AACZ,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,mBACN,MACA,cACwB;AACxB,UAAM,YAAY,KAAK,gBAAgB,KAAK,SAAS;AACrD,QAAI,CAAC,UAAW,QAAO;AAGvB,UAAM,qBAAqB,KAAK,wBAAwB,cAAc,SAAS;AAE/E,UAAM,mBAAmB,KAAK,gBAAgB,MAAM,kBAAkB;AACtE,UAAM,gBAAgB,KAAK,mBAAmB,MAAM,SAAS;AAC7D,UAAM,WAAW,KAAK,kBAAkB,MAAM,gBAAgB;AAG9D,UAAM,kBAAkB,aAAa,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,YAAY,CAAC;AAE7E,WAAO;AAAA,MACL,WAAW,KAAK;AAAA,MAChB;AAAA,MACA,QAAQ,KAAK,eAAe,MAAM,kBAAkB,kBAAkB;AAAA,MACtE;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ,aAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,WAA0D;AAChF,YAAQ,WAAW;AAAA,MACjB,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AACH,eAAO;AAAA,MAET,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AACH,eAAO;AAAA,MAET,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AACH,eAAO;AAAA,MAET;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,wBACN,OACA,WACQ;AACR,QAAI,QAAQ;AAEZ,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,SAAU;AACnB,YAAM,cAAc,KAAK,gBAAgB,KAAK,SAAS;AACvD,UAAI,gBAAgB,WAAW;AAC7B;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,gBAAgB,MAAuB,oBAAoC;AAEjF,QAAI;AACJ,QAAI,KAAK,cAAc,IAAI;AACzB,oBAAc;AAAA,IAChB,WAAW,KAAK,cAAc,GAAG;AAC/B,oBAAc;AAAA,IAChB,OAAO;AACL,oBAAc;AAAA,IAChB;AAGA,UAAM,sBAAsB,KAAK,IAAI,KAAK,aAAa,IAAI,GAAG;AAG9D,UAAM,eAAe,qBAAqB,IAAI,qBAAqB;AAEnE,WAAO,KAAK,MAAM,cAAc,sBAAsB,YAAY;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAmB,MAAuB,WAAyC;AACzF,UAAM,iBAAiB,0BAA0B,SAAS;AAI1D,WAAO,KAAK,MAAM,KAAK,uBAAuB,iBAAiB,GAAG;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,MAAuB,kBAA8C;AAE7F,QAAI,KAAK,aAAa,OAAO,KAAK,cAAc,IAAI;AAClD,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,aAAa,KAAK;AACzB,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,aAAa,MAAM,KAAK,cAAc,GAAG;AAChD,aAAO;AAAA,IACT;AAGA,QAAI,mBAAmB,KAAM;AAC3B,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,eACN,MACA,SACA,oBACQ;AACR,UAAM,UAAU,KAAK,YAAY,QAAQ,CAAC;AAC1C,QAAI,SAAS,WAAW,KAAK,UAAU,0BAAuB,OAAO;AACrE,cAAU,aAAa,OAAO;AAE9B,QAAI,qBAAqB,GAAG;AAC1B,gBAAU,kBAAkB,kBAAkB;AAAA,IAChD;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,uBAAuB,UAAkC,CAAC,GAAsB;AAC9E,UAAM;AAAA,MACJ,gBAAgB,2BAA2B,QAAQ;AAAA,MACnD,iBAAiB,2BAA2B,QAAQ;AAAA,MACpD,yBAAyB;AAAA,IAC3B,IAAI;AAEJ,UAAM,gBAAgB,KAAK,QAAQ,sBAAsB;AACzD,UAAM,cAAiC,CAAC;AAExC,eAAW,QAAQ,eAAe;AAEhC,UAAI,0BAA0B,KAAK,iBAAkB;AAGrD,UAAI,KAAK,aAAa,cAAe;AACrC,UAAI,KAAK,cAAc,eAAgB;AAEvC,YAAM,aAAa,KAAK,2BAA2B,IAAI;AACvD,UAAI,YAAY;AACd,oBAAY,KAAK,UAAU;AAAA,MAC7B;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,yBAAyB,YAA8C;AACrE,UAAM,OAAO,KAAK,QAAQ,iBAAiB,UAAU;AACrD,QAAI,CAAC,KAAM,QAAO;AAElB,WAAO,KAAK,2BAA2B,IAAI;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,0BACE,YACA,YAAoB,2BAA2B,UAAU,WAChD;AACT,UAAM,OAAO,KAAK,QAAQ,iBAAiB,UAAU;AACrD,QAAI,CAAC,KAAM,QAAO;AAElB,WAAO,CAAC,KAAK,oBAAoB,KAAK,cAAc;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKQ,2BAA2B,MAAuD;AACxF,UAAM,mBAAmB,KAAK,wBAAwB,IAAI;AAC1D,UAAM,gBAAgB,KAAK,2BAA2B,IAAI;AAC1D,UAAM,WAAW,KAAK,0BAA0B,MAAM,gBAAgB;AAEtE,WAAO;AAAA,MACL,WAAW,KAAK;AAAA,MAChB,WAAW;AAAA,MACX,QAAQ,KAAK,uBAAuB,MAAM,gBAAgB;AAAA,MAC1D;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB,oBAAoB,KAAK;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,wBAAwB,MAAuC;AAGrE,UAAM,sBAAsB,KAAK,IAAI,GAAG,KAAK,WAAW,SAAS,CAAC;AAGlE,QAAI;AACJ,QAAI,KAAK,cAAc,IAAI;AACzB,oBAAc;AAAA,IAChB,WAAW,KAAK,cAAc,GAAG;AAC/B,oBAAc;AAAA,IAChB,WAAW,KAAK,cAAc,GAAG;AAC/B,oBAAc;AAAA,IAChB,OAAO;AACL,oBAAc;AAAA,IAChB;AAGA,UAAM,sBAAsB,KAAK,IAAI,KAAK,aAAa,IAAI,GAAG;AAE9D,WAAO,KAAK,MAAM,cAAc,sBAAsB,mBAAmB;AAAA,EAC3E;AAAA;AAAA;AAAA;AAAA,EAKQ,2BAA2B,MAAuC;AACxE,UAAM,iBAAiB,0BAA0B;AAGjD,UAAM,oBAAoB,KAAK,WAAW,SAAS;AAGnD,UAAM,mBAAmB;AAEzB,WAAO,KAAK,MAAM,oBAAoB,iBAAiB,qBAAqB,GAAG;AAAA,EACjF;AAAA;AAAA;AAAA;AAAA,EAKQ,0BACN,MACA,kBACoB;AAEpB,QAAI,KAAK,aAAa,OAAO,KAAK,cAAc,IAAI;AAClD,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,aAAa,KAAK;AACzB,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,aAAa,MAAM,KAAK,cAAc,GAAG;AAChD,aAAO;AAAA,IACT;AAGA,QAAI,mBAAmB,KAAM;AAC3B,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,uBAAuB,MAA+B,SAAyB;AACrF,UAAM,UAAU,KAAK,YAAY,QAAQ,CAAC;AAC1C,UAAM,WAAW,KAAK,WAAW,KAAK,IAAI;AAC1C,QAAI,SAAS,0BAA0B,QAAQ,cAAc,KAAK,UAAU,0BAAuB,OAAO;AAC1G,cAAU,aAAa,OAAO;AAC9B,cAAU,cAAc,KAAK,WAAW,SAAS,CAAC;AAElD,WAAO;AAAA,EACT;AACF;;;ACtdO,IAAM,mBAAN,MAA6B;AAAA,EAOlC,YACmB,SACA,SACjB,QACA;AAHiB;AACA;AAPnB,SAAiB,uBAAuB,oBAAI,IAAoB;AAChE,SAAiB,uBAAuB,oBAAI,IAA6C;AACzF,SAAiB,iBAAiB,oBAAI,IAAY;AAClD,SAAQ,MAAiC;AAOvC,SAAK,SAAS;AAAA,MACZ,SAAS,OAAO;AAAA,MAChB,WAAW,OAAO,aAAa,2BAA2B,UAAU;AAAA,MACpE,YAAY,OAAO,cAAc,2BAA2B,UAAU;AAAA,MACtE,gBAAgB,OAAO,mBAAmB,MAAM;AAAA,MAAC;AAAA,IACnD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,KAA+B;AACpC,SAAK,MAAM;AAEX,eAAW,SAAS,IAAI,WAAW,GAAG;AACpC,WAAK,eAAe,IAAI,MAAM,UAAU,IAAI;AAAA,IAC9C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,kBACE,WACA,mBACM;AACN,SAAK,qBAAqB,IAAI,UAAU,MAAM;AAAA,MAC5C;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,oBAAoB,eAA6B;AAC/C,SAAK,qBAAqB,OAAO,aAAa;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,eAAgC;AAC3C,WAAO,KAAK,qBAAqB,IAAI,aAAa;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,eAA0D;AACrE,WAAO,KAAK,qBAAqB,IAAI,aAAa,GAAG;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,8BAAwC;AACtC,WAAO,MAAM,KAAK,KAAK,qBAAqB,KAAK,CAAC;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,WAAmB,WAAmC;AACpE,QAAI,CAAC,KAAK,OAAO,QAAS;AAC1B,QAAI,CAAC,KAAK,IAAK;AAGf,QAAI,KAAK,eAAe,IAAI,SAAS,EAAG;AACxC,QAAI,KAAK,IAAI,WAAW,SAAS,GAAG;AAClC,WAAK,eAAe,IAAI,SAAS;AACjC;AAAA,IACF;AAGA,UAAM,MAAM,GAAG,SAAS,IAAI,SAAS;AACrC,UAAM,SAAS,KAAK,qBAAqB,IAAI,GAAG,KAAK,KAAK;AAC1D,SAAK,qBAAqB,IAAI,KAAK,KAAK;AAGxC,QAAI,UAAU,KAAK,OAAO,WAAW;AACnC,WAAK,eAAe,WAAW,SAAS;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAqB;AACnB,QAAI,CAAC,KAAK,IAAK,QAAO;AACtB,WAAO,KAAK,IAAI,WAAW,EAAE,UAAU,KAAK,OAAO;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,2BAAmC;AACjC,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,uBAA+B;AAC7B,QAAI,CAAC,KAAK,IAAK,QAAO,KAAK,OAAO;AAClC,WAAO,KAAK,IAAI,GAAG,KAAK,OAAO,aAAa,KAAK,IAAI,WAAW,EAAE,MAAM;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA,EAKA,cAAoB;AAClB,SAAK,qBAAqB,MAAM;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,YAAuC;AACrC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAa,SAAyC;AACpD,QAAI,QAAQ,YAAY,QAAW;AACjC,WAAK,OAAO,UAAU,QAAQ;AAAA,IAChC;AACA,QAAI,QAAQ,cAAc,QAAW;AACnC,WAAK,OAAO,YAAY,QAAQ;AAAA,IAClC;AACA,QAAI,QAAQ,eAAe,QAAW;AACpC,WAAK,OAAO,aAAa,QAAQ;AAAA,IACnC;AACA,QAAI,QAAQ,mBAAmB,QAAW;AACxC,WAAK,OAAO,iBAAiB,QAAQ;AAAA,IACvC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,WAAmB,WAAmC;AAC3E,QAAI,CAAC,KAAK,IAAK;AAGf,QAAI,KAAK,UAAU,GAAG;AAEpB;AAAA,IACF;AAGA,UAAM,aAAa,KAAK,qBAAqB,IAAI,SAAS;AAC1D,QAAI,CAAC,YAAY;AAEf;AAAA,IACF;AAGA,UAAM,YAAY,KAAK,QAAQ,wBAAwB,SAAS;AAChE,QAAI,CAAC,UAAW;AAGhB,QACE,WAAW,qBACX,CAAC,WAAW,kBAAkB,SAAS,SAAS,GAChD;AACA;AAAA,IACF;AAGA,SAAK,YAAY,WAAW,WAAW,WAAW,SAAS;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKQ,YACN,eACA,WACA,WACM;AACN,QAAI,CAAC,KAAK,IAAK;AAEf,QAAI;AACF,cAAQ,WAAW;AAAA,QACjB,KAAK;AACH,eAAK,IAAI,aAAa,SAAS;AAC/B;AAAA,QACF,KAAK;AACH,eAAK,IAAI,kBAAkB,SAA0C;AACrE;AAAA,QACF,KAAK;AACH,eAAK,IAAI,iBAAiB,SAAiC;AAC3D;AAAA,MACJ;AAGA,WAAK,eAAe,IAAI,aAAa;AAGrC,WAAK,QAAQ,kBAAkB,eAAe,IAAI;AAGlD,WAAK,OAAO,eAAe,eAAe,SAAS;AAAA,IACrD,SAAS,OAAO;AAEd,cAAQ,MAAM,sCAAsC,SAAS,cAAc,aAAa,MAAM,KAAK;AAAA,IACrG;AAAA,EACF;AACF;;;AC7OO,IAAM,0BAAN,MAAiC;AAAA,EAGtC,YAA6B,UAAwB;AAAxB;AAF7B,SAAQ,UAAU;AAAA,EAEoC;AAAA;AAAA;AAAA;AAAA,EAKtD,YAAqB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,KAA6B,QAAiB;AACvD,QAAI,KAAK,aAAa,OAAQ;AAC9B,QAAI,KAAK,QAAS;AAElB,UAAM,kBAAkB,KAAK,oBAAoB,MAAM;AAEvD,eAAW,OAAO,iBAAiB;AACjC,UAAI,IAAI,WAAW,IAAI,KAAK,EAAG;AAE/B,YAAM,YAAY,KAAK,gBAAgB,IAAI,KAAK;AAEhD,UAAI;AACF,YAAI,IAAI,cAAc,QAAQ;AAC5B,cAAI,aAAa,SAAS;AAAA,QAC5B,OAAO;AACL,cAAI,kBAAkB,SAA0C;AAAA,QAClE;AAAA,MACF,SAAS,OAAO;AAEd,gBAAQ,KAAK,qCAAqC,IAAI,SAAS,cAAc,IAAI,KAAK,MAAM,KAAK;AAAA,MACnG;AAAA,IACF;AAEA,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,oBAAoB,QAAuC;AACzD,UAAM,SAAS,KAAK,cAAc,QAAQ,IAAI,CAAC;AAC/C,UAAM,kBAA8C,CAAC;AAErD,eAAW,SAAS,QAAQ;AAC1B,YAAM,MAAM,KAAK,eAAe,KAAK;AACrC,UAAI,KAAK;AACP,wBAAgB,KAAK,GAAG;AAAA,MAC1B;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,OAAgB,QAAgB,OAA4B;AAChF,UAAM,SAAsB,CAAC;AAE7B,QAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO;AAAA,IACT;AAGA,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,aAAO;AAAA,IACT;AAEA,eAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,KAAgC,GAAG;AACzE,YAAM,YAAY,SAAS,GAAG,MAAM,IAAI,GAAG,KAAK;AAChD,YAAM,YAAY,KAAK,QAAQ,GAAG;AAElC,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,MAAM;AAAA,QACN,UAAU,KAAK,SAAS,SAAS;AAAA,QACjC;AAAA,QACA,aAAa;AAAA,MACf,CAAC;AAGD,UAAI,KAAK,aAAa,SAAS,cAAc,YAAY,QAAQ,MAAM;AACrE,eAAO,KAAK,GAAG,KAAK,cAAc,KAAK,WAAW,QAAQ,CAAC,CAAC;AAAA,MAC9D;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,QAAQ,OAAmC;AACjD,QAAI,UAAU,KAAM,QAAO;AAC3B,QAAI,UAAU,OAAW,QAAO;AAChC,QAAI,MAAM,QAAQ,KAAK,EAAG,QAAO;AAEjC,UAAM,OAAO,OAAO;AACpB,QAAI,SAAS,SAAU,QAAO;AAC9B,QAAI,SAAS,SAAU,QAAO;AAC9B,QAAI,SAAS,UAAW,QAAO;AAC/B,QAAI,SAAS,SAAU,QAAO;AAE9B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,SAAS,MAAkC;AACjD,WAAO,SAAS,YAAY,SAAS,YAAY,SAAS;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,OAAmD;AAExE,QAAI,CAAC,MAAM,SAAU,QAAO;AAG5B,QAAI,KAAK,aAAa,YAAY,MAAM,QAAQ,GAAG;AACjD,aAAO;AAAA,IACT;AAGA,QAAI,MAAM,SAAS,YAAY,KAAK,qBAAqB,KAAK,GAAG;AAC/D,aAAO;AAAA,IACT;AAGA,UAAM,YAAY,KAAK,gBAAgB,KAAK;AAC5C,UAAM,SAAS,KAAK,eAAe,OAAO,SAAS;AAEnD,WAAO;AAAA,MACL,OAAO,MAAM;AAAA,MACb;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,OAA2B;AACtD,QAAI,MAAM,SAAS,SAAU,QAAO;AAGpC,UAAM,sBAAsB;AAAA,MAC1B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,YAAY,MAAM,KAAK,YAAY;AACzC,eAAW,WAAW,qBAAqB;AACzC,UAAI,UAAU,SAAS,OAAO,GAAG;AAC/B,eAAO;AAAA,MACT;AAAA,IACF;AAGA,QAAI,OAAO,MAAM,gBAAgB,YAAY,MAAM,YAAY,SAAS,KAAK;AAC3E,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,OAAwC;AAE9D,QAAI,MAAM,SAAS,UAAU;AAE3B,UAAI,MAAM,KAAK,YAAY,EAAE,SAAS,IAAI,GAAG;AAC3C,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAGA,QAAI,MAAM,SAAS,WAAW;AAC5B,aAAO;AAAA,IACT;AAGA,QAAI,MAAM,SAAS,UAAU;AAE3B,UAAI,MAAM,KAAK,YAAY,EAAE,SAAS,IAAI,KAAK,MAAM,KAAK,YAAY,MAAM,MAAM;AAChF,eAAO;AAAA,MACT;AAGA,UAAI,KAAK,cAAc,KAAK,GAAG;AAC7B,eAAO;AAAA,MACT;AAGA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,OAA2B;AAC/C,UAAM,YAAY,MAAM,KAAK,YAAY;AAGzC,UAAM,eAAe,CAAC,QAAQ,QAAQ,WAAW;AACjD,eAAW,WAAW,cAAc;AAClC,UAAI,UAAU,SAAS,OAAO,GAAG;AAC/B,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,eAAe,CAAC,OAAO,MAAM,WAAW,SAAS;AACvD,eAAW,UAAU,cAAc;AACjC,UAAI,MAAM,KAAK,SAAS,MAAM,GAAG;AAC/B,eAAO;AAAA,MACT;AAAA,IACF;AAGA,QAAI,OAAO,MAAM,gBAAgB,UAAU;AACzC,YAAM,iBAAiB;AACvB,UAAI,eAAe,KAAK,MAAM,WAAW,GAAG;AAC1C,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,OAAkB,WAAyC;AAChF,QAAI,cAAc,aAAa;AAC7B,UAAI,MAAM,SAAS,UAAU;AAC3B,eAAO,kBAAkB,MAAM,IAAI;AAAA,MACrC;AACA,UAAI,KAAK,cAAc,KAAK,GAAG;AAC7B,eAAO,oBAAoB,MAAM,IAAI;AAAA,MACvC;AAAA,IACF;AAEA,QAAI,MAAM,KAAK,YAAY,EAAE,SAAS,IAAI,KAAK,MAAM,KAAK,YAAY,MAAM,MAAM;AAChF,aAAO,aAAa,MAAM,IAAI;AAAA,IAChC;AAEA,QAAI,MAAM,SAAS,WAAW;AAC5B,aAAO,kBAAkB,MAAM,IAAI;AAAA,IACrC;AAEA,WAAO,iBAAiB,MAAM,IAAI,aAAa,MAAM,IAAI;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,WAA0C;AAChE,UAAM,QAAQ,UAAU,MAAM,GAAG;AAEjC,QAAI,MAAM,WAAW,GAAG;AAEtB,aAAO,gBAAgB,WAAW,CAAC,WAAc;AAC/C,eAAQ,OAAmC,SAAS;AAAA,MACtD,CAAC;AAAA,IACH;AAGA,WAAO,gBAAgB,WAAW,CAAC,WAAc;AAC/C,UAAI,UAAmB;AACvB,iBAAW,QAAQ,OAAO;AACxB,YAAI,YAAY,QAAQ,YAAY,OAAW,QAAO;AACtD,kBAAW,QAAoC,IAAI;AAAA,MACrD;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AACF;;;AC3TO,IAAM,uBAAN,MAA2B;AAAA,EAGhC,YAAY,QAAoB;AAC9B,SAAK,IAAI,QAAQ,KAAK;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,YAA8C;AAElD,UAAM,eAAe,WAAW,OAAO,CAAC,QAAQ,IAAI,SAAS,CAAC;AAE9D,QAAI,aAAa,WAAW,GAAG;AAC7B,aAAO,CAAC;AAAA,IACV;AAGA,UAAM,WAAW,oBAAI,IAOnB;AAGF,eAAW,aAAa,cAAc;AACpC,eAAS,OAAO,GAAG,OAAO,UAAU,QAAQ,QAAQ;AAClD,cAAM,SAAS,UAAU,IAAI;AAC7B,cAAM,EAAE,OAAO,OAAO,OAAO,IAAI;AAIjC,cAAM,kBAAkB,KAAK,KAAK,IAAI,OAAO;AAE7C,cAAM,WAAW,SAAS,IAAI,KAAK;AACnC,YAAI,UAAU;AACZ,mBAAS,YAAY;AACrB,mBAAS,QAAQ,IAAI,MAAM;AAC3B,mBAAS,eAAe,MAAM,IAAI;AAAA,QACpC,OAAO;AACL,mBAAS,IAAI,OAAO;AAAA,YAClB,UAAU;AAAA,YACV,SAAS,oBAAI,IAAI,CAAC,MAAM,CAAC;AAAA,YACzB,gBAAgB,EAAE,CAAC,MAAM,GAAG,MAAM;AAAA,UACpC,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAGA,UAAM,SAAyB,CAAC;AAChC,eAAW,CAAC,OAAO,IAAI,KAAK,UAAU;AACpC,aAAO,KAAK;AAAA,QACV;AAAA,QACA,OAAO,KAAK;AAAA,QACZ,QAAQ,MAAM,KAAK,KAAK,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;AAAA,QAChD,gBAAgB,KAAK;AAAA,MACvB,CAAC;AAAA,IACH;AAGA,WAAO,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAEvC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,cAAc,YAA8B,SAAmC;AAE7E,QAAI,QAAQ,WAAW,WAAW,QAAQ;AACxC,YAAM,IAAI;AAAA,QACR,yBAAyB,QAAQ,MAAM,mCAAmC,WAAW,MAAM;AAAA,MAC7F;AAAA,IACF;AAGA,UAAM,gBAAsE,CAAC;AAC7E,aAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC1C,UAAI,WAAW,CAAC,EAAE,SAAS,GAAG;AAC5B,sBAAc,KAAK,EAAE,WAAW,WAAW,CAAC,GAAG,QAAQ,QAAQ,CAAC,EAAE,CAAC;AAAA,MACrE;AAAA,IACF;AAEA,QAAI,cAAc,WAAW,GAAG;AAC9B,aAAO,CAAC;AAAA,IACV;AAGA,UAAM,WAAW,oBAAI,IAOnB;AAGF,eAAW,EAAE,WAAW,OAAO,KAAK,eAAe;AACjD,eAAS,OAAO,GAAG,OAAO,UAAU,QAAQ,QAAQ;AAClD,cAAM,SAAS,UAAU,IAAI;AAC7B,cAAM,EAAE,OAAO,OAAO,OAAO,IAAI;AAGjC,cAAM,kBAAkB,UAAU,KAAK,KAAK,IAAI,OAAO;AAEvD,cAAM,WAAW,SAAS,IAAI,KAAK;AACnC,YAAI,UAAU;AACZ,mBAAS,YAAY;AACrB,mBAAS,QAAQ,IAAI,MAAM;AAC3B,mBAAS,eAAe,MAAM,IAAI;AAAA,QACpC,OAAO;AACL,mBAAS,IAAI,OAAO;AAAA,YAClB,UAAU;AAAA,YACV,SAAS,oBAAI,IAAI,CAAC,MAAM,CAAC;AAAA,YACzB,gBAAgB,EAAE,CAAC,MAAM,GAAG,MAAM;AAAA,UACpC,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAGA,UAAM,SAAyB,CAAC;AAChC,eAAW,CAAC,OAAO,IAAI,KAAK,UAAU;AACpC,aAAO,KAAK;AAAA,QACV;AAAA,QACA,OAAO,KAAK;AAAA,QACZ,QAAQ,MAAM,KAAK,KAAK,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;AAAA,QAChD,gBAAgB,KAAK;AAAA,MACvB,CAAC;AAAA,IACH;AAGA,WAAO,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAEvC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,OAAe;AACb,WAAO,KAAK;AAAA,EACd;AACF;;;ACxOO,SAAS,gBAAgB,KAAqB;AAEnD,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,OAAO,KAAK,KAAK,MAAM,EAAE,SAAS,WAAW;AAAA,EACtD;AAGA,QAAM,SAAS,KAAK,SAAS,mBAAmB,GAAG,CAAC,CAAC;AACrD,SAAO,OAAO,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,EAAE;AACzE;AASO,SAAS,gBAAgB,SAAyB;AAEvD,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,OAAO,KAAK,SAAS,WAAW,EAAE,SAAS,MAAM;AAAA,EAC1D;AAGA,MAAI,SAAS,QAAQ,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG;AAGzD,QAAM,MAAM,OAAO,SAAS;AAC5B,MAAI,KAAK;AACP,cAAU,IAAI,OAAO,IAAI,GAAG;AAAA,EAC9B;AAEA,SAAO,mBAAmB,OAAO,KAAK,MAAM,CAAC,CAAC;AAChD;;;ACjBO,SAAS,cAAc,GAAY,GAAoB;AAE5D,MAAI,KAAK,QAAQ,KAAK,KAAM,QAAO;AACnC,MAAI,KAAK,KAAM,QAAO;AACtB,MAAI,KAAK,KAAM,QAAO;AAGtB,MAAI,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU;AAClD,WAAO,IAAI;AAAA,EACb;AAGA,MAAI,aAAa,QAAQ,aAAa,MAAM;AAC1C,WAAO,EAAE,QAAQ,IAAI,EAAE,QAAQ;AAAA,EACjC;AAGA,MAAI,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU;AAClD,UAAM,QAAQ,KAAK,MAAM,CAAC;AAC1B,UAAM,QAAQ,KAAK,MAAM,CAAC;AAE1B,QAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,KAAK,GAAG;AAClC,aAAO,QAAQ;AAAA,IACjB;AAEA,WAAO,EAAE,cAAc,CAAC;AAAA,EAC1B;AAGA,MAAI,OAAO,MAAM,aAAa,OAAO,MAAM,WAAW;AACpD,WAAO,MAAM,IAAI,IAAI,IAAI,IAAI;AAAA,EAC/B;AAGA,SAAO,OAAO,CAAC,EAAE,cAAc,OAAO,CAAC,CAAC;AAC1C;;;ACsBO,IAAM,kCAAkC,KAAK,KAAK;AAwBlD,IAAM,cAAN,MAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOvB,OAAO,OAAO,MAA+B;AAC3C,UAAM,OAAO,KAAK,UAAU,IAAI;AAChC,WAAO,gBAAgB,IAAI;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,OAAO,QAAwC;AACpD,QAAI;AACF,YAAM,OAAO,gBAAgB,MAAM;AACnC,YAAM,OAAO,KAAK,MAAM,IAAI;AAG5B,UACE,OAAO,SAAS,YAChB,OAAO,KAAK,eAAe,YAC3B,OAAO,KAAK,aAAa,YACzB,OAAO,KAAK,cAAc,YACzB,KAAK,kBAAkB,SAAS,KAAK,kBAAkB,UACxD,OAAO,KAAK,kBAAkB,YAC9B,OAAO,KAAK,aAAa,YACzB,OAAO,KAAK,cAAc,UAC1B;AACA,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,OAAO,YACL,SACA,MACA,WACQ;AACR,UAAM,aAAsC,CAAC;AAC7C,UAAM,WAAmC,CAAC;AAG1C,UAAM,cAAc,OAAO,QAAQ,IAAI;AACvC,QAAI,YAAY,WAAW,GAAG;AAC5B,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AACA,UAAM,CAAC,WAAW,aAAa,IAAI,YAAY,CAAC;AAIhD,eAAW,UAAU,SAAS;AAC5B,YAAM,SAAS,OAAO,UAAU;AAEhC,iBAAW,MAAM,IAAI,OAAO;AAC5B,eAAS,MAAM,IAAI,OAAO;AAAA,IAC5B;AAEA,UAAM,OAAwB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,eAAe,WAAW,aAAa,IAAI;AAAA,MAC3C,UAAU,WAAW,IAAI;AAAA,MACzB,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,WAAO,KAAK,OAAO,IAAI;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,eACL,YACA,MACA,WACQ;AACR,WAAO,KAAK,YAAY,CAAC,UAAU,GAAG,MAAM,SAAS;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,OAAO,QACL,QACA,WACA,MACA,SACS;AACT,UAAM,SAAS,SAAS,YAAY;AAGpC,QAAI,OAAO,kBAAkB,WAAW,aAAa,IAAI,GAAG;AAC1D,aAAO;AAAA,IACT;AAGA,QAAI,OAAO,aAAa,WAAW,IAAI,GAAG;AACxC,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,IAAI,IAAI,OAAO,YAAY,QAAQ;AAC1C,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,gBACL,QACA,SAAiB,SACiC;AAClD,QAAI,EAAE,UAAU,OAAO,aAAa;AAClC,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,YAAY,OAAO,WAAW,MAAM;AAAA,MACpC,UAAU,OAAO,SAAS,MAAM;AAAA,IAClC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,OAAO,cACL,QACA,QACS;AACT,UAAM,SAAS,OAAO,UAAU;AAChC,UAAM,WAAW,KAAK,gBAAgB,QAAQ,MAAM;AAGpD,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,KAAK,cAAc,OAAO,WAAW,SAAS,UAAU;AAEpE,QAAI,OAAO,kBAAkB,OAAO;AAElC,UAAI,MAAM,EAAG,QAAO;AACpB,UAAI,QAAQ,KAAK,OAAO,MAAM,SAAS,SAAU,QAAO;AAAA,IAC1D,OAAO;AAEL,UAAI,MAAM,EAAG,QAAO;AACpB,UAAI,QAAQ,KAAK,OAAO,MAAM,SAAS,SAAU,QAAO;AAAA,IAC1D;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,OAAO,cAAc,GAAY,GAAoB;AACnD,WAAO,cAAc,GAAG,CAAC;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,OAAO,MACL,SACA,MACA,WACiB;AACjB,UAAM,aAAsC,CAAC;AAC7C,UAAM,WAAmC,CAAC;AAG1C,UAAM,cAAc,OAAO,QAAQ,IAAI;AACvC,UAAM,CAAC,WAAW,aAAa,IAAI,YAAY,CAAC;AAEhD,eAAW,UAAU,SAAS;AAC5B,iBAAW,UAAU,OAAO,KAAK,OAAO,UAAU,GAAG;AACnD,cAAM,gBAAgB,WAAW,MAAM;AACvC,cAAM,WAAW,OAAO,WAAW,MAAM;AAEzC,YAAI,kBAAkB,QAAW;AAE/B,qBAAW,MAAM,IAAI;AACrB,mBAAS,MAAM,IAAI,OAAO,SAAS,MAAM;AAAA,QAC3C,OAAO;AAEL,gBAAM,MAAM,KAAK,cAAc,UAAU,aAAa;AACtD,gBAAM,YACJ,kBAAkB,QACd,MAAM,KAAM,QAAQ,KAAK,OAAO,SAAS,MAAM,IAAI,SAAS,MAAM,IAClE,MAAM,KAAM,QAAQ,KAAK,OAAO,SAAS,MAAM,IAAI,SAAS,MAAM;AAExE,cAAI,WAAW;AACb,uBAAW,MAAM,IAAI;AACrB,qBAAS,MAAM,IAAI,OAAO,SAAS,MAAM;AAAA,UAC3C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,eAAe,WAAW,aAAa,IAAI;AAAA,MAC3C,UAAU,WAAW,IAAI;AAAA,MACzB,WAAW,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,iBAAiB,QAAiC,WAA4B;AACnF,WAAO,OAAO,SAAS;AAAA,EACzB;AACF;;;ACzUO,IAAM,gBAAN,cAAiD,OAAa;AAAA,EAanE,YAAY,KAAU,UAA6B,CAAC,GAAG;AACrD,UAAM,GAAG;AACT,SAAK,UAAU;AAEf,SAAK,gBAAgB,IAAI,cAAc;AACvC,SAAK,wBAAwB,IAAI,sBAAsB;AAAA,MACrD,WAAW,CAAC,QAAQ,KAAK,IAAI,GAAG;AAAA,MAChC,eAAe,MAAM,KAAK,QAAQ;AAAA,IACpC,CAAC;AACD,SAAK,mBAAmB,IAAI,iBAAiB;AAAA,MAC3C,WAAW,CAAC,QAAQ,KAAK,IAAI,GAAG;AAAA,MAChC,eAAe,MAAM,KAAK,QAAQ;AAAA,IACpC,CAAC;AACD,SAAK,iBAAiB,IAAI,eAAe;AAAA,MACvC,eAAe,KAAK;AAAA,MACpB,uBAAuB,KAAK;AAAA,IAC9B,CAAC;AAGD,SAAK,cAAc;AAAA,MACjB,IAAI;AAAA,QACF,MAAM,KAAK,KAAK;AAAA,QAChB,CAAC,QAAQ,KAAK,IAAI,GAAG;AAAA,QACrB,CAAC,QAAQ,UAAU,KAAK,kBAAkB,QAAQ,KAAK;AAAA,MACzD;AAAA,IACF;AAGA,SAAK,eAAe,IAAI,oBAAoB;AAC5C,SAAK,eAAe,IAAI,aAAa,KAAK,YAAY;AAGtD,QAAI,QAAQ,kBAAkB,WAAW,SAAS;AAChD,WAAK,mBAAmB,IAAI;AAAA,QAC1B,KAAK;AAAA,QACL,KAAK;AAAA,QACL,QAAQ,iBAAiB;AAAA,MAC3B;AACA,WAAK,iBAAiB,OAAO,IAAI;AAAA,IACnC,OAAO;AACL,WAAK,mBAAmB;AAAA,IAC1B;AAGA,QAAI,QAAQ,mBAAmB,QAAQ,oBAAoB,QAAQ;AACjE,WAAK,0BAA0B,IAAI,wBAA2B,QAAQ,eAAe;AAAA,IACvF,OAAO;AACL,WAAK,0BAA0B;AAAA,IACjC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,aAAgB,WAAyE;AACvF,QAAI,KAAK,QAAQ,mBAAmB;AAClC,YAAMC,SAAQ,IAAI,cAAuB,WAAW;AAAA,QAClD,YAAY,KAAK,QAAQ;AAAA,MAC3B,CAAC;AACD,WAAK,cAAc,SAASA,MAAK;AACjC,WAAK,WAAWA,MAAK;AACrB,aAAOA;AAAA,IACT;AAEA,UAAM,QAAQ,IAAI,UAAmB,SAAS;AAC9C,SAAK,cAAc,SAAS,KAAK;AACjC,SAAK,WAAW,KAAK;AACrB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,kBACE,WACA,YACuD;AACvD,QAAI,KAAK,QAAQ,mBAAmB;AAClC,YAAMA,SAAQ,IAAI,mBAA4B,WAAW,YAAY;AAAA,QACnE,YAAY,KAAK,QAAQ;AAAA,MAC3B,CAAC;AACD,WAAK,cAAc,SAASA,MAAK;AACjC,WAAK,WAAWA,MAAK;AACrB,aAAOA;AAAA,IACT;AAEA,UAAM,QAAQ,IAAI,eAAwB,WAAW,UAAU;AAC/D,SAAK,cAAc,SAAS,KAAK;AACjC,SAAK,WAAW,KAAK;AACrB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBA,iBACE,WACA,UACqD;AACrD,QAAI,KAAK,QAAQ,mBAAmB;AAClC,YAAMA,SAAQ,IAAI,kBAA2B,WAAW,UAAU;AAAA,QAChE,YAAY,KAAK,QAAQ;AAAA,MAC3B,CAAC;AACD,WAAK,cAAc,SAASA,MAAK;AACjC,WAAK,WAAWA,MAAK;AACrB,aAAOA;AAAA,IACT;AAEA,UAAM,QAAQ,IAAI,cAAuB,WAAW,QAAQ;AAC5D,SAAK,cAAc,SAAS,KAAK;AACjC,SAAK,WAAW,KAAK;AACrB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAY,OAA6B;AACvC,SAAK,cAAc,SAAS,KAAK;AACjC,SAAK,WAAW,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAe,OAAgC;AAC7C,WAAO,KAAK,cAAc,YAAY,KAAK;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAqC;AACnC,WAAO,KAAK,cAAc,cAAc;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,eAAgC;AACzC,WAAO,KAAK,cAAc,SAAS,aAAa;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKQ,WAAc,OAA6B;AACjD,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,QAAQ,GAAG;AACzC,YAAM,IAAI,KAAK,KAAK;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,OAA4B;AAChC,UAAM,QAAQ,YAAY,IAAI;AAC9B,UAAM,OAAO,KAAK,eAAe,SAAS,KAAK;AAC/C,UAAM,YAAY,KAAK,YAAY,KAAK,IAAI;AAG5C,UAAM,UAAU,UAAU,QAAQ;AAClC,UAAM,WAAW,YAAY,IAAI,IAAI;AAGrC,SAAK,kBAAkB,OAAO,UAAU,QAAQ,QAAQ,KAAK,WAAW;AAGxE,WAAO,IAAI,aAAa,IAAI,IAAI,OAAO,GAAG,UAAU,iBAAiB,CAAC;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,aAAa,OAAwB;AACnC,UAAM,OAAO,KAAK,MAAM,KAAK;AAC7B,UAAM,UAAoB,CAAC;AAE3B,eAAW,OAAO,MAAM;AACtB,YAAM,QAAQ,KAAK,IAAI,GAAG;AAC1B,UAAI,UAAU,QAAW;AACvB,gBAAQ,KAAK,CAAC,KAAK,KAAK,CAAC;AAAA,MAC3B;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,OAAmB;AAC7B,UAAM,OAAO,KAAK,MAAM,KAAK;AAC7B,UAAM,UAAe,CAAC;AAEtB,eAAW,OAAO,MAAM;AACtB,YAAM,QAAQ,KAAK,IAAI,GAAG;AAC1B,UAAI,UAAU,QAAW;AACvB,gBAAQ,KAAK,KAAK;AAAA,MACpB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAsB;AAC1B,UAAM,YAAY,KAAK,MAAM,KAAK;AAClC,WAAO,UAAU,KAAK;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAY,MAA8B;AAChD,YAAQ,KAAK,MAAM;AAAA,MACjB,KAAK;AACH,eAAO,KAAK,MAAM,SAAS,KAAK,KAAK;AAAA,MAEvC,KAAK,aAAa;AAChB,cAAM,WAAW,KAAK,cAAc,iBAAiB;AACrD,YAAI,UAAU;AAEZ,iBAAO,SAAS,SAAS,KAAK,SAA2C;AAAA,QAC3E;AAEA,eAAO,KAAK,SAAS,KAAK,SAAkB;AAAA,MAC9C;AAAA,MAEA,KAAK;AACH,eAAO,IAAI;AAAA,UACT,KAAK,MAAM,IAAI,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC;AAAA,QAC3C;AAAA,MAEF,KAAK;AACH,eAAO,IAAI,eAAe,KAAK,MAAM,IAAI,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC,CAAC;AAAA,MAEtE,KAAK;AACH,eAAO,IAAI;AAAA,UACT,KAAK,YAAY,KAAK,MAAM;AAAA,UAC5B,CAAC,QAAQ,KAAK,IAAI,GAAG;AAAA,UACrB,CAAC,WAAW;AACV,gBAAI,WAAW,OAAW,QAAO;AACjC,mBAAO,KAAK,iBAAiB,QAAQ,KAAK,SAAkB;AAAA,UAC9D;AAAA,QACF;AAAA,MAEF,KAAK,OAAO;AACV,cAAM,WAAW,IAAI,IAAI,KAAK,YAAY,KAAK,MAAM,EAAE,QAAQ,CAAC;AAChE,cAAM,aAAa,IAAI,IAAI,KAAK,KAAK,CAAC;AACtC,mBAAW,OAAO,UAAU;AAC1B,qBAAW,OAAO,GAAG;AAAA,QACvB;AACA,eAAO,IAAI,aAAa,YAAY,GAAG;AAAA,MACzC;AAAA,MAEA;AACE,cAAM,IAAI,MAAM,2BAA4B,KAAkB,IAAI,EAAE;AAAA,IACxE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,SAAS,OAA4B;AAC3C,UAAM,SAAS,oBAAI,IAAO;AAC1B,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,QAAQ,GAAG;AACzC,UAAI,KAAK,iBAAiB,OAAO,KAAK,GAAG;AACvC,eAAO,IAAI,GAAG;AAAA,MAChB;AAAA,IACF;AACA,WAAO,IAAI,aAAa,QAAQ,OAAO,gBAAgB;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAAiB,QAAW,OAAuB;AACzD,QAAI;AACF,YAAM,YAAY,KAAK,iBAAiB,KAAK;AAC7C,aAAO,kBAAkB,WAAW,MAAM;AAAA,IAC5C,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAkB,QAAW,OAAqC;AAGxE,QAAI,eAAgB,OAA8C;AAEhE,aAAO,KAAK,iBAAiB,QAAQ,KAAyB;AAAA,IAChE;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,OAA6B;AACpD,QAAI,UAAU,OAAO;AACnB,cAAQ,MAAM,MAAM;AAAA,QAClB,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,WAAY,MAAgC;AAAA,YAC5C,OAAQ,MAA6B;AAAA,UACvC;AAAA,QACF,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,WAAY,MAAgC;AAAA,YAC5C,OAAQ,MAA6B;AAAA,UACvC;AAAA,QACF,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,WAAY,MAAgC;AAAA,YAC5C,OAAQ,MAA6B;AAAA,UACvC;AAAA,QACF,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,WAAY,MAAgC;AAAA,YAC5C,OAAQ,MAA6B;AAAA,UACvC;AAAA,QACF,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,WAAY,MAAgC;AAAA,YAC5C,OAAQ,MAA6B;AAAA,UACvC;AAAA,QACF,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,WAAY,MAAgC;AAAA,YAC5C,OAAQ,MAA6B;AAAA,UACvC;AAAA,QACF,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,WAAY,MAAgC,YAAY,CAAC,GAAG;AAAA,cAC1D,CAAC,MAAM,KAAK,iBAAiB,CAAC;AAAA,YAChC;AAAA,UACF;AAAA,QACF,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,WAAY,MAAgC,YAAY,CAAC,GAAG;AAAA,cAC1D,CAAC,MAAM,KAAK,iBAAiB,CAAC;AAAA,YAChC;AAAA,UACF;AAAA,QACF,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,UAAU;AAAA,cACR,KAAK,iBAAkB,MAA2B,KAAK;AAAA,YACzD;AAAA,UACF;AAAA,QACF,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,WAAY,MAAgC;AAAA,YAC5C,OAAQ,MAA6B;AAAA,UACvC;AAAA,QACF,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,WAAY,MAAgC;AAAA,YAC5C,OAAQ,MAAgC;AAAA,UAC1C;AAAA,QACF,KAAK;AACH,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,WAAY,MAAgC;AAAA,YAC5C,OAAQ,MAAgC;AAAA,UAC1C;AAAA,QACF;AACE,iBAAO,EAAE,IAAI,MAAM,OAAO,KAAK;AAAA,MACnC;AAAA,IACF;AACA,WAAO,EAAE,IAAI,MAAM,OAAO,KAAK;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,mBACE,OACA,UACY;AACZ,WAAO,KAAK,iBAAiB,UAAU,OAAO,QAAQ;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,oBAAoB,OAAmB;AACrC,WAAO,KAAK,iBAAiB,WAAW,KAAK;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,wBAAwB,OAAuB;AAC7C,WAAO,KAAK,iBAAiB,eAAe,KAAK;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,IAAI,KAAQ,OAAU,OAA8B;AACzD,UAAM,WAAW,KAAK,IAAI,GAAG;AAC7B,UAAM,SAAS,MAAM,IAAI,KAAK,OAAO,KAAK;AAG1C,QAAI,KAAK,2BAA2B,CAAC,KAAK,wBAAwB,UAAU,GAAG;AAC7E,WAAK,wBAAwB,WAAW,MAAM,KAAK;AAAA,IACrD;AAEA,QAAI,aAAa,QAAW;AAC1B,WAAK,cAAc,gBAAgB,KAAK,UAAU,KAAK;AACvD,WAAK,iBAAiB,gBAAgB,KAAK,UAAU,KAAK;AAAA,IAC5D,OAAO;AACL,WAAK,cAAc,cAAc,KAAK,KAAK;AAC3C,WAAK,iBAAiB,cAAc,KAAK,KAAK;AAAA,IAChD;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKO,OAAO,KAAsB;AAClC,UAAM,WAAW,KAAK,IAAI,GAAG;AAC7B,UAAM,SAAS,MAAM,OAAO,GAAG;AAE/B,QAAI,aAAa,QAAW;AAC1B,WAAK,cAAc,gBAAgB,KAAK,QAAQ;AAChD,WAAK,iBAAiB,gBAAgB,KAAK,QAAQ;AAAA,IACrD;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKO,MAAM,KAAQ,QAA+B;AAClD,UAAM,WAAW,KAAK,IAAI,GAAG;AAC7B,UAAM,SAAS,MAAM,MAAM,KAAK,MAAM;AAEtC,QAAI,QAAQ;AACV,YAAM,WAAW,KAAK,IAAI,GAAG;AAE7B,UAAI,aAAa,UAAa,aAAa,QAAW;AAEpD,aAAK,cAAc,cAAc,KAAK,QAAQ;AAC9C,aAAK,iBAAiB,cAAc,KAAK,QAAQ;AAAA,MACnD,WAAW,aAAa,UAAa,aAAa,QAAW;AAE3D,aAAK,cAAc,gBAAgB,KAAK,QAAQ;AAChD,aAAK,iBAAiB,gBAAgB,KAAK,QAAQ;AAAA,MACrD,WAAW,aAAa,UAAa,aAAa,QAAW;AAE3D,aAAK,cAAc,gBAAgB,KAAK,UAAU,QAAQ;AAC1D,aAAK,iBAAiB,gBAAgB,KAAK,UAAU,QAAQ;AAAA,MAC/D;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKO,QAAc;AACnB,UAAM,MAAM;AACZ,SAAK,cAAc,MAAM;AACzB,SAAK,iBAAiB,MAAM;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,OAAoB;AACzB,UAAM,OAAO;AACb,WAAO;AAAA,MACL,EAAE,OAAO,QAAQ,IAAI;AACnB,mBAAW,CAAC,GAAG,KAAK,KAAK,QAAQ,GAAG;AAClC,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBAAyC;AACvC,UAAM,QAAQ,oBAAI,IAAwB;AAC1C,eAAW,SAAS,KAAK,cAAc,cAAc,GAAG;AACtD,YAAM,IAAI,MAAM,UAAU,MAAM,MAAM,SAAS,CAAC;AAAA,IAClD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,wBAA4C;AAC1C,WAAO,KAAK,cAAc,SAAS;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA0C;AACxC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,sBAA8C;AAC5C,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,2BAAwD;AACtD,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,OAAyB;AACpC,WAAO,KAAK,eAAe,SAAS,KAAK;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,kBACE,WACA,mBACM;AACN,QAAI,KAAK,kBAAkB;AACzB,WAAK,iBAAiB,kBAAkB,WAAW,iBAAiB;AAAA,IACtE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,oBAAoB,eAA6B;AAC/C,QAAI,KAAK,kBAAkB;AACzB,WAAK,iBAAiB,oBAAoB,aAAa;AAAA,IACzD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,oBAAoB,SAAqD;AACvE,WAAO,KAAK,aAAa,eAAe,OAAO;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,qBAAwC;AACtC,WAAO,KAAK,aAAa,cAAc;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,uBAA6B;AAC3B,SAAK,aAAa,MAAM;AACxB,QAAI,KAAK,kBAAkB;AACzB,WAAK,iBAAiB,YAAY;AAAA,IACpC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAuC;AACrC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAgC;AAC9B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAqD;AACnD,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,wBAAiC;AAC/B,WAAO,KAAK,qBAAqB;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,wBAAiC;AAC/B,WAAO,KAAK,QAAQ,sBAAsB;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,sBAAsB,kBAAqD;AACzE,UAAM,WAAW,oBAAoB,KAAK,QAAQ;AAElD,eAAW,SAAS,KAAK,cAAc,cAAc,GAAG;AACtD,UAAI,YAAY,SAAU,MAAmC,QAAQ;AACnE,cAAM,YAAY;AAClB,YAAI,CAAC,UAAU,SAAS;AACtB,oBAAU,YAAY,QAAQ;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,uBAA+B;AAC7B,QAAI,QAAQ;AACZ,eAAW,SAAS,KAAK,cAAc,cAAc,GAAG;AACtD,UAAI,YAAY,SAAU,MAAmC,QAAQ;AACnE,cAAM,YAAY;AAClB,iBAAS,UAAU;AAAA,MACrB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA6B;AAC3B,eAAW,SAAS,KAAK,cAAc,cAAc,GAAG;AACtD,UAAI,YAAY,SAAU,MAAmC,QAAQ;AACnE,cAAM,YAAY;AAClB,YAAI,CAAC,UAAU,SAAS;AACtB,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,kBACN,OACA,UACA,YACA,WACM;AAEN,UAAM,iBAAiB,KAAK,QAAQ,kBAAkB,SAAS,WAC7D,2BAA2B,QAAQ;AAErC,QAAI,CAAC,kBAAkB,CAAC,KAAK,kBAAkB;AAC7C;AAAA,IACF;AAGA,UAAM,YAAY,KAAK,iBAAiB,KAAK;AAC7C,QAAI,CAAC,UAAW;AAGhB,UAAM,YAAY,KAAK,iBAAiB,KAAK;AAC7C,QAAI,CAAC,UAAW;AAGhB,UAAM,WAAW,KAAK,cAAc,SAAS,SAAS;AAGtD,SAAK,aAAa;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAGA,QAAI,KAAK,kBAAkB;AACzB,WAAK,iBAAiB,gBAAgB,WAAW,SAAS;AAAA,IAC5D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,OAA6B;AACpD,QAAI,cAAc,KAAK,GAAG;AACxB,aAAQ,MAA0B;AAAA,IACpC;AAGA,QAAI,MAAM,SAAS,SAAS,MAAM,SAAS,MAAM;AAC/C,YAAM,WAAY,MAAiC;AACnD,UAAI,YAAY,SAAS,SAAS,GAAG;AACnC,eAAO,KAAK,iBAAiB,SAAS,CAAC,CAAC;AAAA,MAC1C;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,OAAO;AACxB,YAAM,QAAS,MAA4B;AAC3C,UAAI,OAAO;AACT,eAAO,KAAK,iBAAiB,KAAK;AAAA,MACpC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,OAAuC;AAC9D,QAAI,cAAc,KAAK,GAAG;AACxB,YAAM,OAAO,MAAM;AAEnB,YAAM,iBAAqC;AAAA,QACzC;AAAA,QAAM;AAAA,QAAO;AAAA,QAAM;AAAA,QAAO;AAAA,QAAM;AAAA,QAAO;AAAA,QAAW;AAAA,QAAM;AAAA,QACxD;AAAA,QAAY;AAAA,QAAe;AAAA,MAC7B;AACA,UAAI,eAAe,SAAS,IAAwB,GAAG;AACrD,eAAO;AAAA,MACT;AAAA,IACF;AAGA,QAAI,MAAM,SAAS,SAAS,MAAM,SAAS,MAAM;AAC/C,YAAM,WAAY,MAAiC;AACnD,UAAI,YAAY,SAAS,SAAS,GAAG;AACnC,eAAO,KAAK,iBAAiB,SAAS,CAAC,CAAC;AAAA,MAC1C;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,OAAO;AACxB,YAAM,QAAS,MAA4B;AAC3C,UAAI,OAAO;AACT,eAAO,KAAK,iBAAiB,KAAK;AAAA,MACpC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;ACn8BO,IAAM,oBAAoB,oBAAI,IAAI;AAAA;AAAA,EAEvC;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EAC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","names":["h","h","import_zod","import_zod","WriteConcern","PartitionState","ConsistencyLevel","BTree","index"]}
|