@earth-app/collegedb 1.1.3 → 1.1.4

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/dist/index.js.map CHANGED
@@ -5,12 +5,12 @@
5
5
  "/**\n * @fileoverview Custom error class for CollegeDB operations\n *\n * This module provides the CollegeDBError class that extends the native Error class\n * to provide more specific error information for CollegeDB operations. This allows\n * for better error handling and debugging throughout the application.\n *\n * @example\n * ```typescript\n * import { CollegeDBError } from './errors';\n *\n * throw new CollegeDBError('Failed to allocate shard', 'SHARD_ALLOCATION_ERROR');\n * ```\n *\n * @author CollegeDB Team\n * @since 1.0.2\n */\n\n/**\n * Custom error class for CollegeDB operations\n *\n * Extends the native Error class to provide more specific error information\n * for CollegeDB operations. Includes an optional error code for better\n * error categorization and handling.\n *\n * @example\n * ```typescript\n * try {\n * await getShardForKey('invalid-key');\n * } catch (error) {\n * if (error instanceof CollegeDBError) {\n * console.error(`CollegeDB Error (${error.code}): ${error.message}`);\n * }\n * }\n * ```\n */\nexport class CollegeDBError extends Error {\n\t/**\n\t * Optional error code for categorizing different types of errors\n\t */\n\tpublic readonly code?: string;\n\n\t/**\n\t * Creates a new CollegeDBError instance\n\t * @param message - Error message describing what went wrong\n\t * @param code - Optional error code for categorization\n\t * @example\n\t * ```typescript\n\t * throw new CollegeDBError('Shard not found', 'SHARD_NOT_FOUND');\n\t * ```\n\t */\n\tconstructor(message: string, code?: string) {\n\t\tsuper(message);\n\t\tthis.name = 'CollegeDBError';\n\t\tthis.code = code;\n\n\t\t// Maintains proper stack trace for where our error was thrown (only available on V8)\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, CollegeDBError);\n\t\t}\n\t}\n}\n",
6
6
  "/**\n * @fileoverview KV-based shard mapping implementation for CollegeDB\n *\n * This module provides the KVShardMapper class that uses Cloudflare KV storage\n * to maintain mappings between primary keys and their assigned D1 database shards.\n * It handles the persistence and retrieval of shard assignments, enabling the\n * database router to consistently route queries to the correct shard.\n *\n * Key features:\n * - Primary key to shard mapping storage and retrieval\n * - Multiple lookup keys for the same shard mapping (e.g., username, email, id)\n * - SHA-256 hashing of keys for security and privacy (enabled by default)\n * - Shard discovery and management\n * - Key counting and statistics for load balancing\n * - Batch operations for efficient KV usage\n *\n * @example\n * ```typescript\n * const mapper = new KVShardMapper(env.KV, { hashShardMappings: true });\n *\n * // Set a mapping with multiple lookup keys\n * await mapper.setShardMapping('user-123', 'db-east', ['username:john', 'email:john@example.com', 'id:123']);\n *\n * // Get a mapping by any of the keys\n * const mapping = await mapper.getShardMapping('email:john@example.com');\n * console.log(mapping?.shard); // 'db-east'\n *\n * // Get statistics\n * const counts = await mapper.getShardKeyCounts();\n * console.log(counts); // { 'db-east': 42, 'db-west': 38 }\n * ```\n *\n * @author Gregory Mitchell\n * @since 1.0.0\n */\n\nimport { CollegeDBError } from './errors';\nimport type { CollegeDBConfig, KVStorage, MultiKeyShardMapping, ShardMapping } from './types';\n\n/**\n * KV key prefix for shard mappings\n *\n * All primary key to shard mappings are stored with this prefix to namespace\n * them from other data in the KV store and enable efficient prefix-based queries.\n *\n * @constant\n * @private\n */\nconst SHARD_MAPPING_PREFIX = 'shard:';\n\n/**\n * KV key prefix for multi-key shard mappings\n *\n * Multi-key mappings store the primary mapping data and list of all associated keys.\n *\n * @constant\n * @private\n * @since 1.0.3\n */\nconst MULTI_KEY_MAPPING_PREFIX = 'multikey:';\n\n/**\n * KV key for storing the list of known shards\n *\n * A single key that stores the JSON array of all known shard binding names.\n * This provides a quick way to discover available shards without scanning\n * all mapping entries.\n *\n * @constant\n * @private\n */\nconst KNOWN_SHARDS_KEY = 'known_shards';\n\n/**\n * Default TTL for in-memory mapping cache entries.\n * @private\n */\nconst DEFAULT_MAPPING_CACHE_TTL_MS = 30_000;\n\n/**\n * Default TTL for in-memory known shards cache entries.\n * @private\n */\nconst DEFAULT_KNOWN_SHARDS_CACHE_TTL_MS = 10_000;\n\n/**\n * The KVShardMapper class provides a persistent storage layer for mapping\n * primary keys to their assigned D1 database shards. It uses Cloudflare KV\n * for global, eventually consistent storage with low latency reads.\n *\n * Features:\n * - CRUD operations for shard mappings\n * - Multiple lookup keys for the same shard (username, email, id, etc.)\n * - SHA-256 hashing of keys for security and privacy\n * - Atomic updates with timestamp tracking\n * - Efficient bulk operations and statistics\n * - Prefix-based key organization for performance\n *\n * @example\n * ```typescript\n * const mapper = new KVShardMapper(env.KV, { hashShardMappings: true });\n *\n * // Create a new mapping with multiple lookup keys\n * await mapper.setShardMapping('primary-key-123', 'db-central', ['username:john', 'email:john@example.com']);\n *\n * // Update an existing mapping\n * await mapper.updateShardMapping('username:john', 'db-west');\n *\n * // Query mapping by any key\n * const mapping = await mapper.getShardMapping('email:john@example.com');\n * if (mapping) {\n * console.log(`User is on ${mapping.shard}`);\n * }\n * ```\n */\nexport class KVShardMapper {\n\t/**\n\t * KV provider for storing mappings\n\t * @readonly\n\t */\n\tprivate readonly kv: KVStorage;\n\n\t/**\n\t * Whether to hash mapping keys with SHA-256\n\t * @readonly\n\t */\n\tprivate readonly hashKeys: boolean;\n\n\t/**\n\t * Cache for hashed keys to avoid repeated crypto operations\n\t * @private\n\t */\n\tprivate readonly hashCache = new Map<string, string>();\n\n\t/**\n\t * In-memory mapping cache to reduce repeated KV reads.\n\t * @private\n\t */\n\tprivate readonly mappingCache = new Map<string, { mapping: ShardMapping | null; expiresAt: number }>();\n\n\t/**\n\t * In-memory known shards cache.\n\t * @private\n\t */\n\tprivate readonly knownShardsCache = {\n\t\tshards: null as string[] | null,\n\t\texpiresAt: 0\n\t};\n\n\t/**\n\t * Mapping cache TTL in milliseconds.\n\t * @private\n\t */\n\tprivate readonly mappingCacheTtlMs: number;\n\n\t/**\n\t * Known shards cache TTL in milliseconds.\n\t * @private\n\t */\n\tprivate readonly knownShardsCacheTtlMs: number;\n\n\t/**\n\t * Creates a new KVShardMapper instance\n\t * @param kv - KV storage provider\n\t * @param config - Configuration options including hashing preference\n\t */\n\tconstructor(\n\t\tkv: KVStorage,\n\t\tconfig: Partial<Pick<CollegeDBConfig, 'hashShardMappings' | 'mappingCacheTtlMs' | 'knownShardsCacheTtlMs'>> = {}\n\t) {\n\t\tthis.kv = kv;\n\t\tthis.hashKeys = config.hashShardMappings ?? true; // Default to true for security\n\t\tthis.mappingCacheTtlMs = config.mappingCacheTtlMs ?? DEFAULT_MAPPING_CACHE_TTL_MS;\n\t\tthis.knownShardsCacheTtlMs = config.knownShardsCacheTtlMs ?? DEFAULT_KNOWN_SHARDS_CACHE_TTL_MS;\n\t}\n\n\t/**\n\t * Reads a mapping from the in-memory cache.\n\t * @private\n\t */\n\tprivate getCachedMapping(hashedKey: string): ShardMapping | null | undefined {\n\t\tconst cached = this.mappingCache.get(hashedKey);\n\t\tif (!cached) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (cached.expiresAt < Date.now()) {\n\t\t\tthis.mappingCache.delete(hashedKey);\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn cached.mapping;\n\t}\n\n\t/**\n\t * Writes a mapping to the in-memory cache.\n\t * @private\n\t */\n\tprivate setCachedMapping(hashedKey: string, mapping: ShardMapping | null): void {\n\t\tif (this.mappingCache.size > 50_000) {\n\t\t\tconst firstKey = this.mappingCache.keys().next().value;\n\t\t\tif (firstKey) {\n\t\t\t\tthis.mappingCache.delete(firstKey);\n\t\t\t}\n\t\t}\n\n\t\tthis.mappingCache.set(hashedKey, {\n\t\t\tmapping,\n\t\t\texpiresAt: Date.now() + this.mappingCacheTtlMs\n\t\t});\n\t}\n\n\t/**\n\t * Updates mapping cache entries for the provided logical keys.\n\t * @private\n\t */\n\tprivate async cacheMappingForKeys(keys: string[], mapping: ShardMapping | null): Promise<void> {\n\t\tconst hashedKeys = await Promise.all(keys.map((k) => this.hashKey(k)));\n\t\tfor (const hashedKey of hashedKeys) {\n\t\t\tthis.setCachedMapping(hashedKey, mapping);\n\t\t}\n\t}\n\n\t/**\n\t * Retrieves known shards from cache when available.\n\t * @private\n\t */\n\tprivate getCachedKnownShards(): string[] | null {\n\t\tif (this.knownShardsCache.shards && this.knownShardsCache.expiresAt >= Date.now()) {\n\t\t\treturn [...this.knownShardsCache.shards];\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Stores known shards in the cache.\n\t * @private\n\t */\n\tprivate setCachedKnownShards(shards: string[]): void {\n\t\tthis.knownShardsCache.shards = [...shards];\n\t\tthis.knownShardsCache.expiresAt = Date.now() + this.knownShardsCacheTtlMs;\n\t}\n\n\t/**\n\t * Hashes a key using SHA-256 if hashing is enabled\n\t * @param key - The key to hash\n\t * @returns The hashed key or original key if hashing is disabled\n\t */\n\tasync hashKey(key: string): Promise<string> {\n\t\tif (!this.hashKeys) {\n\t\t\treturn key;\n\t\t}\n\n\t\t// Check cache first to avoid repeated crypto operations\n\t\tconst cached = this.hashCache.get(key);\n\t\tif (cached) {\n\t\t\treturn cached;\n\t\t}\n\n\t\tconst encoder = new TextEncoder();\n\t\tconst data = encoder.encode(key);\n\t\tconst hashBuffer = await crypto.subtle.digest('SHA-256', data);\n\t\tconst hashArray = new Uint8Array(hashBuffer);\n\t\tconst hashHex = Array.from(hashArray)\n\t\t\t.map((b) => b.toString(16).padStart(2, '0'))\n\t\t\t.join('');\n\n\t\t// Cache the result (limit cache size to prevent memory issues)\n\t\tif (this.hashCache.size < 10000) {\n\t\t\tthis.hashCache.set(key, hashHex);\n\t\t}\n\n\t\treturn hashHex;\n\t}\n\n\t/**\n\t * Retrieves the shard assignment for a given primary key from KV storage.\n\t * Returns null if no mapping exists, indicating the key has not been\n\t * assigned to any shard yet. Supports both single-key and multi-key lookups.\n\t * @param primaryKey - The primary key to look up (will be hashed if hashing is enabled)\n\t * @returns Promise resolving to the shard mapping or null if not found\n\t * @throws {Error} If KV read operation fails\n\t * @example\n\t * ```typescript\n\t * const mapping = await mapper.getShardMapping('email:user@example.com');\n\t * if (mapping) {\n\t * console.log(`User is on shard: ${mapping.shard}`);\n\t * console.log(`Created: ${new Date(mapping.createdAt)}`);\n\t * } else {\n\t * console.log('User not yet assigned to any shard');\n\t * }\n\t * ```\n\t */\n\tasync getShardMapping(primaryKey: string): Promise<ShardMapping | null> {\n\t\tconst hashedKey = await this.hashKey(primaryKey);\n\t\tconst cached = this.getCachedMapping(hashedKey);\n\t\tif (cached !== undefined) {\n\t\t\treturn cached;\n\t\t}\n\n\t\tconst key = `${SHARD_MAPPING_PREFIX}${hashedKey}`;\n\n\t\t// Try single-key mapping first\n\t\tconst singleMapping = await this.kv.get<ShardMapping>(key, 'json');\n\t\tif (singleMapping) {\n\t\t\tthis.setCachedMapping(hashedKey, singleMapping);\n\t\t\treturn singleMapping;\n\t\t}\n\n\t\t// Try multi-key mapping lookup\n\t\tconst multiKeyMapping = await this.kv.get<MultiKeyShardMapping>(`${MULTI_KEY_MAPPING_PREFIX}${hashedKey}`, 'json');\n\t\tif (multiKeyMapping) {\n\t\t\tconst resolved: ShardMapping = {\n\t\t\t\tshard: multiKeyMapping.shard,\n\t\t\t\tcreatedAt: multiKeyMapping.createdAt,\n\t\t\t\tupdatedAt: multiKeyMapping.updatedAt,\n\t\t\t\toriginalKey: this.hashKeys ? undefined : primaryKey\n\t\t\t};\n\n\t\t\tthis.setCachedMapping(hashedKey, resolved);\n\n\t\t\t// If hash-based key storage is enabled, cache sibling lookup keys too.\n\t\t\tif (this.hashKeys) {\n\t\t\t\tfor (const siblingHashedKey of multiKeyMapping.keys) {\n\t\t\t\t\tthis.setCachedMapping(siblingHashedKey, resolved);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn resolved;\n\t\t}\n\n\t\tthis.setCachedMapping(hashedKey, null);\n\t\treturn null;\n\t}\n\n\t/**\n\t * Creates a new shard assignment for a primary key. This is typically used\n\t * when a new primary key is first encountered and needs to be assigned to\n\t * a shard. Sets both created and updated timestamps to the current time.\n\t *\n\t * **Note**: This will overwrite any existing mapping for the same key.\n\t * Use updateShardMapping() if you want to preserve creation timestamp.\n\t * @param primaryKey - The primary key to map\n\t * @param shard - The shard binding name to assign\n\t * @param additionalKeys - Optional array of additional lookup keys for the same mapping\n\t * @returns Promise that resolves when the mapping is stored\n\t * @throws {Error} If KV write operation fails\n\t * @example\n\t * ```typescript\n\t * // Assign a new user to the west coast shard with multiple lookup keys\n\t * await mapper.setShardMapping('user-123', 'db-west', ['username:john', 'email:john@example.com']);\n\t * ```\n\t */\n\tasync setShardMapping(primaryKey: string, shard: string, additionalKeys: string[] = []): Promise<void> {\n\t\tconst allKeys = [primaryKey, ...additionalKeys];\n\t\tconst timestamp = Date.now();\n\t\tconst mapping: ShardMapping = {\n\t\t\tshard,\n\t\t\tcreatedAt: timestamp,\n\t\t\tupdatedAt: timestamp,\n\t\t\toriginalKey: this.hashKeys ? undefined : primaryKey\n\t\t};\n\n\t\tif (allKeys.length === 1) {\n\t\t\t// Single key mapping - use the original format for backward compatibility\n\t\t\tconst hashedKey = await this.hashKey(primaryKey);\n\t\t\tconst key = `${SHARD_MAPPING_PREFIX}${hashedKey}`;\n\n\t\t\tawait this.kv.put(key, JSON.stringify(mapping));\n\t\t\tthis.setCachedMapping(hashedKey, mapping);\n\t\t} else {\n\t\t\t// Multi-key mapping - store the primary mapping and create lookup entries\n\t\t\tconst primaryHashedKey = await this.hashKey(primaryKey);\n\t\t\tconst primaryMappingKey = `${MULTI_KEY_MAPPING_PREFIX}${primaryHashedKey}`;\n\n\t\t\t// Store hashed keys when hashing is enabled to avoid leaking originals while enabling updates\n\t\t\tconst storedKeys = this.hashKeys ? await Promise.all(allKeys.map((k) => this.hashKey(k))) : allKeys;\n\n\t\t\tconst multiKeyMapping: MultiKeyShardMapping = {\n\t\t\t\tshard,\n\t\t\t\tcreatedAt: timestamp,\n\t\t\t\tupdatedAt: timestamp,\n\t\t\t\tkeys: storedKeys\n\t\t\t};\n\n\t\t\t// Store the primary multi-key mapping\n\t\t\tawait this.kv.put(primaryMappingKey, JSON.stringify(multiKeyMapping));\n\n\t\t\t// Create lookup entries for all keys pointing to the primary mapping\n\t\t\tconst lookupPromises = allKeys.map(async (lookupKey) => {\n\t\t\t\tconst hashedLookupKey = await this.hashKey(lookupKey);\n\t\t\t\tconst lookupMappingKey = `${SHARD_MAPPING_PREFIX}${hashedLookupKey}`;\n\t\t\t\tconst lookupMapping: ShardMapping = {\n\t\t\t\t\tshard,\n\t\t\t\t\tcreatedAt: timestamp,\n\t\t\t\t\tupdatedAt: timestamp,\n\t\t\t\t\toriginalKey: this.hashKeys ? undefined : lookupKey\n\t\t\t\t};\n\t\t\t\treturn this.kv.put(lookupMappingKey, JSON.stringify(lookupMapping));\n\t\t\t});\n\n\t\t\tawait Promise.all(lookupPromises);\n\n\t\t\t// Cache all lookup keys to avoid immediate read-after-write KV hits.\n\t\t\tawait this.cacheMappingForKeys(allKeys, mapping);\n\t\t}\n\t}\n\n\t/**\n\t * Changes the shard assignment for a primary key that already has a mapping.\n\t * Preserves the original creation timestamp while updating the modified\n\t * timestamp. Throws an error if no existing mapping is found.\n\t *\n\t * This is typically used during shard rebalancing or data migration operations.\n\t * Works with both single-key and multi-key mappings.\n\t * @param primaryKey - The primary key to update\n\t * @param newShard - The new shard binding name to assign\n\t * @returns Promise that resolves when the mapping is updated\n\t * @throws {Error} If no existing mapping found or KV operation fails\n\t * @example\n\t * ```typescript\n\t * try {\n\t * // Move user to a different shard for rebalancing\n\t * await mapper.updateShardMapping('email:user@example.com', 'db-central');\n\t * console.log('User successfully moved to central shard');\n\t * } catch (error) {\n\t * console.error('Failed to update mapping:', error.message);\n\t * }\n\t * ```\n\t */\n\tasync updateShardMapping(primaryKey: string, newShard: string): Promise<void> {\n\t\tconst existing = await this.getShardMapping(primaryKey);\n\t\tif (!existing) {\n\t\t\tthrow new CollegeDBError(`No existing mapping found for primary key: ${primaryKey}`, 'MAPPING_NOT_FOUND');\n\t\t}\n\n\t\tconst hashedKey = await this.hashKey(primaryKey);\n\t\tconst singleMappingKey = `${SHARD_MAPPING_PREFIX}${hashedKey}`;\n\t\tconst multiKeyMappingKey = `${MULTI_KEY_MAPPING_PREFIX}${hashedKey}`;\n\n\t\t// Check if this is a multi-key mapping\n\t\tconst multiKeyMapping = await this.kv.get<MultiKeyShardMapping>(multiKeyMappingKey, 'json');\n\n\t\tif (multiKeyMapping) {\n\t\t\t// Update multi-key mapping\n\t\t\tconst timestamp = Date.now();\n\t\t\tconst updatedMultiKeyMapping: MultiKeyShardMapping = {\n\t\t\t\t...multiKeyMapping,\n\t\t\t\tshard: newShard,\n\t\t\t\tupdatedAt: timestamp\n\t\t\t};\n\t\t\tawait this.kv.put(multiKeyMappingKey, JSON.stringify(updatedMultiKeyMapping));\n\n\t\t\t// Update all lookup entries. Keys are stored hashed when hashing is enabled.\n\t\t\tconst keysToUpdate =\n\t\t\t\tmultiKeyMapping.keys.length > 0 ? (this.hashKeys ? multiKeyMapping.keys : multiKeyMapping.keys) : [await this.hashKey(primaryKey)]; // Fallback for legacy empty key lists\n\n\t\t\tconst lookupPromises = keysToUpdate.map(async (keyId) => {\n\t\t\t\tconst lookupMappingKey = `${SHARD_MAPPING_PREFIX}${keyId}`;\n\t\t\t\tconst lookupMapping: ShardMapping = {\n\t\t\t\t\t...existing,\n\t\t\t\t\tshard: newShard,\n\t\t\t\t\tupdatedAt: timestamp\n\t\t\t\t};\n\t\t\t\treturn this.kv.put(lookupMappingKey, JSON.stringify(lookupMapping));\n\t\t\t});\n\n\t\t\tawait Promise.all(lookupPromises);\n\n\t\t\tconst updatedMapping: ShardMapping = {\n\t\t\t\t...existing,\n\t\t\t\tshard: newShard,\n\t\t\t\tupdatedAt: timestamp\n\t\t\t};\n\n\t\t\tif (this.hashKeys) {\n\t\t\t\tfor (const keyId of keysToUpdate) {\n\t\t\t\t\tthis.setCachedMapping(keyId, updatedMapping);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.setCachedMapping(hashedKey, updatedMapping);\n\t\t} else {\n\t\t\t// Update single-key mapping\n\t\t\tconst updatedMapping: ShardMapping = {\n\t\t\t\t...existing,\n\t\t\t\tshard: newShard,\n\t\t\t\tupdatedAt: Date.now()\n\t\t\t};\n\t\t\tawait this.kv.put(singleMappingKey, JSON.stringify(updatedMapping));\n\t\t\tthis.setCachedMapping(hashedKey, updatedMapping);\n\t\t}\n\t}\n\n\t/**\n\t * Completely removes the shard assignment for a primary key from KV storage.\n\t * This is typically used when data is being permanently deleted or when\n\t * cleaning up orphaned mappings. Handles both single-key and multi-key mappings.\n\t *\n\t * **WARNING**: After deletion, the primary key will be treated as new\n\t * and may be assigned to a different shard on next access.\n\t *\n\t * @param primaryKey - The primary key mapping to remove\n\t * @returns Promise that resolves when the mapping is deleted\n\t * @throws {Error} If KV delete operation fails\n\t * @example\n\t * ```typescript\n\t * // Remove mapping for deleted user\n\t * await mapper.deleteShardMapping('email:deleted@example.com');\n\t * console.log('Mapping removed for deleted user');\n\t * ```\n\t */\n\tasync deleteShardMapping(primaryKey: string): Promise<void> {\n\t\tconst hashedKey = await this.hashKey(primaryKey);\n\t\tconst singleMappingKey = `${SHARD_MAPPING_PREFIX}${hashedKey}`;\n\t\tconst multiKeyMappingKey = `${MULTI_KEY_MAPPING_PREFIX}${hashedKey}`;\n\n\t\t// Check if this is a multi-key mapping\n\t\tconst multiKeyMapping = await this.kv.get<MultiKeyShardMapping>(multiKeyMappingKey, 'json');\n\n\t\tif (multiKeyMapping) {\n\t\t\t// Delete multi-key mapping\n\t\t\tawait this.kv.delete(multiKeyMappingKey);\n\n\t\t\t// Delete all lookup entries. Keys are stored hashed when hashing is enabled.\n\t\t\tconst keysToDelete =\n\t\t\t\tmultiKeyMapping.keys.length > 0 ? (this.hashKeys ? multiKeyMapping.keys : multiKeyMapping.keys) : [await this.hashKey(primaryKey)]; // Fallback for legacy empty key lists\n\n\t\t\tconst deletePromises = keysToDelete.map(async (keyId) => {\n\t\t\t\tconst lookupMappingKey = `${SHARD_MAPPING_PREFIX}${keyId}`;\n\t\t\t\treturn this.kv.delete(lookupMappingKey);\n\t\t\t});\n\n\t\t\tawait Promise.all(deletePromises);\n\n\t\t\tif (this.hashKeys) {\n\t\t\t\tfor (const keyId of keysToDelete) {\n\t\t\t\t\tthis.setCachedMapping(keyId, null);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.setCachedMapping(hashedKey, null);\n\t\t} else {\n\t\t\t// Delete single-key mapping\n\t\t\tawait this.kv.delete(singleMappingKey);\n\t\t\tthis.setCachedMapping(hashedKey, null);\n\t\t}\n\t}\n\n\t/**\n\t * Retrieves the list of all shard binding names that have been registered\n\t * with the system. This is maintained separately from the individual mappings\n\t * for efficient shard discovery.\n\t *\n\t * @returns Promise resolving to array of shard binding names\n\t * @throws {Error} If KV read operation fails\n\t * @example\n\t * ```typescript\n\t * const shards = await mapper.getKnownShards();\n\t * console.log('Available shards:', shards);\n\t * // Output: ['db-east', 'db-west', 'db-central']\n\t * ```\n\t */\n\tasync getKnownShards(): Promise<string[]> {\n\t\tconst cached = this.getCachedKnownShards();\n\t\tif (cached) {\n\t\t\treturn cached;\n\t\t}\n\n\t\tconst shards = await this.kv.get<string[]>(KNOWN_SHARDS_KEY, 'json');\n\t\tconst normalized = shards || [];\n\t\tthis.setCachedKnownShards(normalized);\n\t\treturn normalized;\n\t}\n\n\t/**\n\t * Replaces the entire list of known shards with a new list. This is typically\n\t * used during system initialization or when shards are added/removed in bulk.\n\t *\n\t * @param shards - Array of shard binding names to store\n\t * @returns Promise that resolves when the list is updated\n\t * @throws {Error} If KV write operation fails\n\t * @example\n\t * ```typescript\n\t * // Update shard list after adding new regions\n\t * await mapper.setKnownShards(['db-east', 'db-west', 'db-central', 'db-asia']);\n\t * ```\n\t */\n\tasync setKnownShards(shards: string[]): Promise<void> {\n\t\tif (!shards || shards.length === 0) return;\n\n\t\tconst unique = [...new Set(shards.filter(Boolean))];\n\t\tif (unique.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.kv.put(KNOWN_SHARDS_KEY, JSON.stringify(unique));\n\t\tthis.setCachedKnownShards(unique);\n\t}\n\n\t/**\n\t * Appends a new shard to the list of known shards if it's not already present.\n\t * This operation is idempotent - adding the same shard multiple times has no effect.\n\t *\n\t * @param shard - The shard binding name to add\n\t * @returns Promise that resolves when the shard is added\n\t * @throws {Error} If KV operations fail\n\t * @example\n\t * ```typescript\n\t * // Register a new shard when it comes online\n\t * await mapper.addKnownShard('db-europe');\n\t * console.log('European shard registered');\n\t * ```\n\t */\n\tasync addKnownShard(shard: string): Promise<void> {\n\t\tif (!shard) return;\n\n\t\tconst knownShards = await this.getKnownShards();\n\t\tif (!knownShards.includes(shard)) {\n\t\t\tknownShards.push(shard);\n\t\t\tawait this.setKnownShards(knownShards);\n\t\t}\n\t}\n\n\t/**\n\t * Scans all shard mappings to find primary keys assigned to the specified shard.\n\t * This operation requires reading all mappings and can be expensive for large\n\t * datasets. Consider caching results or using getShardKeyCounts() for statistics.\n\t *\n\t * @param shard - The shard binding name to search for\n\t * @returns Promise resolving to array of primary keys assigned to the shard\n\t * @throws {Error} If KV operations fail\n\t * @example\n\t * ```typescript\n\t * // Find all users on the east coast shard\n\t * const eastCoastUsers = await mapper.getKeysForShard('db-east');\n\t * console.log(`East coast has ${eastCoastUsers.length} users`);\n\t * ```\n\t */\n\tasync getKeysForShard(shard: string): Promise<string[]> {\n\t\tconst keys: string[] = [];\n\n\t\t// Scan single-key mappings\n\t\tconst singleKeyList = await this.kv.list({ prefix: SHARD_MAPPING_PREFIX });\n\t\tfor (const kvKey of singleKeyList.keys) {\n\t\t\tconst mapping = await this.kv.get<ShardMapping>(kvKey.name, 'json');\n\t\t\tif (mapping?.shard === shard) {\n\t\t\t\tconst originalKey = kvKey.name.replace(SHARD_MAPPING_PREFIX, '');\n\t\t\t\t// If hashing is enabled, we can't recover the original key\n\t\t\t\tif (mapping.originalKey) {\n\t\t\t\t\tkeys.push(mapping.originalKey);\n\t\t\t\t} else if (!this.hashKeys) {\n\t\t\t\t\tkeys.push(originalKey);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Scan multi-key mappings\n\t\tconst multiKeyList = await this.kv.list({ prefix: MULTI_KEY_MAPPING_PREFIX });\n\t\tfor (const kvKey of multiKeyList.keys) {\n\t\t\tconst mapping = await this.kv.get<MultiKeyShardMapping>(kvKey.name, 'json');\n\t\t\tif (mapping?.shard === shard) {\n\t\t\t\t// Add all keys from this multi-key mapping\n\t\t\t\tkeys.push(...mapping.keys);\n\t\t\t}\n\t\t}\n\n\t\treturn [...new Set(keys)]; // Remove duplicates\n\t}\n\n\t/**\n\t * Scans all shard mappings to count how many primary keys are assigned to\n\t * each shard. Returns a mapping of shard names to their key counts. This\n\t * is useful for load balancing and monitoring shard utilization.\n\t *\n\t * **Performance Note**: This operation scans all mappings and can be\n\t * expensive for large datasets. Consider implementing caching for frequently\n\t * accessed statistics.\n\t *\n\t * @returns Promise resolving to object mapping shard names to key counts\n\t * @throws {Error} If KV operations fail\n\t * @example\n\t * ```typescript\n\t * const counts = await mapper.getShardKeyCounts();\n\t * console.log('Shard utilization:', counts);\n\t * // Output: { 'db-east': 1247, 'db-west': 982, 'db-central': 1156 }\n\t *\n\t * // Find the least loaded shard\n\t * const leastLoaded = Object.entries(counts)\n\t * .sort(([,a], [,b]) => a - b)[0][0];\n\t * console.log('Least loaded shard:', leastLoaded);\n\t * ```\n\t */\n\tasync getShardKeyCounts(): Promise<Record<string, number>> {\n\t\tconst counts: Record<string, number> = {};\n\n\t\t// Count single-key mappings\n\t\tconst singleKeyList = await this.kv.list({ prefix: SHARD_MAPPING_PREFIX });\n\t\tfor (const kvKey of singleKeyList.keys) {\n\t\t\tconst mapping = await this.kv.get<ShardMapping>(kvKey.name, 'json');\n\t\t\tif (mapping) {\n\t\t\t\tcounts[mapping.shard] = (counts[mapping.shard] || 0) + 1;\n\t\t\t}\n\t\t}\n\n\t\t// Count multi-key mappings\n\t\tconst multiKeyList = await this.kv.list({ prefix: MULTI_KEY_MAPPING_PREFIX });\n\t\tfor (const kvKey of multiKeyList.keys) {\n\t\t\tconst mapping = await this.kv.get<MultiKeyShardMapping>(kvKey.name, 'json');\n\t\t\tif (mapping) {\n\t\t\t\t// Each multi-key mapping represents multiple keys, so count them all\n\t\t\t\tcounts[mapping.shard] = (counts[mapping.shard] || 0) + mapping.keys.length;\n\t\t\t}\n\t\t}\n\n\t\treturn counts;\n\t}\n\n\t/**\n\t * Deletes ALL shard mappings from KV storage. This is a destructive operation\n\t * that removes all primary key assignments. After this operation, all keys\n\t * will be treated as new and may be assigned to different shards.\n\t *\n\t * **DANGER**: This operation is irreversible and will cause data routing\n\t * issues if used in production. Only use during development, testing, or\n\t * complete system resets.\n\t *\n\t * @returns Promise that resolves when all mappings are deleted\n\t * @throws {Error} If KV operations fail\n\t * @example\n\t * ```typescript\n\t * // Only use in development/testing!\n\t * if (process.env.NODE_ENV === 'development') {\n\t * await mapper.clearAllMappings();\n\t * console.log('All mappings cleared for testing');\n\t * }\n\t * ```\n\t */\n\tasync clearAllMappings(): Promise<void> {\n\t\t// Clear single-key mappings\n\t\tconst singleKeyList = await this.kv.list({ prefix: SHARD_MAPPING_PREFIX });\n\t\tconst singleKeyPromises = singleKeyList.keys.map((key) => this.kv.delete(key.name));\n\n\t\t// Clear multi-key mappings\n\t\tconst multiKeyList = await this.kv.list({ prefix: MULTI_KEY_MAPPING_PREFIX });\n\t\tconst multiKeyPromises = multiKeyList.keys.map((key) => this.kv.delete(key.name));\n\n\t\tawait Promise.all([...singleKeyPromises, ...multiKeyPromises]);\n\t\tthis.mappingCache.clear();\n\t}\n\n\t/**\n\t * Adds additional lookup keys to an existing shard mapping. This allows you to\n\t * query the same shard mapping using multiple identifiers (e.g., username, email, id).\n\t *\n\t * @param primaryKey - An existing key in the mapping\n\t * @param additionalKeys - New keys to add for lookup\n\t * @returns Promise that resolves when the additional keys are added\n\t * @throws {Error} If no existing mapping found or KV operations fail\n\t * @example\n\t * ```typescript\n\t * // Add email lookup to an existing user mapping\n\t * await mapper.addLookupKeys('user-123', ['email:user@example.com']);\n\t * ```\n\t * @since 1.0.3\n\t */\n\tasync addLookupKeys(primaryKey: string, additionalKeys: string[]): Promise<void> {\n\t\tconst existing = await this.getShardMapping(primaryKey);\n\t\tif (!existing) {\n\t\t\tthrow new CollegeDBError(`No existing mapping found for primary key: ${primaryKey}`, 'MAPPING_NOT_FOUND');\n\t\t}\n\n\t\t// Create a new multi-key mapping or add to existing one\n\t\tconst hashedPrimaryKey = await this.hashKey(primaryKey);\n\t\tconst multiKeyMappingKey = `${MULTI_KEY_MAPPING_PREFIX}${hashedPrimaryKey}`;\n\t\tlet multiKeyMapping = await this.kv.get<MultiKeyShardMapping>(multiKeyMappingKey, 'json');\n\n\t\tconst allKeys = [primaryKey, ...additionalKeys];\n\t\tconst timestamp = Date.now();\n\n\t\tif (!multiKeyMapping) {\n\t\t\t// Convert single-key to multi-key mapping\n\t\t\tconst storedAllKeys = this.hashKeys ? await Promise.all(allKeys.map((k) => this.hashKey(k))) : allKeys;\n\t\t\tmultiKeyMapping = {\n\t\t\t\tshard: existing.shard,\n\t\t\t\tcreatedAt: existing.createdAt,\n\t\t\t\tupdatedAt: timestamp,\n\t\t\t\tkeys: storedAllKeys\n\t\t\t};\n\t\t} else {\n\t\t\t// Add to existing multi-key mapping\n\t\t\tconst storedAllKeys = this.hashKeys ? await Promise.all(allKeys.map((k) => this.hashKey(k))) : allKeys;\n\t\t\tmultiKeyMapping = {\n\t\t\t\t...multiKeyMapping,\n\t\t\t\tupdatedAt: timestamp,\n\t\t\t\tkeys: [...new Set([...multiKeyMapping.keys, ...storedAllKeys])]\n\t\t\t};\n\t\t}\n\n\t\t// Store the updated multi-key mapping\n\t\tawait this.kv.put(multiKeyMappingKey, JSON.stringify(multiKeyMapping));\n\n\t\t// Create lookup entries for the new additional keys\n\t\tconst lookupPromises = additionalKeys.map(async (lookupKey) => {\n\t\t\tconst hashedLookupKey = await this.hashKey(lookupKey);\n\t\t\tconst lookupMappingKey = `${SHARD_MAPPING_PREFIX}${hashedLookupKey}`;\n\t\t\tconst lookupMapping: ShardMapping = {\n\t\t\t\tshard: existing.shard,\n\t\t\t\tcreatedAt: existing.createdAt,\n\t\t\t\tupdatedAt: timestamp,\n\t\t\t\toriginalKey: this.hashKeys ? undefined : lookupKey\n\t\t\t};\n\t\t\treturn this.kv.put(lookupMappingKey, JSON.stringify(lookupMapping));\n\t\t});\n\n\t\tawait Promise.all(lookupPromises);\n\n\t\t// Refresh cache for primary and added keys.\n\t\tconst refreshedMapping: ShardMapping = {\n\t\t\tshard: existing.shard,\n\t\t\tcreatedAt: existing.createdAt,\n\t\t\tupdatedAt: timestamp,\n\t\t\toriginalKey: existing.originalKey\n\t\t};\n\t\tawait this.cacheMappingForKeys([primaryKey, ...additionalKeys], refreshedMapping);\n\t}\n\n\t/**\n\t * Sets multiple shard mappings concurrently with a configurable concurrency limit.\n\t *\n\t * This helper is used by migration workflows to significantly reduce total\n\t * mapping time while avoiding unbounded concurrency spikes.\n\t *\n\t * @param mappings - The mappings to create\n\t * @param options - Batch execution options\n\t * @param options.concurrency - Maximum concurrent set operations (default: 25)\n\t * @returns Promise that resolves when all mappings are written\n\t * @since 1.1.0\n\t */\n\tasync setShardMappingsBatch(\n\t\tmappings: Array<{ primaryKey: string; shard: string; additionalKeys?: string[] }>,\n\t\toptions: { concurrency?: number } = {}\n\t): Promise<void> {\n\t\tif (mappings.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst concurrency = Math.max(1, options.concurrency ?? 25);\n\t\tlet index = 0;\n\n\t\tconst workers = new Array(Math.min(concurrency, mappings.length)).fill(null).map(async () => {\n\t\t\twhile (index < mappings.length) {\n\t\t\t\tconst currentIndex = index++;\n\t\t\t\tconst item = mappings[currentIndex];\n\t\t\t\tif (!item) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tawait this.setShardMapping(item.primaryKey, item.shard, item.additionalKeys || []);\n\t\t\t}\n\t\t});\n\n\t\tawait Promise.all(workers);\n\t}\n\n\t/**\n\t * Gets all lookup keys associated with a shard mapping. This is useful for\n\t * understanding what keys resolve to the same shard.\n\t *\n\t * @param primaryKey - Any key in the mapping\n\t * @returns Promise resolving to array of all keys in the mapping\n\t * @throws {Error} If no existing mapping found\n\t * @example\n\t * ```typescript\n\t * const allKeys = await mapper.getAllLookupKeys('email:user@example.com');\n\t * console.log(allKeys); // ['user-123', 'username:john', 'email:user@example.com']\n\t * ```\n\t * @since 1.0.3\n\t */\n\tasync getAllLookupKeys(primaryKey: string): Promise<string[]> {\n\t\tconst hashedKey = await this.hashKey(primaryKey);\n\t\tconst multiKeyMappingKey = `${MULTI_KEY_MAPPING_PREFIX}${hashedKey}`;\n\n\t\t// Check if this is a multi-key mapping\n\t\tconst multiKeyMapping = await this.kv.get<MultiKeyShardMapping>(multiKeyMappingKey, 'json');\n\t\tif (multiKeyMapping) {\n\t\t\treturn multiKeyMapping.keys;\n\t\t}\n\n\t\t// If not a multi-key mapping, check if single-key mapping exists\n\t\tconst singleMapping = await this.getShardMapping(primaryKey);\n\t\tif (singleMapping) {\n\t\t\treturn singleMapping.originalKey ? [singleMapping.originalKey] : [primaryKey];\n\t\t}\n\n\t\tthrow new CollegeDBError(`No mapping found for key: ${primaryKey}`, 'MAPPING_NOT_FOUND');\n\t}\n}\n",
7
7
  "/**\n * @fileoverview Database schema management and data migration utilities for CollegeDB\n *\n * This module provides utilities for managing database schemas across multiple D1 shards\n * and migrating data between shards. It includes default schema definitions, schema\n * validation, and data migration functions that ensure consistency across the distributed\n * database system.\n *\n * Key features:\n * - Default schema creation for typical use cases\n * - Schema validation and existence checking\n * - Data migration between D1 database instances\n * - Batch schema operations across multiple shards\n * - Table discovery and management utilities\n *\n * @example\n * ```typescript\n * import { createSchema, migrateRecord, schemaExists } from './migrations';\n *\n * // Create schema on a new shard\n * await createSchema(env.DB_EAST);\n *\n * // Check if schema exists\n * const hasSchema = await schemaExists(env.DB_WEST);\n *\n * // Migrate a user from one shard to another\n * await migrateRecord(env.DB_EAST, env.DB_WEST, 'user-123', 'users');\n * ```\n *\n * @author Gregory Mitchell\n * @since 1.0.0\n */\n\nimport { CollegeDBError } from './errors';\nimport type { KVShardMapper } from './kvmap';\nimport type { CollegeDBConfig, SQLDatabase, ShardingStrategy } from './types';\n\n/**\n * Cache for migration status to avoid repeated checks\n * @private\n */\nconst migrationStatusCache = new Map<string, boolean>();\n\n/**\n * Cache for table structure information to avoid repeated PRAGMA queries\n * @private\n */\nconst tableInfoCache = new Map<string, Array<{ name: string; type: string }>>();\n\n/**\n * Runs async work with a bounded concurrency limit.\n * @private\n */\nasync function mapWithConcurrency<T>(items: T[], concurrency: number, work: (item: T, index: number) => Promise<void>): Promise<void> {\n\tif (items.length === 0) {\n\t\treturn;\n\t}\n\n\tconst workerCount = Math.max(1, Math.min(concurrency, items.length));\n\tlet index = 0;\n\n\tconst workers = new Array(workerCount).fill(null).map(async () => {\n\t\twhile (index < items.length) {\n\t\t\tconst currentIndex = index++;\n\t\t\tconst item = items[currentIndex];\n\t\t\tif (item === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tawait work(item, currentIndex);\n\t\t}\n\t});\n\n\tawait Promise.all(workers);\n}\n\n/**\n * Selects a shard for a key using the requested strategy.\n * @private\n */\nfunction selectShardForKey(\n\tprimaryKey: string,\n\tindex: number,\n\tshardBindings: string[],\n\tstrategy: 'hash' | 'round-robin' | 'random'\n): string {\n\tconst totalShards = shardBindings.length;\n\n\tswitch (strategy) {\n\t\tcase 'hash': {\n\t\t\tlet hash = 0;\n\t\t\tfor (let i = 0; i < primaryKey.length; i++) {\n\t\t\t\tconst char = primaryKey.charCodeAt(i);\n\t\t\t\thash = (hash << 5) - hash + char;\n\t\t\t\thash = hash & hash;\n\t\t\t}\n\t\t\tconst hashIndex = Math.abs(hash) % totalShards;\n\t\t\treturn shardBindings[hashIndex]!;\n\t\t}\n\t\tcase 'random':\n\t\t\treturn shardBindings[Math.floor(Math.random() * totalShards)]!;\n\t\tdefault:\n\t\t\treturn shardBindings[index % totalShards]!;\n\t}\n}\n\n/**\n * Executes SQL statements to create the default table structure and indexes\n * in the specified D1 database. Supports custom schemas and handles SQL\n * statement parsing with comment filtering.\n *\n * The function:\n * 1. Splits the schema into individual SQL statements\n * 2. Filters out comments and empty statements\n * 3. Executes each statement using prepared statements\n * 4. Provides detailed error reporting on failures\n *\n * @param d1 - The D1 database instance to create schema in\n * @param schema - Schema SQL to use\n * @returns Promise that resolves when all schema statements are executed\n * @throws {Error} If any schema statement fails with detailed error information\n * @example\n * ```typescript\n * const sql = `\n * CREATE TABLE products (\n * id TEXT PRIMARY KEY,\n * name TEXT NOT NULL,\n * price REAL\n * );\n * `;\n * await createSchema(env.DB_PRODUCTS, sql);\n * ```\n */\nexport async function createSchema(d1: SQLDatabase, schema: string): Promise<void> {\n\tconst statements = schema\n\t\t.split(';')\n\t\t.map((stmt) => stmt.trim())\n\t\t.filter((stmt) => stmt.length > 0 && !stmt.startsWith('--')); // Filter out comments\n\n\tfor (const statement of statements) {\n\t\ttry {\n\t\t\tawait d1.prepare(statement).run();\n\t\t} catch (error) {\n\t\t\tconsole.error('Failed to execute schema statement:', statement, error);\n\t\t\tthrow new CollegeDBError(`Schema migration failed: ${error}`, 'SCHEMA_MIGRATION_FAILED');\n\t\t}\n\t}\n}\n\n/**\n * Applies the schema to all provided D1 database instances in parallel.\n * This is useful for initializing a complete sharded database system\n * where all shards need the same table structure.\n *\n * The function executes schema creation on all shards concurrently for\n * performance, but provides detailed error reporting that identifies\n * which specific shard failed if any errors occur.\n *\n * @param shards - Record mapping shard names to D1 database instances\n * @param schema - Schema SQL to use\n * @returns Promise that resolves when schema is created on all shards\n * @throws {Error} If schema creation fails on any shard, with shard identification\n * @example\n * ```typescript\n * const shards = {\n * 'db-east': env.DB_EAST,\n * 'db-west': env.DB_WEST,\n * 'db-central': env.DB_CENTRAL\n * };\n *\n * try {\n * await createSchemaAcrossShards(shards);\n * console.log('Schema created on all shards successfully');\n * } catch (error) {\n * console.error('Schema creation failed:', error.message);\n * // Error will specify which shard failed\n * }\n * ```\n */\nexport async function createSchemaAcrossShards(shards: Record<string, SQLDatabase>, schema: string): Promise<void> {\n\tconst promises = Object.entries(shards).map(([shardName, db]) => {\n\t\treturn createSchema(db, schema).catch((error) => {\n\t\t\tthrow new CollegeDBError(`Failed to create schema on shard ${shardName}: ${error.message}`, 'SCHEMA_CREATION_FAILED');\n\t\t});\n\t});\n\n\tawait Promise.all(promises);\n}\n\n/**\n * Performs a lightweight check to determine if the expected schema is present\n * in the database.\n *\n * @param d1 - The D1 database instance to check\n * @param table - The name of the table to check\n * @returns Promise resolving to true if schema tables exist, false otherwise\n * @example\n * ```typescript\n * const hasSchema = await schemaExists(env.DB_NEW_SHARD, \"users\");\n * if (!hasSchema) {\n * console.log('Creating schema on new shard...');\n * await createSchema(env.DB_NEW_SHARD, usersSchema);\n * }\n * ```\n */\nexport async function schemaExists(d1: SQLDatabase, table: string): Promise<boolean> {\n\ttry {\n\t\tconst result = await d1.prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name=?\").bind(table).first();\n\t\treturn result !== null;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Removes all tables that are part of the default CollegeDB schema from\n * the specified database. This is a destructive operation that cannot be undone.\n *\n * **DANGER**: This operation permanently deletes all data in the affected\n * tables. Only use during development, testing, or complete system resets.\n *\n * @param d1 - The D1 database instance to drop tables from\n * @param tables - The table schemas to drop\n * @returns Promise that resolves when all tables are dropped\n * @example\n * ```typescript\n * // Only use in development/testing environments!\n * if (process.env.NODE_ENV === 'development') {\n * await dropSchema(env.DB_TEST);\n * console.log('Test database reset completed');\n * }\n * ```\n */\nexport async function dropSchema(d1: SQLDatabase, ...tables: string[]): Promise<void> {\n\tfor (const table of tables) {\n\t\ttry {\n\t\t\tawait d1.prepare(`DROP TABLE IF EXISTS ${table}`).run();\n\t\t} catch (error) {\n\t\t\tconsole.error(`Failed to drop table ${table}:`, error);\n\t\t}\n\t}\n}\n\n/**\n * Queries the SQLite system catalog to retrieve all user-created tables\n * in the database. This is useful for schema inspection, validation,\n * and debugging purposes.\n *\n * @param d1 - The D1 database instance to inspect\n * @returns Promise resolving to array of table names, sorted alphabetically\n * @throws Returns empty array if query fails or database is inaccessible\n * @example\n * ```typescript\n * const tables = await listTables(env.DB_EAST);\n * console.log('Available tables:', tables);\n * // Output: ['posts', 'shard_mappings', 'users']\n *\n * // Check for specific table\n * if (tables.includes('users')) {\n * console.log('Users table exists');\n * }\n * ```\n */\nexport async function listTables(d1: SQLDatabase): Promise<string[]> {\n\ttry {\n\t\tconst result = await d1.prepare(\"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name\").all();\n\t\treturn result.results.map((row: any) => row.name as string);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Moves a single record from a source D1 database to a target D1 database.\n * This is typically used during shard rebalancing operations when data needs\n * to be redistributed across shards for load balancing.\n *\n * The migration process:\n * 1. Retrieves the complete record from the source database\n * 2. Ensures the target database has the required schema\n * 3. Inserts the record into the target database (using REPLACE for safety)\n * 4. Deletes the record from the source database\n *\n * The operation is atomic from the perspective of each database, but not\n * across databases. If the operation fails partway through, manual cleanup\n * may be required.\n *\n * @param source - Source D1 database containing the record\n * @param target - Target D1 database to receive the record\n * @param primaryKey - Primary key of the record to migrate\n * @param tableName - Name of the table containing the record\n * @returns Promise that resolves when migration is complete\n * @throws {Error} If source record not found, schema creation fails, or database operations fail\n * @example\n * ```typescript\n * // Migrate a user from east to west shard\n * try {\n * await migrateRecord(env.DB_EAST, env.DB_WEST, 'user-123', 'users');\n * console.log('User migration completed successfully');\n * } catch (error) {\n * console.error('Migration failed:', error.message);\n * // May need manual cleanup depending on where it failed\n * }\n *\n * // Migrate a post between shards\n * await migrateRecord(source, target, 'post-456', 'posts');\n * ```\n */\nexport async function migrateRecord(source: SQLDatabase, target: SQLDatabase, primaryKey: string, tableName: string): Promise<void> {\n\tconst sourceRecord = await source.prepare(`SELECT * FROM ${tableName} WHERE id = ?`).bind(primaryKey).first();\n\n\tif (!sourceRecord) {\n\t\tthrow new CollegeDBError(`Record with primary key ${primaryKey} not found in source database`, 'RECORD_NOT_FOUND');\n\t}\n\n\t// Create schema if it doesn't exist in target\n\tif (!(await schemaExists(target, tableName))) {\n\t\tawait createSchema(target, tableName);\n\t}\n\n\t// Get column names\n\tconst columns = Object.keys(sourceRecord);\n\tconst placeholders = columns.map(() => '?').join(', ');\n\tconst values = columns.map((col) => sourceRecord[col as keyof typeof sourceRecord]);\n\n\t// Insert into target database\n\tconst insertSQL = `INSERT OR REPLACE INTO ${tableName} (${columns.join(', ')}) VALUES (${placeholders})`;\n\tawait target\n\t\t.prepare(insertSQL)\n\t\t.bind(...values)\n\t\t.run();\n\n\t// Delete from source database\n\tawait source.prepare(`DELETE FROM ${tableName} WHERE id = ?`).bind(primaryKey).run();\n}\n\n/**\n * Scans an existing table to find all primary keys that need to be mapped to shards.\n * This is useful when integrating CollegeDB with an existing database that already\n * contains data. The function assumes the table has an 'id' column as the primary key.\n *\n * @param d1 - The D1 database instance to scan\n * @param tableName - Name of the table to discover primary keys from\n * @param primaryKeyColumn - Name of the primary key column (defaults to 'id')\n * @returns Promise resolving to array of primary key values\n * @throws {Error} If table doesn't exist or database query fails\n * @example\n * ```typescript\n * // Discover all user IDs in an existing users table\n * const userIds = await discoverExistingPrimaryKeys(env.DB_EXISTING, 'users');\n * console.log(`Found ${userIds.length} existing users`);\n *\n * // Discover with custom primary key column\n * const orderIds = await discoverExistingPrimaryKeys(env.DB_ORDERS, 'orders', 'order_id');\n * ```\n */\nexport async function discoverExistingPrimaryKeys(d1: SQLDatabase, tableName: string, primaryKeyColumn: string = 'id'): Promise<string[]> {\n\ttry {\n\t\tconst result = await d1.prepare(`SELECT ${primaryKeyColumn} FROM ${tableName}`).all();\n\t\treturn result.results.map((row: any) => String(row[primaryKeyColumn]));\n\t} catch (error) {\n\t\tthrow new CollegeDBError(`Failed to discover primary keys in table ${tableName}: ${error}`, 'DISCOVERY_FAILED');\n\t}\n}\n\n/**\n * Discovers existing records with additional columns for multi-key mapping support.\n * Scans a table to find primary keys along with username, email, and name columns\n * when they exist, allowing these additional columns to be used as lookup keys.\n *\n * @param d1 - The D1 database instance to scan\n * @param tableName - Name of the table to discover records from\n * @param primaryKeyColumn - Name of the primary key column (defaults to 'id')\n * @returns Promise resolving to array of record data with available columns\n * @throws {Error} If table doesn't exist or database query fails\n * @example\n * ```typescript\n * // Discover all user records with available lookup columns\n * const records = await discoverExistingRecordsWithColumns(env.DB_EXISTING, 'users');\n * console.log(`Found ${records.length} user records`);\n * records.forEach(record => {\n * console.log(`ID: ${record.id}, Email: ${record.email || 'N/A'}`);\n * });\n * ```\n * @since 1.0.4\n */\nexport async function discoverExistingRecordsWithColumns(\n\td1: SQLDatabase,\n\ttableName: string,\n\tprimaryKeyColumn: string = 'id'\n): Promise<Array<{ [key: string]: any }>> {\n\ttry {\n\t\t// Check cache first to avoid repeated PRAGMA queries\n\t\tconst cacheKey = `${tableName}_columns`;\n\t\tlet availableColumns: string[];\n\n\t\tif (tableInfoCache.has(cacheKey)) {\n\t\t\tavailableColumns = tableInfoCache.get(cacheKey)!.map((col) => col.name);\n\t\t} else {\n\t\t\t// First, discover what columns exist in the table\n\t\t\tconst columnInfo = await d1.prepare(`PRAGMA table_info(${tableName})`).all();\n\t\t\tconst columnData = (columnInfo.results as any[]).map((col) => ({ name: col.name as string, type: col.type as string }));\n\n\t\t\t// Cache the result\n\t\t\ttableInfoCache.set(cacheKey, columnData);\n\t\t\tavailableColumns = columnData.map((col) => col.name);\n\t\t}\n\n\t\t// Build SELECT statement with available columns\n\t\tconst columnsToSelect = [primaryKeyColumn];\n\n\t\t// Add optional columns if they exist\n\t\tif (availableColumns.includes('username')) {\n\t\t\tcolumnsToSelect.push('username');\n\t\t}\n\t\tif (availableColumns.includes('email')) {\n\t\t\tcolumnsToSelect.push('email');\n\t\t}\n\t\tif (availableColumns.includes('name')) {\n\t\t\tcolumnsToSelect.push('name');\n\t\t}\n\n\t\tconst selectQuery = `SELECT ${columnsToSelect.join(', ')} FROM ${tableName}`;\n\t\tconst result = await d1.prepare(selectQuery).all();\n\n\t\treturn result.results as Array<{ [key: string]: any }>;\n\t} catch (error) {\n\t\tthrow new CollegeDBError(`Failed to discover records with columns in table ${tableName}: ${error}`, 'DISCOVERY_FAILED');\n\t}\n}\n\n/**\n * Takes a list of existing primary keys and creates shard mappings for them using\n * the specified allocation strategy. This allows existing data to be integrated\n * into the CollegeDB sharding system without data migration.\n *\n * @param primaryKeys - Array of primary key values to create mappings for\n * @param shardBindings - Array of available shard binding names\n * @param strategy - Allocation strategy to use ('hash', 'round-robin', or 'random')\n * @param mapper - KVShardMapper instance for storing mappings\n * @returns Promise that resolves when all mappings are created\n * @throws {Error} If mapping creation fails\n * @example\n * ```typescript\n * import { KVShardMapper } from './kvmap';\n *\n * const mapper = new KVShardMapper(env.KV);\n * const existingIds = await discoverExistingPrimaryKeys(env.DB_EXISTING, 'users');\n * const shards = ['db-east', 'db-west', 'db-central'];\n *\n * await createMappingsForExistingKeys(existingIds, shards, 'hash', mapper);\n * console.log('All existing users mapped to shards');\n * ```\n */\nexport async function createMappingsForExistingKeys(\n\tprimaryKeys: string[],\n\tshardBindings: string[],\n\tstrategy: 'hash' | 'round-robin' | 'random',\n\tmapper: KVShardMapper,\n\toptions: { concurrency?: number } = {}\n): Promise<void> {\n\tif (primaryKeys.length === 0 || shardBindings.length === 0) {\n\t\treturn;\n\t}\n\n\tconst concurrency = Math.max(1, options.concurrency ?? 25);\n\tconst payload = primaryKeys.map((primaryKey, index) => ({\n\t\tprimaryKey,\n\t\tshard: selectShardForKey(primaryKey, index, shardBindings, strategy)\n\t}));\n\n\tawait mapper.setShardMappingsBatch(payload, { concurrency });\n}\n\n/**\n * Represents the result of validating a table for sharding.\n * Contains information about the table structure, primary key, record count,\n * and any issues encountered during validation.\n */\nexport type ValidationResult = {\n\tisValid: boolean;\n\ttableName: string;\n\tprimaryKeyColumn: string;\n\trecordCount: number;\n\tissues: string[];\n};\n\n/**\n * Checks if a table exists and has a primary key column that can be used\n * for sharding. Returns information about the table structure and primary key.\n *\n * @param d1 - The D1 database instance to check\n * @param tableName - Name of the table to validate\n * @param primaryKeyColumn - Expected primary key column name (defaults to 'id')\n * @returns Promise resolving to validation result with table info\n * @throws {Error} If table doesn't exist or validation fails\n * @example\n * ```typescript\n * const validation = await validateTableForSharding(env.DB_EXISTING, 'users');\n * if (validation.isValid) {\n * console.log(`Table ${validation.tableName} is ready for sharding`);\n * console.log(`Primary key: ${validation.primaryKeyColumn}`);\n * console.log(`Record count: ${validation.recordCount}`);\n * } else {\n * console.error('Table validation failed:', validation.issues);\n * }\n * ```\n */\nexport async function validateTableForSharding(d1: SQLDatabase, tableName: string, primaryKeyColumn: string): Promise<ValidationResult> {\n\tconst issues: string[] = [];\n\tlet recordCount = 0;\n\n\ttry {\n\t\t// Check if table exists\n\t\tconst tableCheck = await d1.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name=?`).bind(tableName).first();\n\n\t\tif (!tableCheck) {\n\t\t\tissues.push(`Table '${tableName}' does not exist`);\n\t\t\treturn {\n\t\t\t\tisValid: false,\n\t\t\t\ttableName,\n\t\t\t\tprimaryKeyColumn,\n\t\t\t\trecordCount: 0,\n\t\t\t\tissues\n\t\t\t} satisfies ValidationResult;\n\t\t}\n\n\t\t// Check if primary key column exists\n\t\tconst columnCheck = await d1.prepare(`PRAGMA table_info(${tableName})`).all();\n\t\tconst hasIdColumn = columnCheck.results.some((col: any) => col.name === primaryKeyColumn && col.pk === 1);\n\n\t\tif (!hasIdColumn) {\n\t\t\tissues.push(`Primary key column '${primaryKeyColumn}' not found or not set as primary key`);\n\t\t}\n\n\t\t// Get record count\n\t\tconst countResult = await d1.prepare(`SELECT COUNT(*) as count FROM ${tableName}`).first();\n\t\trecordCount = (countResult as any)?.count || 0;\n\n\t\tif (recordCount === 0) {\n\t\t\tissues.push(`Table '${tableName}' is empty`);\n\t\t}\n\t} catch (error) {\n\t\tissues.push(`Database validation error: ${error}`);\n\t}\n\n\treturn {\n\t\tisValid: issues.length === 0,\n\t\ttableName,\n\t\tprimaryKeyColumn,\n\t\trecordCount,\n\t\tissues\n\t} satisfies ValidationResult;\n}\n\n/**\n * Configuration options for integrating an existing database with CollegeDB.\n * Allows customization of which tables to process, primary key column,\n * sharding strategy, and whether to add the shard_mappings table.\n */\nexport type IntegrationOptions = {\n\ttables?: string[];\n\tprimaryKeyColumn?: string;\n\tstrategy?: ShardingStrategy;\n\taddShardMappingsTable?: boolean;\n\tdryRun?: boolean;\n\tmigrateOtherColumns?: boolean;\n\tconcurrency?: number;\n};\n\n/**\n * Represents the result of integrating an existing database with CollegeDB.\n * Contains information about the success of the integration, shard name,\n * number of tables processed, total records integrated, mappings created,\n * and any issues encountered during the process.\n */\nexport type IntegrationResult = {\n\tsuccess: boolean;\n\tshardName: string;\n\ttablesProcessed: number;\n\ttotalRecords: number;\n\tmappingsCreated: number;\n\tissues: string[];\n};\n\n/**\n * Performs a complete drop-in integration of an existing database.\n * This is the main function for integrating CollegeDB with an existing database\n * that already contains data. It discovers tables, validates them, creates shard\n * mappings, and optionally adds the shard_mappings table if needed.\n *\n * When `migrateOtherColumns` is enabled, the function will also create additional\n * lookup keys for username, email, and name columns if they exist in the table.\n * This allows these fields to be used as lookup keys in addition to the primary key.\n *\n * @param d1 - The existing D1 database to integrate\n * @param shardName - The shard binding name for this database\n * @param mapper - KVShardMapper instance for storing mappings\n * @param options - Configuration options for the integration\n * @param options.migrateOtherColumns - When true, creates additional lookup keys for username, email, and name columns\n * @returns Promise resolving to integration summary\n * @throws {Error} If integration fails\n * @example\n * ```typescript\n * import { KVShardMapper } from './kvmap';\n *\n * const mapper = new KVShardMapper(env.KV);\n * const result = await integrateExistingDatabase(env.DB_EXISTING, 'db-existing', mapper, {\n * tables: ['users', 'posts'],\n * strategy: 'hash',\n * addShardMappingsTable: true,\n * migrateOtherColumns: true // Creates additional lookup keys\n * });\n *\n * console.log(`Integrated ${result.totalRecords} records from ${result.tablesProcessed} tables`);\n * // Now users can be looked up by username:john, email:john@example.com, or name:John Doe\n * ```\n */\nexport async function integrateExistingDatabase(\n\td1: SQLDatabase,\n\tshardName: string,\n\tmapper: KVShardMapper,\n\toptions: IntegrationOptions = {}\n): Promise<IntegrationResult> {\n\tconst {\n\t\ttables,\n\t\tprimaryKeyColumn = 'id',\n\t\tstrategy = 'hash',\n\t\taddShardMappingsTable = true,\n\t\tdryRun = false,\n\t\tmigrateOtherColumns = false,\n\t\tconcurrency = 25\n\t} = options;\n\n\tconst normalizedConcurrency = Math.max(1, concurrency);\n\n\tconst issues: string[] = [];\n\tlet tablesProcessed = 0;\n\tlet totalRecords = 0;\n\tlet mappingsCreated = 0;\n\n\ttry {\n\t\t// Discover tables if not specified\n\t\tconst tablesToProcess = tables || (await listTables(d1));\n\n\t\t// Filter out the shard_mappings table if it already exists\n\t\tconst dataTableNames = tablesToProcess.filter((table) => table !== 'shard_mappings');\n\n\t\tfor (const tableName of dataTableNames) {\n\t\t\ttry {\n\t\t\t\t// Validate table\n\t\t\t\tconst validation = await validateTableForSharding(d1, tableName, primaryKeyColumn);\n\n\t\t\t\tif (!validation.isValid) {\n\t\t\t\t\tissues.push(`Table ${tableName}: ${validation.issues.join(', ')}`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (migrateOtherColumns) {\n\t\t\t\t\t// Use the new function to get records with additional columns\n\t\t\t\t\tconst records = await discoverExistingRecordsWithColumns(d1, tableName, primaryKeyColumn);\n\t\t\t\t\tif (records.length === 0) {\n\t\t\t\t\t\tissues.push(`Table ${tableName} has no records to process`);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!dryRun) {\n\t\t\t\t\t\tconst payload = records.map((record) => {\n\t\t\t\t\t\t\tconst primaryKey = String(record[primaryKeyColumn]);\n\t\t\t\t\t\t\tconst additionalKeys: string[] = [];\n\n\t\t\t\t\t\t\tif (record.username && typeof record.username === 'string') {\n\t\t\t\t\t\t\t\tadditionalKeys.push(`username:${record.username}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (record.email && typeof record.email === 'string') {\n\t\t\t\t\t\t\t\tadditionalKeys.push(`email:${record.email}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (record.name && typeof record.name === 'string') {\n\t\t\t\t\t\t\t\tadditionalKeys.push(`name:${record.name}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tprimaryKey,\n\t\t\t\t\t\t\t\tshard: shardName,\n\t\t\t\t\t\t\t\tadditionalKeys\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tawait mapper.setShardMappingsBatch(payload, { concurrency: normalizedConcurrency });\n\t\t\t\t\t\tmappingsCreated += payload.length;\n\t\t\t\t\t}\n\n\t\t\t\t\ttotalRecords += records.length;\n\t\t\t\t} else {\n\t\t\t\t\t// Original behavior: only use primary keys\n\t\t\t\t\tconst primaryKeys = await discoverExistingPrimaryKeys(d1, tableName, primaryKeyColumn);\n\t\t\t\t\tif (primaryKeys.length === 0) {\n\t\t\t\t\t\tissues.push(`Table ${tableName} has no records to process`);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!dryRun) {\n\t\t\t\t\t\tconst payload = primaryKeys.map((primaryKey) => ({\n\t\t\t\t\t\t\tprimaryKey,\n\t\t\t\t\t\t\tshard: shardName\n\t\t\t\t\t\t}));\n\t\t\t\t\t\tawait mapper.setShardMappingsBatch(payload, { concurrency: normalizedConcurrency });\n\t\t\t\t\t\tmappingsCreated += payload.length;\n\t\t\t\t\t}\n\n\t\t\t\t\ttotalRecords += primaryKeys.length;\n\t\t\t\t}\n\n\t\t\t\ttablesProcessed++;\n\t\t\t} catch (error) {\n\t\t\t\tissues.push(`Failed to process table ${tableName}: ${error}`);\n\t\t\t}\n\t\t}\n\n\t\tif (addShardMappingsTable && !dryRun) {\n\t\t\tconst hasMappingsTable = (await listTables(d1)).includes('shard_mappings');\n\t\t\tif (!hasMappingsTable) {\n\t\t\t\tawait d1\n\t\t\t\t\t.prepare(\n\t\t\t\t\t\t`\n\t\t\t\t\tCREATE TABLE IF NOT EXISTS shard_mappings (\n\t\t\t\t\t\tprimary_key TEXT PRIMARY KEY,\n\t\t\t\t\t\tshard_name TEXT NOT NULL,\n\t\t\t\t\t\tcreated_at INTEGER NOT NULL,\n\t\t\t\t\t\tupdated_at INTEGER NOT NULL\n\t\t\t\t\t);`.trim()\n\t\t\t\t\t)\n\t\t\t\t\t.run();\n\t\t\t}\n\t\t}\n\n\t\t// Add this shard to known shards list\n\t\tif (!dryRun) {\n\t\t\tawait mapper.addKnownShard(shardName);\n\t\t}\n\t} catch (error) {\n\t\tissues.push(`Integration failed: ${error}`);\n\t}\n\n\treturn {\n\t\tsuccess: issues.length === 0 || (issues.length > 0 && tablesProcessed > 0),\n\t\tshardName,\n\t\ttablesProcessed,\n\t\ttotalRecords,\n\t\tmappingsCreated,\n\t\tissues\n\t};\n}\n\n/**\n * Automatically detects if a database needs migration and performs it\n *\n * This function is called automatically by CollegeDB operations to detect\n * existing databases that contain data but haven't been integrated into the\n * sharding system. It performs seamless migration without user intervention.\n *\n * The detection process:\n * 1. Checks if the database has data tables with primary keys\n * 2. Verifies if primary key mappings exist in KV\n * 3. If unmapped data is found, performs automatic integration\n * 4. Caches results to avoid repeated checks\n *\n * When `migrateOtherColumns` is enabled, additional lookup keys will be created\n * for username, email, and name columns if they exist in the tables.\n *\n * @param d1 - The D1 database instance to check and potentially migrate\n * @param shardName - The shard binding name for this database\n * @param config - CollegeDB configuration containing KV and strategy\n * @param options - Optional migration configuration\n * @param options.migrateOtherColumns - When true, creates additional lookup keys for username, email, and name columns\n * @returns Promise resolving to migration result summary\n * @example\n * ```typescript\n * // Called automatically by CollegeDB operations\n * const result = await autoDetectAndMigrate(env.DB_EXISTING, 'db-existing', config, {\n * migrateOtherColumns: true\n * });\n * if (result.migrationPerformed) {\n * console.log(`Auto-migrated ${result.recordsMigrated} records`);\n * }\n * ```\n */\nexport async function autoDetectAndMigrate(\n\td1: SQLDatabase,\n\tshardName: string,\n\tconfig: CollegeDBConfig,\n\toptions: {\n\t\tprimaryKeyColumn?: string;\n\t\ttablesToCheck?: string[];\n\t\tskipCache?: boolean;\n\t\tmaxRecordsToCheck?: number;\n\t\tmigrateOtherColumns?: boolean;\n\t\tconcurrency?: number;\n\t} = {}\n): Promise<{\n\tmigrationNeeded: boolean;\n\tmigrationPerformed: boolean;\n\trecordsMigrated: number;\n\ttablesProcessed: number;\n\tissues: string[];\n}> {\n\tconst {\n\t\tprimaryKeyColumn = 'id',\n\t\ttablesToCheck,\n\t\tskipCache = false,\n\t\tmaxRecordsToCheck = 1000,\n\t\tmigrateOtherColumns = false,\n\t\tconcurrency = config.migrationConcurrency ?? 25\n\t} = options;\n\n\tconst normalizedConcurrency = Math.max(1, concurrency);\n\n\tconst cacheKey = `${shardName}_migration_check`;\n\n\t// Check cache to avoid repeated migration checks\n\tif (!skipCache && migrationStatusCache.has(cacheKey)) {\n\t\treturn {\n\t\t\tmigrationNeeded: false,\n\t\t\tmigrationPerformed: false,\n\t\t\trecordsMigrated: 0,\n\t\t\ttablesProcessed: 0,\n\t\t\tissues: []\n\t\t};\n\t}\n\n\tconst issues: string[] = [];\n\tlet recordsMigrated = 0;\n\tlet tablesProcessed = 0;\n\tlet migrationNeeded = false;\n\tlet migrationPerformed = false;\n\n\ttry {\n\t\tconst { KVShardMapper } = await import('./kvmap');\n\t\tconst mapper = new KVShardMapper(config.kv, {\n\t\t\thashShardMappings: config.hashShardMappings,\n\t\t\tmappingCacheTtlMs: config.mappingCacheTtlMs,\n\t\t\tknownShardsCacheTtlMs: config.knownShardsCacheTtlMs\n\t\t});\n\n\t\t// Discover tables to check\n\t\tconst allTables = await listTables(d1);\n\t\tconst dataTableNames =\n\t\t\ttablesToCheck ||\n\t\t\tallTables.filter((table) => table !== 'shard_mappings' && !table.startsWith('sqlite_') && table !== 'sqlite_sequence');\n\n\t\tif (dataTableNames.length === 0) {\n\t\t\t// No data tables found, mark as migrated\n\t\t\tmigrationStatusCache.set(cacheKey, true);\n\t\t\treturn {\n\t\t\t\tmigrationNeeded: false,\n\t\t\t\tmigrationPerformed: false,\n\t\t\t\trecordsMigrated: 0,\n\t\t\t\ttablesProcessed: 0,\n\t\t\t\tissues: []\n\t\t\t};\n\t\t}\n\n\t\t// Check each table for unmapped data\n\t\tfor (const tableName of dataTableNames) {\n\t\t\ttry {\n\t\t\t\t// Quick validation\n\t\t\t\tconst validation = await validateTableForSharding(d1, tableName, primaryKeyColumn);\n\t\t\t\tif (!validation.isValid || validation.recordCount === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Sample some primary keys to check if they're mapped\n\t\t\t\tconst sampleSize = Math.min(maxRecordsToCheck, validation.recordCount);\n\t\t\t\tconst sampleKeys = await d1\n\t\t\t\t\t.prepare(\n\t\t\t\t\t\t`\n\t\t\t\t\tSELECT ${primaryKeyColumn} FROM ${tableName}\n\t\t\t\t\tORDER BY ${primaryKeyColumn}\n\t\t\t\t\tLIMIT ?`.trim()\n\t\t\t\t\t)\n\t\t\t\t\t.bind(sampleSize)\n\t\t\t\t\t.all();\n\n\t\t\t\tlet unmappedCount = 0;\n\t\t\t\tconst keysToCheck = sampleKeys.results.slice(0, 10); // Check first 10 as sample\n\n\t\t\t\t// OPTIMIZATION: Batch check multiple keys instead of one-by-one\n\t\t\t\tconst keyCheckPromises = keysToCheck.map(async (row) => {\n\t\t\t\t\tconst primaryKey = String((row as any)[primaryKeyColumn]);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkey: primaryKey,\n\t\t\t\t\t\tmapping: await mapper.getShardMapping(primaryKey)\n\t\t\t\t\t};\n\t\t\t\t});\n\n\t\t\t\tconst keyResults = await Promise.all(keyCheckPromises);\n\n\t\t\t\tfor (const result of keyResults) {\n\t\t\t\t\tif (!result.mapping) {\n\t\t\t\t\t\tunmappedCount++;\n\t\t\t\t\t\tmigrationNeeded = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (unmappedCount > 0) {\n\t\t\t\t\tif (config.debug) console.log(`Auto-migrating table ${tableName} in shard ${shardName} (${validation.recordCount} records)`);\n\n\t\t\t\t\tif (migrateOtherColumns) {\n\t\t\t\t\t\t// Use multi-column discovery for migration with additional lookup keys\n\t\t\t\t\t\tconst allRecords = await discoverExistingRecordsWithColumns(d1, tableName, primaryKeyColumn);\n\n\t\t\t\t\t\tconst payload: Array<{ primaryKey: string; shard: string; additionalKeys: string[] }> = [];\n\t\t\t\t\t\tawait mapWithConcurrency(allRecords, normalizedConcurrency, async (record) => {\n\t\t\t\t\t\t\tconst primaryKey = String(record[primaryKeyColumn]);\n\t\t\t\t\t\t\tconst existingMapping = await mapper.getShardMapping(primaryKey);\n\t\t\t\t\t\t\tif (existingMapping) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst additionalKeys: string[] = [];\n\t\t\t\t\t\t\tif (record.username && typeof record.username === 'string') {\n\t\t\t\t\t\t\t\tadditionalKeys.push(`username:${record.username}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (record.email && typeof record.email === 'string') {\n\t\t\t\t\t\t\t\tadditionalKeys.push(`email:${record.email}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (record.name && typeof record.name === 'string') {\n\t\t\t\t\t\t\t\tadditionalKeys.push(`name:${record.name}`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tpayload.push({\n\t\t\t\t\t\t\t\tprimaryKey,\n\t\t\t\t\t\t\t\tshard: shardName,\n\t\t\t\t\t\t\t\tadditionalKeys\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (payload.length > 0) {\n\t\t\t\t\t\t\tawait mapper.setShardMappingsBatch(payload, { concurrency: normalizedConcurrency });\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\trecordsMigrated += payload.length;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Original behavior: only use primary keys\n\t\t\t\t\t\tconst allPrimaryKeys = await discoverExistingPrimaryKeys(d1, tableName, primaryKeyColumn);\n\n\t\t\t\t\t\tconst payload: Array<{ primaryKey: string; shard: string }> = [];\n\t\t\t\t\t\tawait mapWithConcurrency(allPrimaryKeys, normalizedConcurrency, async (primaryKey) => {\n\t\t\t\t\t\t\tconst existingMapping = await mapper.getShardMapping(primaryKey);\n\t\t\t\t\t\t\tif (!existingMapping) {\n\t\t\t\t\t\t\t\tpayload.push({ primaryKey, shard: shardName });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (payload.length > 0) {\n\t\t\t\t\t\t\tawait mapper.setShardMappingsBatch(payload, { concurrency: normalizedConcurrency });\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\trecordsMigrated += payload.length;\n\t\t\t\t\t}\n\n\t\t\t\t\ttablesProcessed++;\n\t\t\t\t\tmigrationPerformed = true;\n\n\t\t\t\t\tif (config.debug) console.log(`Auto-migrated ${recordsMigrated} records from table ${tableName}`);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tissues.push(`Auto-migration failed for table ${tableName}: ${error}`);\n\t\t\t}\n\t\t}\n\n\t\t// Add shard to known shards if migration was performed\n\t\tif (migrationPerformed) {\n\t\t\tawait mapper.addKnownShard(shardName);\n\n\t\t\t// Add shard_mappings table if it doesn't exist\n\t\t\tconst hasMappingsTable = allTables.includes('shard_mappings');\n\t\t\tif (!hasMappingsTable) {\n\t\t\t\tawait d1\n\t\t\t\t\t.prepare(\n\t\t\t\t\t\t`CREATE TABLE IF NOT EXISTS shard_mappings (\n\t\t\t\t\t\tprimary_key TEXT PRIMARY KEY,\n\t\t\t\t\t\tshard_name TEXT NOT NULL,\n\t\t\t\t\t\tcreated_at INTEGER NOT NULL,\n\t\t\t\t\t\tupdated_at INTEGER NOT NULL\n\t\t\t\t\t);\n\t\t\t\t`\n\t\t\t\t\t)\n\t\t\t\t\t.run();\n\t\t\t}\n\t\t}\n\n\t\t// Cache the result to avoid repeated checks\n\t\tmigrationStatusCache.set(cacheKey, true);\n\n\t\tif (migrationPerformed && config.debug) {\n\t\t\tconsole.log(`Auto-migration completed for shard ${shardName}: ${recordsMigrated} records from ${tablesProcessed} tables`);\n\t\t}\n\t} catch (error) {\n\t\tissues.push(`Auto-migration error: ${error}`);\n\t}\n\n\treturn {\n\t\tmigrationNeeded,\n\t\tmigrationPerformed,\n\t\trecordsMigrated,\n\t\ttablesProcessed,\n\t\tissues\n\t};\n}\n\n/**\n * Performs a lightweight check to determine if a database contains\n * existing data that hasn't been mapped to the sharding system.\n * This is used internally to trigger automatic migration.\n *\n * @param d1 - The D1 database instance to check\n * @param shardName - The shard binding name\n * @param config - CollegeDB configuration\n * @returns Promise resolving to true if migration is needed\n * @example\n * ```typescript\n * const needsMigration = await checkMigrationNeeded(env.DB, 'db-main', config);\n * if (needsMigration) {\n * console.log('Database contains unmapped data');\n * }\n * ```\n */\nexport async function checkMigrationNeeded(d1: SQLDatabase, shardName: string, config: CollegeDBConfig): Promise<boolean> {\n\tconst cacheKey = `${shardName}_migration_check`;\n\n\t// Check cache first (but not during tests with skip cache)\n\tif (migrationStatusCache.has(cacheKey)) {\n\t\treturn false; // Already checked/migrated\n\t}\n\n\ttry {\n\t\t// Check if shard_mappings table exists as indicator of previous migration\n\t\tconst tables = await listTables(d1);\n\t\tconst hasShardMappingsTable = tables.includes('shard_mappings');\n\n\t\tif (hasShardMappingsTable) {\n\t\t\t// If shard_mappings table exists, this database has been processed before\n\t\t\tmigrationStatusCache.set(cacheKey, true);\n\t\t\treturn false;\n\t\t}\n\n\t\tconst { KVShardMapper } = await import('./kvmap');\n\t\tconst mapper = new KVShardMapper(config.kv, {\n\t\t\thashShardMappings: config.hashShardMappings,\n\t\t\tmappingCacheTtlMs: config.mappingCacheTtlMs,\n\t\t\tknownShardsCacheTtlMs: config.knownShardsCacheTtlMs\n\t\t});\n\n\t\t// Quick check: look for any table with data\n\t\tconst dataTableNames = tables.filter(\n\t\t\t(table) => table !== 'shard_mappings' && !table.startsWith('sqlite_') && table !== 'sqlite_sequence'\n\t\t);\n\n\t\tfor (const tableName of dataTableNames.slice(0, 3)) {\n\t\t\t// Check first 3 tables only\n\t\t\ttry {\n\t\t\t\t// Check if table has records\n\t\t\t\tconst countResult = await d1.prepare(`SELECT COUNT(*) as count FROM ${tableName} LIMIT 1`).first();\n\t\t\t\tconst recordCount = (countResult as any)?.count || 0;\n\n\t\t\t\tif (recordCount > 0) {\n\t\t\t\t\t// Sample one record to see if it's mapped\n\t\t\t\t\tconst sampleRecord = await d1.prepare(`SELECT id FROM ${tableName} LIMIT 1`).first();\n\t\t\t\t\tif (sampleRecord) {\n\t\t\t\t\t\tconst primaryKey = String((sampleRecord as any).id);\n\t\t\t\t\t\tconst mapping = await mapper.getShardMapping(primaryKey);\n\t\t\t\t\t\tif (!mapping) {\n\t\t\t\t\t\t\treturn true; // Found unmapped data\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Skip tables that don't have 'id' column or have other issues\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t} catch {\n\t\treturn false; // Assume no migration needed if check fails\n\t}\n}\n\n/**\n * Clears the migration status cache\n *\n * Resets the internal cache used to track which databases have been\n * checked for migration. Useful for testing or forcing re-checks.\n *\n * @example\n * ```typescript\n * // Force re-check of all databases\n * clearMigrationCache();\n * ```\n */\nexport function clearMigrationCache(): void {\n\tmigrationStatusCache.clear();\n}\n\n/**\n * Clears a specific migration cache entry\n *\n * Resets the cache for a specific shard, forcing re-check on next\n * migration detection call.\n *\n * @param shardName - The shard name to clear from cache\n * @example\n * ```typescript\n * // Force re-check of specific shard\n * clearShardMigrationCache('db-auto');\n * ```\n */\nexport function clearShardMigrationCache(shardName: string): void {\n\tconst cacheKey = `${shardName}_migration_check`;\n\tmigrationStatusCache.delete(cacheKey);\n}\n",
8
- "/**\n * @fileoverview Main routing and query distribution logic for CollegeDB\n *\n * This module provides the core functionality for routing database queries to the\n * appropriate D1 shard based on primary key mappings. It handles shard selection,\n * database routing, and provides a unified API for CRUD operations across multiple\n * distributed D1 databases.\n *\n * Key responsibilities:\n * - Initialize and manage the global CollegeDB configuration\n * - Route queries to appropriate shards based on primary key mappings\n * - Implement shard allocation strategies (round-robin, random, hash-based)\n * - Provide unified CRUD operations across distributed shards\n * - Coordinate with Durable Objects for centralized shard management\n * - Handle shard rebalancing and data migration\n *\n * @example\n * ```typescript\n * import { initialize, insert, first, run } from 'collegedb';\n *\n * // Initialize the system\n * initialize({\n * kv: env.KV,\n * coordinator: env.ShardCoordinator,\n * shards: {\n * 'db-east': env.DB_EAST,\n * 'db-west': env.DB_WEST\n * },\n * strategy: 'hash'\n * });\n *\n * // Insert a record (automatically routed to appropriate shard)\n * await run('user-123', 'INSERT INTO users (id, name) VALUES (?, ?)', ['user-123', 'John']);\n *\n * // Query the record (routed to same shard)\n * const result = await first('user-123', 'SELECT * FROM users WHERE id = ?', ['user-123']);\n * ```\n *\n * @author CollegeDB Team\n * @since 1.0.0\n */\n\nimport type { Request } from '@cloudflare/workers-types';\nimport { CollegeDBError } from './errors';\nimport { KVShardMapper } from './kvmap';\nimport type {\n\tCollegeDBConfig,\n\tD1Region,\n\tOperationType,\n\tPreparedStatement,\n\tQueryResult,\n\tSQLDatabase,\n\tShardLocation,\n\tShardStats,\n\tShardingStrategy\n} from './types';\n\n/**\n * Global configuration for the collegedb instance\n *\n * Stores the system-wide configuration including KV namespace, available shards,\n * coordinator settings, and allocation strategy. Must be initialized before\n * any routing operations can be performed.\n *\n * @private\n */\nlet globalConfig: CollegeDBConfig | null = null;\n\n/**\n * Shared mapper instance for the active configuration.\n *\n * Reusing a single mapper preserves in-memory caches and avoids repeated\n * constructor/setup overhead on each operation.\n *\n * @private\n */\nlet globalMapper: KVShardMapper | null = null;\n\n/**\n * In-memory cache for per-shard size checks.\n * @private\n */\nconst shardSizeCache = new Map<string, { size: number; expiresAt: number }>();\n\n/**\n * Gets the shared mapper for the active configuration.\n * @private\n */\nfunction getMapper(config: CollegeDBConfig): KVShardMapper {\n\tif (!globalMapper) {\n\t\tglobalMapper = new KVShardMapper(config.kv, {\n\t\t\thashShardMappings: config.hashShardMappings,\n\t\t\tmappingCacheTtlMs: config.mappingCacheTtlMs,\n\t\t\tknownShardsCacheTtlMs: config.knownShardsCacheTtlMs\n\t\t});\n\t}\n\n\treturn globalMapper;\n}\n\n/**\n * Sets up the global configuration for the CollegeDB system. This must be called\n * before any other operations can be performed. The configuration includes KV\n * storage, available D1 shards, optional coordinator, and allocation strategy.\n *\n * This will also automatically detect and migrate existing databases without requiring\n * additional setup. If shards contain existing data with primary keys, CollegeDB\n * will automatically create the necessary mappings for seamless operation.\n *\n * @param config - Configuration object containing all necessary bindings and settings\n * @throws {Error} If configuration is invalid or required bindings are missing\n * @example\n * ```typescript\n * // Basic setup with multiple shards - auto-migration happens automatically\n * initialize({\n * kv: env.KV,\n * shards: {\n * 'db-primary': env.DB_PRIMARY, // Existing DB with data\n * 'db-secondary': env.DB_SECONDARY // Another existing DB\n * },\n * strategy: 'round-robin'\n * });\n * // Existing data is now automatically accessible via CollegeDB!\n *\n * // Advanced setup with coordinator\n * initialize({\n * kv: env.KV,\n * coordinator: env.ShardCoordinator,\n * shards: {\n * 'db-east': env.DB_EAST,\n * 'db-west': env.DB_WEST,\n * 'db-central': env.DB_CENTRAL\n * },\n * strategy: 'hash'\n * });\n * ```\n */\nexport function initialize(config: CollegeDBConfig) {\n\tglobalConfig = config;\n\tglobalMapper = new KVShardMapper(config.kv, {\n\t\thashShardMappings: config.hashShardMappings,\n\t\tmappingCacheTtlMs: config.mappingCacheTtlMs,\n\t\tknownShardsCacheTtlMs: config.knownShardsCacheTtlMs\n\t});\n\tshardSizeCache.clear();\n\n\t// Background: sync KV known shards with configured shards\n\ttry {\n\t\tconst mapper = getMapper(config);\n\t\tPromise.resolve()\n\t\t\t.then(async () => {\n\t\t\t\tconst existing = await mapper.getKnownShards();\n\t\t\t\tconst merged = Array.from(new Set([...existing, ...Object.keys(config.shards)]));\n\t\t\t\tawait mapper.setKnownShards(merged);\n\t\t\t})\n\t\t\t.catch(() => void 0);\n\t} catch {}\n\n\tif (config.shards && Object.keys(config.shards).length > 0 && !config.disableAutoMigration) {\n\t\tperformAutoMigration(config).catch((error) => {\n\t\t\tconsole.warn('Background auto-migration failed:', error);\n\t\t});\n\t}\n}\n\n/**\n * Sets up the global configuration for the CollegeDB system asynchronously.\n * This must be called before any other operations can be performed. The\n * configuration includes KVstorage, available D1 shards, optional coordinator,\n * and allocation strategy.\n *\n * This will also automatically detect and migrate existing databases without requiring\n * additional setup. If shards contain existing data with primary keys, CollegeDB\n * will automatically create the necessary mappings for seamless operation.\n *\n * Compared to `initialize`, this method waits for the background check to finish.\n *\n * @param config - Configuration object containing all necessary bindings and settings\n * @throws {Error} If configuration is invalid or required bindings are missing\n * @example\n * ```typescript\n * // Basic setup with multiple shards - auto-migration happens automatically\n * initializeAsync({\n * kv: env.KV,\n * shards: {\n * 'db-primary': env.DB_PRIMARY, // Existing DB with data\n * 'db-secondary': env.DB_SECONDARY // Another existing DB\n * },\n * strategy: 'round-robin'\n * });\n * // Existing data is now automatically accessible via CollegeDB!\n *\n * // Advanced setup with coordinator\n * initializeAsync({\n * kv: env.KV,\n * coordinator: env.ShardCoordinator,\n * shards: {\n * 'db-east': env.DB_EAST,\n * 'db-west': env.DB_WEST,\n * 'db-central': env.DB_CENTRAL\n * },\n * strategy: 'hash'\n * });\n * ```\n */\nexport async function initializeAsync(config: CollegeDBConfig) {\n\tglobalConfig = config;\n\tglobalMapper = new KVShardMapper(config.kv, {\n\t\thashShardMappings: config.hashShardMappings,\n\t\tmappingCacheTtlMs: config.mappingCacheTtlMs,\n\t\tknownShardsCacheTtlMs: config.knownShardsCacheTtlMs\n\t});\n\tshardSizeCache.clear();\n\n\t// Sync KV known shards with configured shards (awaited in async init)\n\ttry {\n\t\tconst mapper = getMapper(config);\n\t\tconst existing = await mapper.getKnownShards();\n\t\tconst merged = Array.from(new Set([...existing, ...Object.keys(config.shards)]));\n\t\tawait mapper.setKnownShards(merged);\n\t} catch {}\n\n\tif (config.shards && Object.keys(config.shards).length > 0 && !config.disableAutoMigration)\n\t\ttry {\n\t\t\tawait performAutoMigration(config);\n\t\t} catch (error) {\n\t\t\tconsole.warn('Auto migration failed:', error);\n\t\t}\n}\n\n/**\n * Initializes the configuration and then performs a callback once the configuration\n * has finished initializing.\n *\n * @param config - CollegeDB Configuration\n * @param callback - The callback to perform after the initialization\n * @returns The result of the callback\n * @example\n * ```\n * import { collegedb, first } from 'collegedb'\n *\n * const result = collegedb({\n * kv: env.KV,\n * shards: {\n * 'db-primary': env.DB_PRIMARY, // Existing DB with data\n * 'db-secondary': env.DB_SECONDARY // Another existing DB\n * },\n * strategy: 'hash'\n * }, async () => {\n * return await first('user-123', 'SELECT * FROM users WHERE id = ?', ['user-123']);\n * });\n * ```\n */\nexport async function collegedb<T>(config: CollegeDBConfig, callback: () => T) {\n\tawait initializeAsync(config);\n\treturn await callback();\n}\n\n/**\n * Performs automatic migration detection for all shards in the background\n *\n * This function runs asynchronously after initialization to check all configured\n * shards for existing data that needs migration. It's designed to be non-blocking\n * and won't interfere with immediate database operations.\n *\n * @private\n * @param config - CollegeDB configuration\n */\nasync function performAutoMigration(config: CollegeDBConfig): Promise<void> {\n\ttry {\n\t\tconst { autoDetectAndMigrate } = await import('./migrations');\n\t\tconst shardNames = Object.keys(config.shards);\n\n\t\tif (config.debug) {\n\t\t\tconsole.log(`🔍 Checking ${shardNames.length} shards for existing data...`);\n\t\t}\n\n\t\t// Check each shard for migration needs\n\t\tconst migrationPromises = shardNames.map(async (shardName) => {\n\t\t\tconst database = config.shards[shardName];\n\t\t\tif (!database) return null;\n\n\t\t\ttry {\n\t\t\t\tconst result = await autoDetectAndMigrate(database, shardName, config, {\n\t\t\t\t\tmaxRecordsToCheck: 1000\n\t\t\t\t});\n\n\t\t\t\treturn {\n\t\t\t\t\tshardName,\n\t\t\t\t\t...result\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(`Auto-migration failed for shard ${shardName}:`, error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t});\n\n\t\tconst results = await Promise.all(migrationPromises);\n\t\tconst successfulMigrations = results.filter((r) => r?.migrationPerformed);\n\n\t\tif (config.debug) {\n\t\t\tif (successfulMigrations.length > 0) {\n\t\t\t\tconst totalRecords = successfulMigrations.reduce((sum, r) => sum + (r?.recordsMigrated || 0), 0);\n\t\t\t\tconsole.log(`🎉 Auto-migration completed! Migrated ${totalRecords} records across ${successfulMigrations.length} shards`);\n\t\t\t\tsuccessfulMigrations.forEach((result) => {\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\tconsole.log(` ✅ ${result.shardName}: ${result.recordsMigrated} records from ${result.tablesProcessed} tables`);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconsole.log('✅ All shards ready - no migration needed');\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tconsole.warn('Background auto-migration setup failed:', error);\n\t}\n}\n\n/**\n * Resets the global configuration (for testing purposes only)\n *\n * @private\n * @internal\n */\nexport function resetConfig(): void {\n\tglobalConfig = null;\n\tglobalMapper = null;\n\tshardSizeCache.clear();\n}\n\n/**\n * Gets the global configuration, throwing an error if not initialized\n *\n * Internal utility function that retrieves the global configuration and\n * ensures the system has been properly initialized before performing\n * any operations.\n *\n * @private\n * @returns The global CollegeDB configuration\n * @throws {Error} If initialize() has not been called yet\n */\nfunction getConfig(): CollegeDBConfig {\n\tif (!globalConfig) {\n\t\tthrow new CollegeDBError('CollegeDB not initialized. Call initialize() first.', 'NOT_INITIALIZED');\n\t}\n\treturn globalConfig;\n}\n\n/**\n * Determines the operation type from a SQL statement\n * @private\n * @param sql - The SQL statement to analyze\n * @returns The operation type ('read' for SELECT, 'write' for INSERT/UPDATE/DELETE)\n */\nfunction getOperationType(sql: string): OperationType {\n\tconst sql0 = sql.trim().toUpperCase();\n\n\tif (\n\t\tsql0.startsWith('SELECT') ||\n\t\tsql0.startsWith('VALUES') ||\n\t\tsql0.startsWith('TABLE') ||\n\t\tsql0.startsWith('PRAGMA') ||\n\t\tsql0.startsWith('EXPLAIN') ||\n\t\tsql0.startsWith('WITH') ||\n\t\tsql0.startsWith('SHOW')\n\t) {\n\t\treturn 'read';\n\t}\n\n\t// All other operations (INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, etc.) are considered writes\n\treturn 'write';\n}\n\n/**\n * Resolves the effective sharding strategy based on configuration and operation type\n * @private\n * @param config - CollegeDB configuration\n * @param type - The type of operation being performed\n * @returns The effective sharding strategy to use\n */\nfunction resolveStrategy(config: CollegeDBConfig, type: OperationType): ShardingStrategy {\n\tconst strategy = config.strategy || 'hash';\n\n\tif (typeof strategy === 'string') {\n\t\treturn strategy;\n\t}\n\n\t// Fallbacks for partially specified mixed strategies\n\tconst mixed = strategy as Partial<Record<OperationType, ShardingStrategy>>;\n\treturn (mixed[type] || mixed.write || mixed.read || 'hash') as ShardingStrategy;\n}\n\n/**\n * Calculates the relative distance between two D1 regions for location-based sharding.\n * Lower values indicate closer regions with better expected latency.\n *\n * @private\n * @param from - Source region\n * @param to - Target region\n * @returns Relative distance score (lower is better)\n */\nfunction calculateRegionDistance(from: D1Region, to: D1Region): number {\n\t// Same region = optimal\n\tif (from === to) return 0;\n\n\t// Define region coordinates (approximate)\n\tconst regionCoords: Record<D1Region, { lat: number; lon: number }> = {\n\t\twnam: { lat: 37.7749, lon: -122.4194 }, // San Francisco\n\t\tenam: { lat: 40.7128, lon: -74.006 }, // New York\n\t\tweur: { lat: 51.5074, lon: -0.1278 }, // London\n\t\teeur: { lat: 52.52, lon: 13.405 }, // Berlin\n\t\tapac: { lat: 35.6762, lon: 139.6503 }, // Tokyo\n\t\toc: { lat: -33.8688, lon: 151.2093 }, // Sydney\n\t\tme: { lat: 25.2048, lon: 55.2708 }, // Dubai\n\t\taf: { lat: -26.2041, lon: 28.0473 } // Johannesburg\n\t};\n\n\tconst fromCoord = regionCoords[from];\n\tconst toCoord = regionCoords[to];\n\n\t// Simple Euclidean distance calculation\n\tconst latDiff = fromCoord.lat - toCoord.lat;\n\tconst lonDiff = fromCoord.lon - toCoord.lon;\n\treturn Math.sqrt(latDiff * latDiff + lonDiff * lonDiff);\n}\n\n/**\n * Determines the closest D1 region based on an IP address.\n * Uses IP geolocation to estimate the user's location and find the nearest D1 region.\n *\n * This function uses Cloudflare's CF object which provides geolocation data\n * in Cloudflare Workers environment. Falls back to 'wnam' if geolocation fails.\n *\n * @param request - The incoming Request object (contains CF geolocation data in Cloudflare Workers)\n * @returns The closest D1Region based on IP geolocation\n * @example\n * ```typescript\n * // In a Cloudflare Worker\n * export default {\n * async fetch(request: Request, env: Env) {\n * const userRegion = getClosestRegionFromIP(request);\n *\n * initialize({\n * kv: env.KV,\n * strategy: 'location',\n * targetRegion: userRegion, // Automatically optimized for user location\n * shardLocations: { ... },\n * shards: { ... }\n * });\n * }\n * };\n * ```\n */\nexport function getClosestRegionFromIP(request: Request): D1Region {\n\tconst cf = request.cf;\n\n\tif (!cf || !cf.country) {\n\t\treturn 'wnam';\n\t}\n\n\tconst country = cf.country as string;\n\tconst continent = cf.continent as string;\n\n\t// Western North America\n\tif (['US', 'CA', 'MX'].includes(country)) {\n\t\t// Further refine by region/state if available\n\t\tconst region = (cf.region || cf.regionCode || '') as string;\n\t\tconst timezone = (cf.timezone || '') as string;\n\n\t\t// West Coast indicators\n\t\tif (\n\t\t\tregion.includes('CA') ||\n\t\t\tregion.includes('WA') ||\n\t\t\tregion.includes('OR') ||\n\t\t\tregion.includes('NV') ||\n\t\t\tregion.includes('AZ') ||\n\t\t\tregion.includes('UT') ||\n\t\t\ttimezone.includes('Pacific') ||\n\t\t\ttimezone.includes('America/Los_Angeles')\n\t\t) {\n\t\t\treturn 'wnam';\n\t\t}\n\n\t\t// East Coast and Central - default to Eastern North America\n\t\treturn 'enam';\n\t}\n\n\t// Eastern North America (broader North America)\n\tif (['GL', 'PM', 'BM'].includes(country)) {\n\t\treturn 'enam';\n\t}\n\n\t// Western Europe\n\tif (['GB', 'IE', 'FR', 'ES', 'PT', 'NL', 'BE', 'LU', 'CH', 'AT', 'IT'].includes(country)) {\n\t\treturn 'weur';\n\t}\n\n\t// Eastern Europe\n\tif (\n\t\t[\n\t\t\t'DE',\n\t\t\t'PL',\n\t\t\t'CZ',\n\t\t\t'SK',\n\t\t\t'HU',\n\t\t\t'SI',\n\t\t\t'HR',\n\t\t\t'BA',\n\t\t\t'RS',\n\t\t\t'ME',\n\t\t\t'MK',\n\t\t\t'AL',\n\t\t\t'BG',\n\t\t\t'RO',\n\t\t\t'MD',\n\t\t\t'UA',\n\t\t\t'BY',\n\t\t\t'LT',\n\t\t\t'LV',\n\t\t\t'EE',\n\t\t\t'FI',\n\t\t\t'SE',\n\t\t\t'NO',\n\t\t\t'DK',\n\t\t\t'IS'\n\t\t].includes(country)\n\t) {\n\t\treturn 'eeur';\n\t}\n\n\t// Russia - closer to Eastern Europe for most population centers\n\tif (country === 'RU') {\n\t\treturn 'eeur';\n\t}\n\n\t// Asia Pacific\n\tif (['JP', 'KR', 'CN', 'HK', 'TW', 'MO', 'MN', 'KP'].includes(country)) {\n\t\treturn 'apac';\n\t}\n\n\t// Southeast Asia and South Asia -> APAC\n\tif (\n\t\t['TH', 'VN', 'SG', 'MY', 'ID', 'PH', 'BN', 'KH', 'LA', 'MM', 'TL', 'IN', 'PK', 'BD', 'LK', 'NP', 'BT', 'MV', 'AF'].includes(country)\n\t) {\n\t\treturn 'apac';\n\t}\n\n\t// Oceania\n\tif (['AU', 'NZ', 'PG', 'FJ', 'NC', 'VU', 'SB', 'WS', 'TO', 'KI', 'NR', 'PW', 'FM', 'MH', 'TV'].includes(country)) {\n\t\treturn 'oc';\n\t}\n\n\t// Middle East\n\tif (['AE', 'SA', 'QA', 'KW', 'BH', 'OM', 'YE', 'IQ', 'IR', 'SY', 'LB', 'JO', 'IL', 'PS', 'TR', 'CY'].includes(country)) {\n\t\treturn 'me';\n\t}\n\n\t// Africa\n\tif (continent === 'AF' || ['EG', 'LY', 'TN', 'DZ', 'MA', 'SD', 'SS', 'ET', 'ER', 'DJ', 'SO'].includes(country)) {\n\t\treturn 'af';\n\t}\n\n\t// Central Asia -> closer to Eastern Europe\n\tif (['KZ', 'UZ', 'TM', 'TJ', 'KG'].includes(country)) {\n\t\treturn 'eeur';\n\t}\n\n\t// South America -> geographically closer to Eastern North America\n\tif (continent === 'SA' || ['BR', 'AR', 'CL', 'PE', 'CO', 'VE', 'EC', 'BO', 'PY', 'UY', 'GY', 'SR', 'GF'].includes(country)) {\n\t\treturn 'enam';\n\t}\n\n\t// Central America and Caribbean -> Eastern North America\n\tif (\n\t\t['GT', 'BZ', 'SV', 'HN', 'NI', 'CR', 'PA', 'CU', 'JM', 'HT', 'DO', 'PR', 'TT', 'BB', 'GD', 'VC', 'LC', 'DM', 'AG', 'KN'].includes(\n\t\t\tcountry\n\t\t)\n\t) {\n\t\treturn 'enam';\n\t}\n\n\t// Default fallback - Western North America (major Cloudflare hub)\n\treturn 'wnam';\n}\n\nfunction parseRegion(location: ShardLocation | D1Region): D1Region {\n\tif (typeof location === 'string') {\n\t\treturn location;\n\t}\n\n\treturn location.region || 'wnam';\n}\n\n/**\n * Gets the approximate size of a D1 database in bytes using an efficient SQL query.\n * Uses SQLite's page_count and page_size pragmas for accurate size calculation.\n *\n * @private\n * @param database - The SQL database instance to measure\n * @returns Promise resolving to the database size in bytes\n * @throws {CollegeDBError} If the size query fails\n */\nasync function getDatabaseSize(database: SQLDatabase): Promise<number> {\n\ttry {\n\t\t// Get page count and page size efficiently\n\t\tconst [pageCountResult, pageSizeResult] = await Promise.all([\n\t\t\tdatabase.prepare('PRAGMA page_count').first<{ page_count: number }>(),\n\t\t\tdatabase.prepare('PRAGMA page_size').first<{ page_size: number }>()\n\t\t]);\n\n\t\tif (!pageCountResult?.page_count || !pageSizeResult?.page_size) {\n\t\t\tthrow new CollegeDBError('Failed to retrieve database size information', 'SIZE_QUERY_FAILED');\n\t\t}\n\n\t\treturn pageCountResult.page_count * pageSizeResult.page_size;\n\t} catch (error) {\n\t\tthrow new CollegeDBError(\n\t\t\t`Failed to get database size: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t\t'SIZE_QUERY_FAILED'\n\t\t);\n\t}\n}\n\n/**\n * Retrieves a shard size using a short-lived in-memory cache.\n * @private\n */\nasync function getDatabaseSizeForAllocation(shardName: string, config: CollegeDBConfig): Promise<number> {\n\tconst cacheTtlMs = Math.max(0, config.sizeCacheTtlMs ?? 30_000);\n\tconst cached = shardSizeCache.get(shardName);\n\n\tif (cached && cached.expiresAt >= Date.now()) {\n\t\treturn cached.size;\n\t}\n\n\tconst database = config.shards[shardName];\n\tif (!database) {\n\t\tthrow new CollegeDBError(`Shard ${shardName} not found in configuration`, 'SHARD_NOT_FOUND');\n\t}\n\n\tconst size = await getDatabaseSize(database);\n\tif (cacheTtlMs > 0) {\n\t\tshardSizeCache.set(shardName, {\n\t\t\tsize,\n\t\t\texpiresAt: Date.now() + cacheTtlMs\n\t\t});\n\t}\n\n\treturn size;\n}\n\n/**\n * Filters available shards to exclude those that exceed the configured maximum size.\n * This is used during shard allocation to prevent new data from being assigned to\n * shards that are approaching or exceeding their size limits.\n *\n * @private\n * @param availableShards - List of shard names to filter\n * @param config - CollegeDB configuration containing maxDatabaseSize setting\n * @returns Promise resolving to filtered list of shard names\n */\nasync function filterShardsBySize(availableShards: string[], config: CollegeDBConfig): Promise<string[]> {\n\tif (typeof config.maxDatabaseSize !== 'number' || !Number.isFinite(config.maxDatabaseSize) || config.maxDatabaseSize <= 0) {\n\t\treturn availableShards;\n\t}\n\n\tconst limit = config.maxDatabaseSize;\n\n\tconst sizeChecks = await Promise.allSettled(\n\t\tavailableShards.map(async (shardName) => {\n\t\t\tconst size = await getDatabaseSizeForAllocation(shardName, config);\n\t\t\treturn {\n\t\t\t\tshard: shardName,\n\t\t\t\tsize,\n\t\t\t\twithinLimit: size < limit\n\t\t\t};\n\t\t})\n\t);\n\n\tconst validShards = sizeChecks\n\t\t.filter(\n\t\t\t(result): result is PromiseFulfilledResult<{ shard: string; size: number; withinLimit: boolean }> =>\n\t\t\t\tresult.status === 'fulfilled' && result.value.withinLimit\n\t\t)\n\t\t.map((result) => result.value.shard);\n\n\t// If all shards exceed the size limit, log warning and return all shards\n\t// to prevent complete failure (existing mappings should still work)\n\tif (validShards.length === 0) {\n\t\tif (config.debug) {\n\t\t\tconsole.warn('All shards exceed maxDatabaseSize limit. Allowing allocation to prevent failure.');\n\t\t}\n\t\treturn availableShards;\n\t}\n\n\tif (config.debug && validShards.length < availableShards.length) {\n\t\tconst excludedShards = availableShards.filter((shard) => !validShards.includes(shard));\n\t\tconsole.log(`Excluded ${excludedShards.length} shards due to size limits: ${excludedShards.join(', ')}`);\n\t}\n\n\treturn validShards;\n}\n\n/**\n * Selects the optimal shard for location-based allocation strategy.\n * Prioritizes shards in the target region, then nearby regions by distance.\n *\n * @private\n * @param targetRegion - The preferred region for allocation\n * @param availableShards - List of available shard names\n * @param shardLocations - Geographic locations of each shard\n * @param primaryKey - The primary key being allocated (for consistent tiebreaking)\n * @returns Selected shard name\n */\nfunction selectShardByLocation(\n\ttargetRegion: D1Region,\n\tavailableShards: string[],\n\tshardLocations: Record<string, ShardLocation | D1Region>,\n\tprimaryKey: string\n): string {\n\t// Filter shards that have location information\n\tconst locatedShards = availableShards.filter((shard) => shardLocations[shard]);\n\n\tif (locatedShards.length === 0) {\n\t\t// Fallback to hash if no location info available\n\t\tlet hash = 0;\n\t\tfor (let i = 0; i < primaryKey.length; i++) {\n\t\t\tconst char = primaryKey.charCodeAt(i);\n\t\t\thash = (hash << 5) - hash + char;\n\t\t\thash = hash & hash;\n\t\t}\n\t\tconst index = Math.abs(hash) % availableShards.length;\n\t\treturn availableShards[index]!;\n\t}\n\n\t// Calculate distances and priorities\n\tconst shardScores = locatedShards.map((shard) => {\n\t\tconst location = shardLocations[shard]!;\n\t\tconst distance = calculateRegionDistance(targetRegion, parseRegion(location));\n\n\t\tconst priority = typeof location === 'object' ? location.priority || 1 : 1;\n\t\tconst score = distance - priority * 0.1;\n\n\t\treturn { shard, score, distance, priority };\n\t});\n\n\t// Sort by score (lower is better)\n\tshardScores.sort((a, b) => a.score - b.score);\n\n\tconst bestScore = shardScores[0]!.score;\n\tconst bestShards = shardScores.filter((s) => Math.abs(s.score - bestScore) < 0.01);\n\n\tif (bestShards.length === 1) {\n\t\treturn bestShards[0]!.shard;\n\t}\n\n\t// Consistent selection among best candidates\n\tlet hash = 0;\n\tfor (let i = 0; i < primaryKey.length; i++) {\n\t\tconst char = primaryKey.charCodeAt(i);\n\t\thash = (hash << 5) - hash + char;\n\t\thash = hash & hash;\n\t}\n\tconst index = Math.abs(hash) % bestShards.length;\n\treturn bestShards[index]!.shard;\n}\n\n/**\n * Helper to select a shard locally based on the effective strategy when the coordinator\n * is unavailable or not configured. Provides sensible fallbacks to avoid hotspotting.\n * @private\n */\nfunction selectShardByStrategy(\n\teffectiveStrategy: ShardingStrategy,\n\tprimaryKey: string,\n\tavailableShards: string[],\n\tconfig: CollegeDBConfig\n): string {\n\tswitch (effectiveStrategy) {\n\t\tcase 'hash': {\n\t\t\tlet hash = 0;\n\t\t\tfor (let i = 0; i < primaryKey.length; i++) {\n\t\t\t\tconst char = primaryKey.charCodeAt(i);\n\t\t\t\thash = (hash << 5) - hash + char;\n\t\t\t\thash = hash & hash;\n\t\t\t}\n\t\t\tconst index = Math.abs(hash) % availableShards.length;\n\t\t\treturn availableShards[index] || availableShards[0]!;\n\t\t}\n\t\tcase 'location': {\n\t\t\tif (!config.targetRegion) {\n\t\t\t\treturn selectShardByStrategy('hash', primaryKey, availableShards, config);\n\t\t\t}\n\t\t\treturn selectShardByLocation(config.targetRegion, availableShards, config.shardLocations || {}, primaryKey);\n\t\t}\n\t\tcase 'random': {\n\t\t\treturn availableShards[Math.floor(Math.random() * availableShards.length)] || availableShards[0]!;\n\t\t}\n\t\tdefault: {\n\t\t\treturn selectShardByStrategy('hash', primaryKey, availableShards, config);\n\t\t}\n\t}\n}\n\n/**\n * Gets or allocates a shard for a primary key with operation-specific strategy\n *\n * This is the core routing function that determines which shard should handle\n * a given primary key. If a mapping already exists, it returns the existing\n * shard. If not, it allocates a new shard using the configured strategy.\n *\n * Allocation strategies:\n * - **round-robin**: Cycles through shards in order (with coordinator)\n * - **random**: Randomly selects from available shards\n * - **hash**: Uses consistent hashing for deterministic assignment\n * - **location**: Selects shards based on geographic proximity to target region\n *\n * The function prefers using the Durable Object coordinator when available\n * for centralized allocation decisions, falling back to local strategies\n * when the coordinator is unavailable.\n *\n * @private\n * @param primaryKey - The primary key to route\n * @param operationType - The type of operation (read/write) for mixed strategy support\n * @returns Promise resolving to the shard binding name\n * @throws {Error} If no shards are configured or allocation fails\n * @example\n * ```typescript\n * // This function is called internally by CRUD operations\n * const readShard = await getShardForKey('user-123', 'read');\n * const writeShard = await getShardForKey('user-123', 'write');\n * console.log(`User 123 reads from: ${readShard}, writes to: ${writeShard}`);\n * ```\n */\nasync function getShardForKey(primaryKey: string, operationType: OperationType = 'write'): Promise<string> {\n\tconst config = getConfig();\n\tconst mapper = getMapper(config);\n\n\t// Check if mapping already exists\n\tconst existingMapping = await mapper.getShardMapping(primaryKey);\n\tif (existingMapping) {\n\t\treturn existingMapping.shard;\n\t}\n\n\t// Before allocating a new shard, check if any existing shards contain this key\n\tconst availableShards = Object.keys(config.shards);\n\tif (availableShards.length === 0) {\n\t\tthrow new CollegeDBError('No shards configured', 'NO_SHARDS');\n\t}\n\n\t// Filter shards by size limit if configured\n\tconst eligibleShards = await filterShardsBySize(availableShards, config);\n\n\t// If no existing mapping found after auto-migration, allocate a new shard\n\tlet selectedShard: string;\n\tconst effectiveStrategy = resolveStrategy(config, operationType);\n\n\t// Use coordinator if available for allocation\n\tif (config.coordinator) {\n\t\ttry {\n\t\t\tconst coordinatorId = config.coordinator.idFromName('default');\n\t\t\tconst coordinator = config.coordinator.get(coordinatorId);\n\n\t\t\tconst response = await coordinator.fetch('http://coordinator/allocate', {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tprimaryKey,\n\t\t\t\t\tstrategy: effectiveStrategy, // Use resolved strategy instead of config.strategy\n\t\t\t\t\toperationType, // Pass operation type for coordinator awareness\n\t\t\t\t\ttargetRegion: config.targetRegion,\n\t\t\t\t\tshardLocations: config.shardLocations,\n\t\t\t\t\tavailableShards: eligibleShards // Pass filtered shards to coordinator\n\t\t\t\t})\n\t\t\t});\n\n\t\t\tif (response.ok) {\n\t\t\t\tconst result = (await response.json()) as { shard: string };\n\t\t\t\tselectedShard = result.shard;\n\t\t\t} else {\n\t\t\t\tselectedShard = selectShardByStrategy(effectiveStrategy, primaryKey, eligibleShards, config);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.warn('Coordinator allocation failed, falling back to local strategy:', error);\n\t\t\tselectedShard = selectShardByStrategy(effectiveStrategy, primaryKey, eligibleShards, config);\n\t\t}\n\t} else {\n\t\tselectedShard = selectShardByStrategy(effectiveStrategy, primaryKey, eligibleShards, config);\n\t}\n\n\t// Store the mapping\n\tawait mapper.setShardMapping(primaryKey, selectedShard);\n\treturn selectedShard;\n}\n\n/**\n * Gets the D1 database instance for a primary key with operation-specific routing\n *\n * Resolves the primary key to its assigned shard and returns the corresponding\n * D1 database instance. This function handles the complete routing process\n * from primary key to database connection, with support for different strategies\n * based on operation type.\n *\n * @private\n * @param primaryKey - The primary key to route\n * @param operationType - The type of operation (read/write) for mixed strategy support\n * @returns Promise resolving to the D1 database instance\n * @throws {Error} If shard routing fails or database instance not found\n */\nasync function getDatabase(primaryKey: string, operationType: OperationType = 'write'): Promise<SQLDatabase> {\n\tconst config = getConfig();\n\tconst shard = await getShardForKey(primaryKey, operationType);\n\tconst database = config.shards[shard];\n\n\tif (!database) {\n\t\tthrow new CollegeDBError(`Shard ${shard} not found in configuration`, 'SHARD_NOT_FOUND');\n\t}\n\n\treturn database;\n}\n\n/**\n * Creates the database schema in the specified D1 database\n *\n * @param d1 - The D1 database instance to create schema in\n * @param schema - The SQL schema definition to execute\n * @returns Promise that resolves when schema creation is complete\n * @throws {Error} If schema creation fails\n * @example\n * ```typescript\n * const userSchema = `\n * CREATE TABLE users (\n * id TEXT PRIMARY KEY,\n * name TEXT NOT NULL,\n * email TEXT UNIQUE\n * );\n * `;\n * await createSchema(env.DB_NEW_SHARD, userSchema);\n * ```\n */\nexport async function createSchema(d1: SQLDatabase, schema: string): Promise<void> {\n\tconst { createSchema: createSchemaImpl } = await import('./migrations');\n\tawait createSchemaImpl(d1, schema);\n}\n\n/**\n * Prepares a SQL statement for execution with operation-aware routing.\n *\n * @param key - The primary key to route the query\n * @param sql - The SQL statement to prepare\n * @returns Promise that resolves to a prepared statement\n * @throws {Error} If preparation fails\n */\nexport async function prepare(key: string, sql: string): Promise<PreparedStatement> {\n\tconst operationType = getOperationType(sql);\n\tconst db = await getDatabase(key, operationType);\n\tconst result = db.prepare(sql);\n\treturn result;\n}\n\n/**\n * Executes a statement on the appropriate shard based on the primary key.\n * The primary key is used to determine which shard should store the record,\n * ensuring consistent routing for future queries.\n *\n * @template T - Type of the result records\n * @param key - Primary key to route the query (should match the record's primary key)\n * @param sql - SQL statement with parameter placeholders\n * @param bindings - Parameter values to bind to the SQL statement\n * @returns Promise that resolves when the statement is complete\n * @throws {Error} If statement fails or routing fails\n * @example\n * ```typescript\n * // Insert a new user\n * await run('user-123',\n * 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)',\n * ['user-123', 'John Doe', 'john@example.com']\n * );\n *\n * // Insert a post linked to a user\n * await run('post-456',\n * 'INSERT INTO posts (id, user_id, title, content) VALUES (?, ?, ?, ?)',\n * ['post-456', 'user-123', 'Hello World', 'My first post!']\n * );\n * ```\n *\n * @example\n * ```typescript\n * // Update user information\n * await run('user-123',\n * 'UPDATE users SET name = ?, email = ? WHERE id = ?',\n * ['John Smith', 'johnsmith@example.com', 'user-123']\n * );\n *\n * // Update post content\n * await run('post-456',\n * 'UPDATE posts SET title = ?, content = ?, updated_at = strftime(\"%s\", \"now\") WHERE id = ?',\n * ['Updated Title', 'Updated content here', 'post-456']\n * );\n * ```\n *\n * @example\n * ```typescript\n * // Delete a specific user\n * await run('user-123',\n * 'DELETE FROM users WHERE id = ?',\n * ['user-123']\n * );\n *\n * // Delete user's posts (cascade delete)\n * await run('user-123',\n * 'DELETE FROM posts WHERE user_id = ?',\n * ['user-123']\n * );\n *\n * // Delete with conditions\n * await run('user-123',\n * 'DELETE FROM posts WHERE user_id = ? AND created_at < ?',\n * ['user-123', Date.now() - 86400000] // Posts older than 1 day\n * );\n * ```\n */\nexport async function run<T = Record<string, unknown>>(key: string, sql: string, bindings: any[] = []): Promise<QueryResult<T>> {\n\tconst prepared = await prepare(key, sql);\n\tconst result = await prepared.bind(...bindings).run<T>();\n\n\tif (!result.success) {\n\t\tthrow new CollegeDBError(`Query failed: ${result.error || 'Unknown error'}`, 'QUERY_FAILED');\n\t}\n\n\treturn result;\n}\n\n/**\n * Retrieves all records matching the query for a given primary key.\n *\n * This function is useful for fetching multiple records based on a primary key.\n * It automatically routes the query to the correct shard based on the provided\n * primary key, ensuring consistent data access.\n * @param key - Primary key to route the query\n * @param sql - The SQL statement to execute\n * @param bindings - Parameter values to bind to the SQL statement\n * @returns Promise that resolves to the result of the update operation\n * @throws {Error} If update fails or routing fails\n *\n * @example\n * ```typescript\n * type Post = {\n * id: string;\n * user_id: string;\n * title: string;\n * content: string;\n * };\n *\n *\n * // Get user's posts\n * const postsResult = await all<Post>('user-123',\n * 'SELECT * FROM posts WHERE user_id = ? ORDER BY created_at DESC',\n * ['user-123']\n * );\n *\n * console.log(`User has ${postsResult.meta.count} posts`);\n * ```\n */\nexport async function all<T = Record<string, unknown>>(key: string, sql: string, bindings: any[] = []): Promise<QueryResult<T>> {\n\tconst prepared = await prepare(key, sql);\n\tconst result = await prepared.bind(...bindings).all<T>();\n\n\tif (!result.success) {\n\t\tthrow new CollegeDBError(`Query failed: ${result.error || 'Unknown error'}`, 'QUERY_FAILED');\n\t}\n\n\treturn result;\n}\n\n/**\n * Retrieves the first record matching the query for a given primary key.\n *\n * This function is useful for fetching a single record based on a primary key.\n * It automatically routes the query to the correct shard based on the provided\n * primary key, ensuring consistent data access.\n *\n * @template T - Type of the result record\n * @param key - Primary key to route the query\n * @param sql - SQL statement with parameter placeholders\n * @param bindings - Parameter values to bind to the SQL statement\n * @returns Promise that resolves to the first matching record, or null if not found\n * @throws {Error} If query fails or routing fails\n *\n * @example\n * ```typescript\n * type User = {\n * id: string;\n * name: string;\n * email: string;\n * };\n * // Get a specific user\n * const userResult = await first<User>('user-123',\n * 'SELECT * FROM users WHERE id = ?',\n * ['user-123']\n * );\n *\n * if (userResult) {\n * console.log(`Found user: ${userResult.name}`);\n * }\n */\nexport async function first<T = Record<string, unknown>>(key: string, sql: string, bindings: any[] = []): Promise<T | null> {\n\tconst prepared = await prepare(key, sql);\n\tconst result = await prepared.bind(...bindings).first<T>();\n\treturn result;\n}\n\n/**\n * Retrieves all records using a secondary lookup key when available.\n *\n * This helper attempts to resolve the lookup key through KV first. If a mapping\n * exists, the query executes on that shard directly. If the mapping is missing,\n * stale, or returns no rows, the helper safely falls back to fanout (`allAllShards`)\n * and returns merged results.\n *\n * @template T - Type of the result records\n * @param lookupKey - Secondary key such as `email:user@example.com` or `username:alice`\n * @param sql - SQL statement to execute\n * @param bindings - Parameter values to bind to the SQL statement\n * @param batchSize - Number of concurrent shard queries during fanout (default: 50)\n * @returns Promise resolving to merged query results\n * @since 1.1.4\n */\nexport async function allByLookupKey<T = Record<string, unknown>>(\n\tlookupKey: string,\n\tsql: string,\n\tbindings: any[] = [],\n\tbatchSize: number = 50\n): Promise<QueryResult<T>> {\n\tconst config = getConfig();\n\tconst mapper = getMapper(config);\n\tconst mapping = await mapper.getShardMapping(lookupKey);\n\n\tif (mapping) {\n\t\tconst mappedShardDb = config.shards[mapping.shard];\n\t\tif (mappedShardDb) {\n\t\t\tconst mappedResult = await allShard<T>(mapping.shard, sql, bindings);\n\t\t\tif (mappedResult.success && mappedResult.results.length > 0) {\n\t\t\t\treturn mappedResult;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst shardResults = await allAllShards<T>(sql, bindings, batchSize);\n\treturn mergeAllShardQueryResults(shardResults);\n}\n\n/**\n * Retrieves the first record using a secondary lookup key when available.\n *\n * This helper avoids creating new primary-key mappings for secondary identifiers.\n * It first checks KV for a lookup-key mapping and queries that shard directly.\n * If no mapping exists (or the mapping is stale), it falls back to fanout\n * (`firstAllShards`) and returns the first non-null result.\n *\n * @template T - Type of the result record\n * @param lookupKey - Secondary key such as `email:user@example.com` or `username:alice`\n * @param sql - SQL statement to execute\n * @param bindings - Parameter values to bind to the SQL statement\n * @param batchSize - Number of concurrent shard queries during fanout (default: 50)\n * @returns Promise resolving to the first matching record, or null\n * @since 1.1.4\n */\nexport async function firstByLookupKey<T = Record<string, unknown>>(\n\tlookupKey: string,\n\tsql: string,\n\tbindings: any[] = [],\n\tbatchSize: number = 50\n): Promise<T | null> {\n\tconst config = getConfig();\n\tconst mapper = getMapper(config);\n\tconst mapping = await mapper.getShardMapping(lookupKey);\n\n\tif (mapping) {\n\t\tconst mappedShardDb = config.shards[mapping.shard];\n\t\tif (mappedShardDb) {\n\t\t\tconst mappedFirst = await firstShard<T>(mapping.shard, sql, bindings);\n\t\t\tif (mappedFirst !== null) {\n\t\t\t\treturn mappedFirst;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst fanoutResults = await firstAllShards<T>(sql, bindings, batchSize);\n\treturn fanoutResults.find((row): row is T => row !== null) ?? null;\n}\n\n/**\n * Reassigns a primary key to a different shard\n *\n * Moves a primary key and its associated data from one shard to another. This\n * operation is useful for load balancing, shard maintenance, or geographic\n * redistribution of data.\n *\n * The reassignment process:\n * 1. Validates the target shard exists in configuration\n * 2. Checks that a mapping exists for the primary key\n * 3. If target shard differs from current, migrates the data\n * 4. Updates the KV mapping to point to the new shard\n *\n * **Note**: This operation involves data migration and should be used\n * carefully in production environments. Consider the impact on ongoing queries.\n *\n * @param primaryKey - Primary key to reassign to a different shard\n * @param newBinding - New shard binding name where the data should be moved\n * @param tableName - Name of the table containing the record to migrate\n * @returns Promise that resolves when reassignment and migration are complete\n * @throws {Error} If target shard not found, mapping doesn't exist, or migration fails\n * @example\n * ```typescript\n * // Move a user from east to west coast for better latency\n * try {\n * await reassignShard('user-california-123', 'db-west', 'users');\n * console.log('User successfully moved to west coast shard');\n * } catch (error) {\n * console.error('Reassignment failed:', error.message);\n * }\n *\n * // Load balancing: move high-activity user to dedicated shard\n * await reassignShard('user-enterprise-456', 'db-dedicated', 'users');\n * ```\n */\nexport async function reassignShard(primaryKey: string, newBinding: string, tableName: string): Promise<void> {\n\tconst config = getConfig();\n\n\tif (!config.shards[newBinding]) {\n\t\tthrow new CollegeDBError(`Shard ${newBinding} not found in configuration`, 'SHARD_NOT_FOUND');\n\t}\n\n\tconst mapper = getMapper(config);\n\tconst currentMapping = await mapper.getShardMapping(primaryKey);\n\n\tif (!currentMapping) {\n\t\tthrow new CollegeDBError(`No existing mapping found for primary key: ${primaryKey}`, 'MAPPING_NOT_FOUND');\n\t}\n\n\t// Migrate data if different shard\n\tif (currentMapping.shard !== newBinding) {\n\t\tconst { migrateRecord } = await import('./migrations');\n\t\tconst sourceDb = config.shards[currentMapping.shard];\n\t\tconst targetDb = config.shards[newBinding];\n\n\t\tif (!sourceDb || !targetDb) {\n\t\t\tthrow new CollegeDBError('Source or target shard not available', 'SHARD_UNAVAILABLE');\n\t\t}\n\n\t\tawait migrateRecord(sourceDb, targetDb, primaryKey, tableName);\n\t}\n\n\t// Update mapping\n\tawait mapper.updateShardMapping(primaryKey, newBinding);\n}\n\n/**\n * Lists all known shards\n *\n * Returns an array of all shard binding names known to the system. First\n * attempts to get the list from the Durable Object coordinator for the most\n * up-to-date information, then falls back to the configured shards if the\n * coordinator is unavailable.\n *\n * @returns Promise resolving to array of shard binding names\n * @example\n * ```typescript\n * const shards = await listKnownShards();\n * console.log('Available shards:', shards);\n * // Output: ['db-east', 'db-west', 'db-central']\n *\n * // Check if a specific shard is available\n * if (shards.includes('db-asia')) {\n * console.log('Asia region shard is available');\n * }\n * ```\n */\nexport async function listKnownShards(): Promise<string[]> {\n\tconst config = getConfig();\n\n\t// Try to get from coordinator first\n\tif (config.coordinator) {\n\t\ttry {\n\t\t\tconst coordinatorId = config.coordinator.idFromName('default');\n\t\t\tconst coordinator = config.coordinator.get(coordinatorId);\n\n\t\t\tconst response = await coordinator.fetch('http://coordinator/shards');\n\t\t\tif (response.ok) {\n\t\t\t\treturn await response.json();\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.warn('Failed to get shards from coordinator:', error);\n\t\t}\n\t}\n\n\t// Fallback: merge configured shards with KV-known shards\n\ttry {\n\t\tconst mapper = getMapper(config);\n\t\tconst kvShards = await mapper.getKnownShards();\n\t\tconst merged = new Set<string>([...Object.keys(config.shards), ...kvShards]);\n\t\treturn Array.from(merged);\n\t} catch {\n\t\t// If KV lookup fails, just return configured shards\n\t\treturn Object.keys(config.shards);\n\t}\n}\n\n/**\n * Gets statistics for all shards\n *\n * Returns usage statistics for all known shards, including key counts and\n * last updated timestamps. First attempts to get real-time statistics from\n * the Durable Object coordinator, then falls back to KV-based counting.\n *\n * This information is useful for:\n * - Load balancing decisions\n * - Monitoring shard utilization\n * - Capacity planning\n * - Performance analysis\n *\n * @returns Promise resolving to array of shard statistics\n * @example\n * ```typescript\n * const stats = await getShardStats();\n * stats.forEach(shard => {\n * console.log(`${shard.binding}: ${shard.count} keys`);\n * if (shard.lastUpdated) {\n * console.log(` Last updated: ${new Date(shard.lastUpdated)}`);\n * }\n * });\n *\n * // Find most loaded shard\n * const mostLoaded = stats.reduce((prev, current) =>\n * (prev.count > current.count) ? prev : current\n * );\n * console.log(`Most loaded shard: ${mostLoaded.binding} (${mostLoaded.count} keys)`);\n * ```\n */\nexport async function getShardStats(): Promise<ShardStats[]> {\n\tconst config = getConfig();\n\n\t// Try to get from coordinator first\n\tif (config.coordinator) {\n\t\ttry {\n\t\t\tconst coordinatorId = config.coordinator.idFromName('default');\n\t\t\tconst coordinator = config.coordinator.get(coordinatorId);\n\n\t\t\tconst response = await coordinator.fetch('http://coordinator/stats');\n\t\t\tif (response.ok) {\n\t\t\t\treturn await response.json();\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.warn('Failed to get stats from coordinator:', error);\n\t\t}\n\t}\n\n\t// Fallback to KV-based counting\n\tconst mapper = getMapper(config);\n\tconst counts = await mapper.getShardKeyCounts();\n\n\t// Merge shards from config and KV known shards\n\tlet shardNames = Object.keys(config.shards);\n\ttry {\n\t\tconst kvKnown = await mapper.getKnownShards();\n\t\tshardNames = Array.from(new Set([...shardNames, ...kvKnown]));\n\t} catch {}\n\n\treturn shardNames.map((binding) => ({\n\t\tbinding,\n\t\tcount: counts[binding] || 0\n\t}));\n}\n\n/**\n * Bypasses the normal routing logic to execute a query directly on a specified\n * shard. This is useful for administrative operations, cross-shard queries,\n * or when you need to query data that doesn't follow the primary key routing pattern.\n *\n * **Use with caution**: This function bypasses routing safeguards and should\n * be used only when you specifically need to target a particular shard.\n *\n * @param shardBinding - The shard binding name to execute the query on\n * @param sql - SQL statement to execute\n * @param bindings - Parameter values to bind to the SQL statement\n * @returns Promise resolving to the result of the query execution\n * @throws {Error} If shard not found or query fails\n * @example\n * ```typescript\n * // Administrative query: insert a new user directly into a specific shard\n * const result = await runShard('db-east',\n * 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)',\n * ['user-789', 'Alice', 'alice@example.com']\n * );\n * console.log(`Inserted user with ID: ${result.lastInsertId}`);\n * ```\n */\nexport async function runShard<T = Record<string, unknown>>(\n\tshardBinding: string,\n\tsql: string,\n\tbindings: any[] = []\n): Promise<QueryResult<T>> {\n\tconst config = getConfig();\n\tconst db = config.shards[shardBinding];\n\n\tif (!db) {\n\t\tthrow new CollegeDBError(`Shard ${shardBinding} not found`, 'SHARD_NOT_FOUND');\n\t}\n\n\tconst result = await db\n\t\t.prepare(sql)\n\t\t.bind(...bindings)\n\t\t.run<T>();\n\n\tif (!result.success) {\n\t\tthrow new CollegeDBError(`Query failed: ${result.error || 'Unknown error'}`, 'QUERY_FAILED');\n\t}\n\n\treturn result;\n}\n\n/**\n * Bypasses the normal routing logic to execute a query directly on a specified\n * shard. This is useful for administrative operations, cross-shard queries,\n * or when you need to query data that doesn't follow the primary key routing pattern.\n *\n * **Use with caution**: This function bypasses routing safeguards and should\n * be used only when you specifically need to target a particular shard.\n *\n * @param shardBinding - The shard binding name to execute the query on\n * @param sql - SQL statement to execute\n * @param bindings - Parameter values to bind to the SQL statement\n * @returns Promise resolving to structured query results\n * @throws {Error} If shard not found or query fails\n * @example\n * ```typescript\n * // Administrative query: count all users across a specific shard\n * const eastCoastStats = await allShard('db-east',\n * 'SELECT COUNT(*) as user_count FROM users'\n * );\n * console.log(`East coast users: ${eastCoastStats.results[0].user_count}`);\n *\n * // Cross-shard analytics: get recent posts from a specific region\n * const recentPosts = await allShard('db-west',\n * 'SELECT id, title, created_at FROM posts WHERE created_at > ? ORDER BY created_at DESC LIMIT ?',\n * [Date.now() - 86400000, 10] // Last 24 hours, limit 10\n * );\n *\n * // Schema inspection on specific shard\n * const tables = await allShard('db-central',\n * \"SELECT name FROM sqlite_master WHERE type='table'\"\n * );\n * ```\n */\nexport async function allShard<T = Record<string, unknown>>(\n\tshardBinding: string,\n\tsql: string,\n\tbindings: any[] = []\n): Promise<QueryResult<T>> {\n\tconst config = getConfig();\n\tconst db = config.shards[shardBinding];\n\n\tif (!db) {\n\t\tthrow new CollegeDBError(`Shard ${shardBinding} not found`, 'SHARD_NOT_FOUND');\n\t}\n\n\tconst result = await db\n\t\t.prepare(sql)\n\t\t.bind(...bindings)\n\t\t.all<T>();\n\n\treturn result;\n}\n\n/**\n * Bypasses the normal routing logic to execute a query directly on a specified\n * shard. This is useful for administrative operations, cross-shard queries,\n * or when you need to query data that doesn't follow the primary key routing pattern.\n *\n * **Use with caution**: This function bypasses routing safeguards and should\n * be used only when you specifically need to target a particular shard.\n *\n * @param shardBinding - The shard binding name to execute the query on\n * @param sql - SQL statement to execute\n * @param bindings - Parameter values to bind to the SQL statement\n * @returns Promise resolving to the first matching record, or null if not found\n * @throws {Error} If shard not found or query fails\n * @example\n * ```typescript\n * // Administrative query: get a specific user from a shard\n * const user = await firstShard('db-east',\n * 'SELECT * FROM users WHERE id = ?',\n * ['user-123']);\n * if (user) {\n * console.log(`Found user: ${user.name}`);\n * } else {\n * console.log('User not found in east shard');\n * }\n * ```\n */\nexport async function firstShard<T = Record<string, unknown>>(shardBinding: string, sql: string, bindings: any[] = []): Promise<T | null> {\n\tconst config = getConfig();\n\tconst db = config.shards[shardBinding];\n\n\tif (!db) {\n\t\tthrow new CollegeDBError(`Shard ${shardBinding} not found`, 'SHARD_NOT_FOUND');\n\t}\n\n\tconst result = await db\n\t\t.prepare(sql)\n\t\t.bind(...bindings)\n\t\t.first<T>();\n\n\treturn result;\n}\n\n/**\n * Executes a query on all shards and returns the results from each shard.\n *\n * This function is useful for scenarios where you need to aggregate data\n * from multiple shards, such as running analytics or cross-shard queries.\n * It executes the same SQL statement on each shard and collects the results.\n * @param sql - The SQL statement to execute on each shard\n * @param bindings - Parameter values to bind to the SQL statement\n * @param batchSize - Number of concurrent queries to run at once (default: 50)\n * @returns Promise resolving to an array of results from each shard\n * @since 1.0.4\n */\nexport async function runAllShards<T = Record<string, unknown>>(\n\tsql: string,\n\tbindings: any[] = [],\n\tbatchSize: number = 50\n): Promise<QueryResult<T>[]> {\n\tconst config = getConfig();\n\tconst tasks: Array<() => Promise<QueryResult<T>>> = [];\n\n\tfor (const [binding, db] of Object.entries(config.shards)) {\n\t\tif (!binding || !db) {\n\t\t\tconsole.error(`Shard ${binding ?? '<null>'} not found, skipping`);\n\t\t\tcontinue;\n\t\t}\n\n\t\ttasks.push(() =>\n\t\t\tdb\n\t\t\t\t.prepare(sql)\n\t\t\t\t.bind(...bindings)\n\t\t\t\t.run<T>()\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tconsole.error(`Error executing query on shard ${binding}:`, error);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\tresults: [],\n\t\t\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t\tmeta: { duration: 0 }\n\t\t\t\t\t} satisfies QueryResult<T>;\n\t\t\t\t})\n\t\t);\n\t}\n\n\tconst out: QueryResult<T>[] = [];\n\tfor (let i = 0; i < tasks.length; i += batchSize) {\n\t\tconst batch = tasks.slice(i, i + batchSize).map((fn) => fn());\n\t\tout.push(...(await Promise.all(batch)));\n\t}\n\n\treturn out;\n}\n\n/**\n * Executes a query on all shards and returns all matching records from each shard.\n *\n * This function is useful for scenarios where you need to retrieve all records\n * matching a query across multiple shards, such as aggregating data or running\n * cross-shard analytics.\n * @param sql - The SQL statement to execute on each shard\n * @param bindings - Parameter values to bind to the SQL statement\n * @param batchSize - Number of concurrent queries to run at once (default: 50)\n * @returns Promise resolving to an array of results from each shard\n * @since 1.0.4\n */\nexport async function allAllShards<T = Record<string, unknown>>(\n\tsql: string,\n\tbindings: any[] = [],\n\tbatchSize: number = 50\n): Promise<QueryResult<T>[]> {\n\tconst config = getConfig();\n\tconst tasks: Array<() => Promise<QueryResult<T>>> = [];\n\n\tfor (const [binding, db] of Object.entries(config.shards)) {\n\t\tif (!binding || !db) {\n\t\t\tconsole.error(`Shard ${binding ?? '<null>'} not found, skipping`);\n\t\t\tcontinue;\n\t\t}\n\n\t\ttasks.push(() =>\n\t\t\tdb\n\t\t\t\t.prepare(sql)\n\t\t\t\t.bind(...bindings)\n\t\t\t\t.all<T>()\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tconsole.error(`Error executing query on shard ${binding}:`, error);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\tresults: [],\n\t\t\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t\tmeta: { duration: 0 }\n\t\t\t\t\t} satisfies QueryResult<T>;\n\t\t\t\t})\n\t\t);\n\t}\n\n\tconst out: QueryResult<T>[] = [];\n\tfor (let i = 0; i < tasks.length; i += batchSize) {\n\t\tconst batch = tasks.slice(i, i + batchSize).map((fn) => fn());\n\t\tout.push(...(await Promise.all(batch)));\n\t}\n\n\treturn out;\n}\n\n/**\n * Options for global all-shards merge/sort/pagination.\n * @since 1.1.4\n */\nexport interface GlobalAllShardsOptions<T = Record<string, unknown>> {\n\t/** Number of concurrent shard queries to run at once (default: 50). */\n\tbatchSize?: number;\n\t/** Number of rows to skip after global merge/sort (default: 0). */\n\toffset?: number;\n\t/** Maximum rows to return after global merge/sort. */\n\tlimit?: number;\n\t/** Field name or selector used for global sorting. */\n\tsortBy?: keyof T | ((row: T) => unknown);\n\t/** Sort direction for `sortBy` (default: `asc`). */\n\tsortDirection?: 'asc' | 'desc';\n\t/** Optional custom comparator; takes precedence over `sortBy`. */\n\tcomparator?: (left: T, right: T) => number;\n\t/** Optional global row filter applied before sort/paginate. */\n\tfilter?: (row: T) => boolean;\n}\n\nfunction normalizeBatchSize(batchSize: number | undefined, defaultValue: number = 50): number {\n\tif (!Number.isFinite(batchSize ?? defaultValue)) {\n\t\treturn defaultValue;\n\t}\n\n\treturn Math.max(1, Math.floor(batchSize ?? defaultValue));\n}\n\nfunction normalizeOffset(offset: number | undefined): number {\n\tif (!Number.isFinite(offset ?? 0)) {\n\t\treturn 0;\n\t}\n\n\treturn Math.max(0, Math.floor(offset ?? 0));\n}\n\nfunction normalizeLimit(limit: number | undefined): number | undefined {\n\tif (limit === undefined) {\n\t\treturn undefined;\n\t}\n\n\tif (!Number.isFinite(limit)) {\n\t\treturn undefined;\n\t}\n\n\treturn Math.max(0, Math.floor(limit));\n}\n\nfunction getRowSortValue<T>(row: T, sortBy: GlobalAllShardsOptions<T>['sortBy']): unknown {\n\tif (typeof sortBy === 'function') {\n\t\treturn sortBy(row);\n\t}\n\n\tif (!sortBy || typeof row !== 'object' || row === null) {\n\t\treturn undefined;\n\t}\n\n\treturn (row as Record<string, unknown>)[String(sortBy)];\n}\n\nfunction compareUnknown(left: unknown, right: unknown): number {\n\tif (left === right) return 0;\n\tif (left === null || left === undefined) return 1;\n\tif (right === null || right === undefined) return -1;\n\n\tif (typeof left === 'number' && typeof right === 'number') {\n\t\treturn left - right;\n\t}\n\n\tif (typeof left === 'bigint' && typeof right === 'bigint') {\n\t\treturn left < right ? -1 : 1;\n\t}\n\n\tif (left instanceof Date && right instanceof Date) {\n\t\treturn left.getTime() - right.getTime();\n\t}\n\n\tif (typeof left === 'boolean' && typeof right === 'boolean') {\n\t\treturn Number(left) - Number(right);\n\t}\n\n\treturn String(left).localeCompare(String(right), undefined, { numeric: true, sensitivity: 'base' });\n}\n\nfunction mergeAllShardQueryResults<T = Record<string, unknown>>(shardResults: QueryResult<T>[]): QueryResult<T> {\n\tconst allResults = shardResults.flatMap((result) => result.results || []);\n\tconst failures = shardResults.filter((result) => !result.success);\n\tconst totalDuration = shardResults.reduce((sum, result) => sum + (result.meta?.duration || 0), 0);\n\n\tif (failures.length === 0) {\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: allResults,\n\t\t\tmeta: { duration: totalDuration }\n\t\t};\n\t}\n\n\tconst errorMessage = failures\n\t\t.map((failure) => failure.error || 'Unknown shard query error')\n\t\t.filter(Boolean)\n\t\t.join('; ');\n\n\treturn {\n\t\tsuccess: false,\n\t\tresults: allResults,\n\t\terror: errorMessage || 'One or more shard queries failed',\n\t\tmeta: { duration: totalDuration }\n\t};\n}\n\n/**\n * Executes a query on all shards and applies global merge/sort/pagination in-library.\n *\n * Unlike `allAllShards`, this helper returns a single merged `QueryResult` and can\n * sort/paginate across the full combined result set after fanout.\n *\n * @template T - Type of the result records\n * @param sql - SQL statement to execute on each shard\n * @param bindings - Parameter values to bind to the SQL statement\n * @param options - Global merge/sort/pagination options\n * @returns Promise resolving to one globally-processed query result\n * @since 1.1.4\n */\nexport async function allAllShardsGlobal<T = Record<string, unknown>>(\n\tsql: string,\n\tbindings: any[] = [],\n\toptions: GlobalAllShardsOptions<T> = {}\n): Promise<QueryResult<T>> {\n\tconst batchSize = normalizeBatchSize(options.batchSize);\n\tconst offset = normalizeOffset(options.offset);\n\tconst limit = normalizeLimit(options.limit);\n\n\tconst merged = mergeAllShardQueryResults(await allAllShards<T>(sql, bindings, batchSize));\n\tlet rows = merged.results;\n\n\tif (options.filter) {\n\t\trows = rows.filter((row) => options.filter?.(row));\n\t}\n\n\tif (options.comparator) {\n\t\trows = [...rows].sort(options.comparator);\n\t} else if (options.sortBy) {\n\t\tconst direction = options.sortDirection === 'desc' ? -1 : 1;\n\t\trows = [...rows].sort((left, right) => {\n\t\t\tconst leftValue = getRowSortValue(left, options.sortBy);\n\t\t\tconst rightValue = getRowSortValue(right, options.sortBy);\n\t\t\treturn compareUnknown(leftValue, rightValue) * direction;\n\t\t});\n\t}\n\n\tconst end = limit === undefined ? undefined : offset + limit;\n\tconst pagedRows = rows.slice(offset, end);\n\n\treturn {\n\t\t...merged,\n\t\tresults: pagedRows\n\t};\n}\n\n/**\n * Executes a query on all shards and returns the first matching record from each shard.\n *\n * This function is useful for scenarios where you need to retrieve a single record\n * from each shard, such as fetching the latest entry or a specific item that may\n * exist on multiple shards.\n * @param sql - The SQL statement to execute\n * @param bindings - Parameter values to bind to the SQL statement\n * @param batchSize - Number of concurrent queries to run at once (default: 50)\n * @returns Promise resolving to an array of first matching records from each shard\n * @since 1.0.4\n */\nexport async function firstAllShards<T = Record<string, unknown>>(\n\tsql: string,\n\tbindings: any[] = [],\n\tbatchSize: number = 50\n): Promise<(T | null)[]> {\n\tconst config = getConfig();\n\tconst tasks: Array<() => Promise<T | null>> = [];\n\n\tfor (const [binding, db] of Object.entries(config.shards)) {\n\t\tif (!binding || !db) {\n\t\t\tconsole.error(`Shard ${binding ?? '<null>'} not found, skipping`);\n\t\t\tcontinue;\n\t\t}\n\n\t\ttasks.push(() =>\n\t\t\tdb\n\t\t\t\t.prepare(sql)\n\t\t\t\t.bind(...bindings)\n\t\t\t\t.first<T>()\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tconsole.error(`Error executing query on shard ${binding}:`, error);\n\t\t\t\t\treturn null;\n\t\t\t\t})\n\t\t);\n\t}\n\n\tconst out: (T | null)[] = [];\n\tfor (let i = 0; i < tasks.length; i += batchSize) {\n\t\tconst batch = tasks.slice(i, i + batchSize).map((fn) => fn());\n\t\tout.push(...(await Promise.all(batch)));\n\t}\n\n\treturn out;\n}\n\n/**\n * Executes a query on all shards with global merge/sort/pagination and returns\n * the first row after global processing.\n *\n * @template T - Type of the result record\n * @param sql - SQL statement to execute on each shard\n * @param bindings - Parameter values to bind to the SQL statement\n * @param options - Global merge/sort/pagination options (batchSize, sort, offset)\n * @returns Promise resolving to the first globally-processed row, or null\n * @since 1.1.4\n */\nexport async function firstAllShardsGlobal<T = Record<string, unknown>>(\n\tsql: string,\n\tbindings: any[] = [],\n\toptions: Omit<GlobalAllShardsOptions<T>, 'limit'> = {}\n): Promise<T | null> {\n\tconst merged = await allAllShardsGlobal<T>(sql, bindings, {\n\t\t...options,\n\t\tlimit: 1\n\t});\n\n\treturn merged.results[0] ?? null;\n}\n\n/**\n * Flushes all shard mappings (development only)\n *\n * Completely clears all primary key to shard mappings from both KV storage\n * and the Durable Object coordinator. This operation resets the entire\n * routing system to a clean state.\n *\n * **DANGER**: This operation is destructive and irreversible. After flushing,\n * all existing primary keys will be treated as new and may be assigned to\n * different shards than before, causing data routing issues.\n *\n * **Use only for**:\n * - Development and testing environments\n * - Complete system resets\n * - Emergency recovery scenarios\n *\n * @returns Promise that resolves when all mappings are cleared\n * @example\n * ```typescript\n * // Only use in development!\n * if (process.env.NODE_ENV === 'development') {\n * await flush();\n * console.log('All shard mappings cleared for testing');\n *\n * // Now all keys will be reassigned on next access\n * await run('user-123', 'INSERT INTO users (id, name) VALUES (?, ?)',\n * ['user-123', 'Test User']);\n * }\n * ```\n */\nexport async function flush(): Promise<void> {\n\tconst config = getConfig();\n\tconst mapper = getMapper(config);\n\n\tawait mapper.clearAllMappings();\n\tshardSizeCache.clear();\n\n\t// Also flush coordinator if available\n\tif (config.coordinator) {\n\t\ttry {\n\t\t\tconst coordinatorId = config.coordinator.idFromName('default');\n\t\t\tconst coordinator = config.coordinator.get(coordinatorId);\n\n\t\t\tawait coordinator.fetch('http://coordinator/flush', { method: 'POST' });\n\t\t} catch (error) {\n\t\t\tconsole.warn('Failed to flush coordinator:', error);\n\t\t}\n\t}\n}\n\n/**\n * Gets the size of a specific D1 database in bytes.\n * Uses efficient SQLite pragma queries to determine database size.\n *\n * @param shardBinding - The shard binding name to check the size of\n * @returns Promise resolving to the database size in bytes\n * @throws {CollegeDBError} If shard not found or size query fails\n * @example\n * ```typescript\n * // Get size of a specific shard\n * const sizeInBytes = await getDatabaseSizeForShard('db-east');\n * console.log(`Database size: ${Math.round(sizeInBytes / 1024 / 1024)} MB`);\n * ```\n */\nexport async function getDatabaseSizeForShard(shardBinding: string): Promise<number> {\n\tconst config = getConfig();\n\tconst database = config.shards[shardBinding];\n\n\tif (!database) {\n\t\tthrow new CollegeDBError(`Shard ${shardBinding} not found`, 'SHARD_NOT_FOUND');\n\t}\n\n\treturn await getDatabaseSize(database);\n}\n\nconst SQL_IDENTIFIER_PART_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nfunction quoteIdentifier(identifier: string): string {\n\tconst trimmed = identifier.trim();\n\tif (!trimmed) {\n\t\tthrow new CollegeDBError('Identifier cannot be empty', 'INVALID_IDENTIFIER');\n\t}\n\n\tconst parts = trimmed.split('.').map((part) => part.trim());\n\tif (parts.some((part) => !part || !SQL_IDENTIFIER_PART_REGEX.test(part))) {\n\t\tthrow new CollegeDBError(`Invalid SQL identifier: ${identifier}`, 'INVALID_IDENTIFIER');\n\t}\n\n\treturn parts.map((part) => `\"${part}\"`).join('.');\n}\n\nfunction normalizeIndexNameSegment(value: string): string {\n\treturn value\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9_]+/g, '_')\n\t\t.replace(/_+/g, '_')\n\t\t.replace(/^_+|_+$/g, '');\n}\n\n/**\n * Column specification for index creation helpers.\n * @since 1.1.4\n */\nexport interface IndexColumnDefinition {\n\t/** Column name to include in the index. */\n\tname: string;\n\t/** Optional sort direction for this column. */\n\torder?: 'ASC' | 'DESC';\n\t/** Optional collation (e.g., NOCASE). */\n\tcollate?: string;\n}\n\n/**\n * Options for index creation helpers.\n * @since 1.1.4\n */\nexport interface CreateIndexOptions {\n\t/** Explicit index name. When omitted, a deterministic name is generated. */\n\tindexName?: string;\n\t/** Create a unique index. */\n\tunique?: boolean;\n\t/** Include `IF NOT EXISTS` in generated SQL. @default true */\n\tifNotExists?: boolean;\n\t/** Optional partial-index predicate (trusted SQL only). */\n\twhere?: string;\n\t/** Number of concurrent shard operations for all-shard variants. @default 50 */\n\tbatchSize?: number;\n}\n\nfunction normalizeIndexColumns(columns: string | string[] | IndexColumnDefinition[]): IndexColumnDefinition[] {\n\tif (typeof columns === 'string') {\n\t\treturn [{ name: columns }];\n\t}\n\n\tif (!Array.isArray(columns) || columns.length === 0) {\n\t\tthrow new CollegeDBError('At least one index column is required', 'INVALID_INDEX_COLUMNS');\n\t}\n\n\treturn columns.map((column) => {\n\t\tif (typeof column === 'string') {\n\t\t\treturn { name: column };\n\t\t}\n\n\t\tif (!column?.name) {\n\t\t\tthrow new CollegeDBError('Index column name is required', 'INVALID_INDEX_COLUMNS');\n\t\t}\n\n\t\treturn {\n\t\t\tname: column.name,\n\t\t\torder: column.order,\n\t\t\tcollate: column.collate\n\t\t};\n\t});\n}\n\nfunction buildCreateIndexSQL(\n\ttable: string,\n\tcolumns: string | string[] | IndexColumnDefinition[],\n\toptions: CreateIndexOptions = {}\n): string {\n\tconst normalizedColumns = normalizeIndexColumns(columns);\n\tconst quotedTable = quoteIdentifier(table);\n\tconst generatedIndexName = options.indexName\n\t\t? options.indexName\n\t\t: ['idx', normalizeIndexNameSegment(table), ...normalizedColumns.map((column) => normalizeIndexNameSegment(column.name))]\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.join('_')\n\t\t\t\t.slice(0, 120);\n\tconst quotedIndexName = quoteIdentifier(generatedIndexName || 'idx_auto');\n\n\tconst columnClauses = normalizedColumns\n\t\t.map((column) => {\n\t\t\tconst quotedColumn = quoteIdentifier(column.name);\n\t\t\tconst order = column.order ? ` ${column.order}` : '';\n\t\t\tconst collate = column.collate ? ` COLLATE ${quoteIdentifier(column.collate).replace(/\"/g, '')}` : '';\n\t\t\treturn `${quotedColumn}${collate}${order}`;\n\t\t})\n\t\t.join(', ');\n\n\tconst ifNotExistsClause = options.ifNotExists === false ? '' : ' IF NOT EXISTS';\n\tconst uniqueClause = options.unique ? 'UNIQUE ' : '';\n\tconst whereClause = options.where?.trim() ? ` WHERE ${options.where.trim()}` : '';\n\n\treturn `CREATE ${uniqueClause}INDEX${ifNotExistsClause} ${quotedIndexName} ON ${quotedTable} (${columnClauses})${whereClause}`;\n}\n\n/**\n * Creates an index on the shard resolved by the provided key.\n *\n * @param key - Primary key used for shard routing\n * @param table - Target table name\n * @param columns - One or more columns to index\n * @param options - Index creation options\n * @returns Query result for the DDL statement\n * @since 1.1.4\n */\nexport async function index<T = Record<string, unknown>>(\n\tkey: string,\n\ttable: string,\n\tcolumns: string | string[] | IndexColumnDefinition[],\n\toptions: Omit<CreateIndexOptions, 'batchSize'> = {}\n): Promise<QueryResult<T>> {\n\tconst sql = buildCreateIndexSQL(table, columns, options);\n\treturn run<T>(key, sql);\n}\n\n/**\n * Creates an index directly on a specific shard.\n *\n * @param shardBinding - Shard binding name\n * @param table - Target table name\n * @param columns - One or more columns to index\n * @param options - Index creation options\n * @returns Query result for the DDL statement\n * @since 1.1.4\n */\nexport async function indexShard<T = Record<string, unknown>>(\n\tshardBinding: string,\n\ttable: string,\n\tcolumns: string | string[] | IndexColumnDefinition[],\n\toptions: Omit<CreateIndexOptions, 'batchSize'> = {}\n): Promise<QueryResult<T>> {\n\tconst sql = buildCreateIndexSQL(table, columns, options);\n\treturn runShard<T>(shardBinding, sql);\n}\n\n/**\n * Creates an index across all configured shards.\n *\n * @param table - Target table name\n * @param columns - One or more columns to index\n * @param options - Index creation options, including `batchSize`\n * @returns Per-shard query results\n * @since 1.1.4\n */\nexport async function indexAllShards<T = Record<string, unknown>>(\n\ttable: string,\n\tcolumns: string | string[] | IndexColumnDefinition[],\n\toptions: CreateIndexOptions = {}\n): Promise<QueryResult<T>[]> {\n\tconst sql = buildCreateIndexSQL(table, columns, options);\n\treturn runAllShards<T>(sql, [], normalizeBatchSize(options.batchSize));\n}\n\n/**\n * Explain helpers options.\n * @since 1.1.4\n */\nexport interface ExplainOptions {\n\t/** Explain mode. @default query-plan */\n\tmode?: 'query-plan' | 'raw' | 'analyze';\n\t/** Number of concurrent shard operations for all-shard variants. @default 50 */\n\tbatchSize?: number;\n}\n\nfunction buildExplainSQL(sql: string, mode: ExplainOptions['mode'] = 'query-plan'): string {\n\tswitch (mode) {\n\t\tcase 'raw':\n\t\t\treturn `EXPLAIN ${sql}`;\n\t\tcase 'analyze':\n\t\t\treturn `EXPLAIN ANALYZE ${sql}`;\n\t\tcase 'query-plan':\n\t\tdefault:\n\t\t\treturn `EXPLAIN QUERY PLAN ${sql}`;\n\t}\n}\n\n/**\n * Executes an explain query on the shard resolved by key.\n *\n * @param key - Primary key used for shard routing\n * @param sql - SQL statement to inspect\n * @param bindings - Parameter values for the SQL statement\n * @param options - Explain mode options\n * @returns Explain rows as a QueryResult\n * @since 1.1.4\n */\nexport async function explain<T = Record<string, unknown>>(\n\tkey: string,\n\tsql: string,\n\tbindings: any[] = [],\n\toptions: Omit<ExplainOptions, 'batchSize'> = {}\n): Promise<QueryResult<T>> {\n\treturn all<T>(key, buildExplainSQL(sql, options.mode), bindings);\n}\n\n/**\n * Executes an explain query on a specific shard.\n *\n * @param shardBinding - Shard binding name\n * @param sql - SQL statement to inspect\n * @param bindings - Parameter values for the SQL statement\n * @param options - Explain mode options\n * @returns Explain rows as a QueryResult\n * @since 1.1.4\n */\nexport async function explainShard<T = Record<string, unknown>>(\n\tshardBinding: string,\n\tsql: string,\n\tbindings: any[] = [],\n\toptions: Omit<ExplainOptions, 'batchSize'> = {}\n): Promise<QueryResult<T>> {\n\treturn allShard<T>(shardBinding, buildExplainSQL(sql, options.mode), bindings);\n}\n\n/**\n * Executes an explain query across all shards.\n *\n * @param sql - SQL statement to inspect\n * @param bindings - Parameter values for the SQL statement\n * @param options - Explain options, including `batchSize`\n * @returns Per-shard explain query results\n * @since 1.1.4\n */\nexport async function explainAllShards<T = Record<string, unknown>>(\n\tsql: string,\n\tbindings: any[] = [],\n\toptions: ExplainOptions = {}\n): Promise<QueryResult<T>[]> {\n\treturn allAllShards<T>(buildExplainSQL(sql, options.mode), bindings, normalizeBatchSize(options.batchSize));\n}\n\n/**\n * Table row-count result for a shard.\n * @since 1.1.4\n */\nexport interface ShardTableCount {\n\tshard: string;\n\tcount: number | null;\n\tsuccess: boolean;\n\terror?: string;\n}\n\n/**\n * Counts rows for a table on the shard resolved by key.\n *\n * @param key - Primary key used for shard routing\n * @param table - Table name to count\n * @returns Row count for that routed shard\n * @since 1.1.4\n */\nexport async function count(key: string, table: string): Promise<number> {\n\tconst quotedTable = quoteIdentifier(table);\n\tconst row = await first<{ row_count?: number | string }>(key, `SELECT COUNT(*) AS row_count FROM ${quotedTable}`);\n\tif (!row || row.row_count === undefined || row.row_count === null) {\n\t\treturn 0;\n\t}\n\n\treturn Number(row.row_count) || 0;\n}\n\n/**\n * Counts rows for a table on a specific shard.\n *\n * @param shardBinding - Shard binding name\n * @param table - Table name to count\n * @returns Row count for the shard\n * @since 1.1.4\n */\nexport async function countShard(shardBinding: string, table: string): Promise<number> {\n\tconst quotedTable = quoteIdentifier(table);\n\tconst row = await firstShard<{ row_count?: number | string }>(shardBinding, `SELECT COUNT(*) AS row_count FROM ${quotedTable}`);\n\tif (!row || row.row_count === undefined || row.row_count === null) {\n\t\treturn 0;\n\t}\n\n\treturn Number(row.row_count) || 0;\n}\n\n/**\n * Counts rows for a table across all shards.\n *\n * @param table - Table name to count\n * @param batchSize - Number of concurrent shard queries (default: 50)\n * @returns Per-shard counts and global total\n * @since 1.1.4\n */\nexport async function countAllShards(table: string, batchSize: number = 50): Promise<{ total: number; shards: ShardTableCount[] }> {\n\tconst config = getConfig();\n\tconst normalizedBatchSize = normalizeBatchSize(batchSize);\n\tconst quotedTable = quoteIdentifier(table);\n\tconst sql = `SELECT COUNT(*) AS row_count FROM ${quotedTable}`;\n\tconst tasks: Array<() => Promise<ShardTableCount>> = [];\n\n\tfor (const [binding, db] of Object.entries(config.shards)) {\n\t\tif (!binding || !db) {\n\t\t\tcontinue;\n\t\t}\n\n\t\ttasks.push(async () => {\n\t\t\ttry {\n\t\t\t\tconst row = await db.prepare(sql).first<{ row_count?: number | string }>();\n\t\t\t\tconst parsed = Number(row?.row_count ?? 0);\n\t\t\t\treturn {\n\t\t\t\t\tshard: binding,\n\t\t\t\t\tcount: Number.isFinite(parsed) ? parsed : 0,\n\t\t\t\t\tsuccess: true\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tshard: binding,\n\t\t\t\t\tcount: null,\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: error instanceof Error ? error.message : String(error)\n\t\t\t\t};\n\t\t\t}\n\t\t});\n\t}\n\n\tconst shards: ShardTableCount[] = [];\n\tfor (let i = 0; i < tasks.length; i += normalizedBatchSize) {\n\t\tconst batch = tasks.slice(i, i + normalizedBatchSize).map((task) => task());\n\t\tshards.push(...(await Promise.all(batch)));\n\t}\n\n\tconst total = shards.reduce((sum, shard) => sum + (shard.count ?? 0), 0);\n\treturn { total, shards };\n}\n\n/**\n * Size information for a shard.\n * @since 1.1.4\n */\nexport interface ShardSizeResult {\n\tshard: string;\n\tsize: number | null;\n\tsuccess: boolean;\n\terror?: string;\n}\n\n/**\n * Gets the size in bytes for the shard resolved by key.\n *\n * @param key - Primary key used for shard routing\n * @returns Database size in bytes\n * @since 1.1.4\n */\nexport async function getDatabaseSizeForKey(key: string): Promise<number> {\n\tconst config = getConfig();\n\tconst shardBinding = await getShardForKey(key, 'read');\n\tconst database = config.shards[shardBinding];\n\n\tif (!database) {\n\t\tthrow new CollegeDBError(`Shard ${shardBinding} not found in configuration`, 'SHARD_NOT_FOUND');\n\t}\n\n\treturn getDatabaseSize(database);\n}\n\n/**\n * Gets database sizes for all shards.\n *\n * @param batchSize - Number of concurrent shard queries (default: 50)\n * @returns Per-shard size results with success/error status\n * @since 1.1.4\n */\nexport async function getDatabaseSizesAllShards(batchSize: number = 50): Promise<ShardSizeResult[]> {\n\tconst config = getConfig();\n\tconst normalizedBatchSize = normalizeBatchSize(batchSize);\n\tconst tasks: Array<() => Promise<ShardSizeResult>> = [];\n\n\tfor (const [binding, db] of Object.entries(config.shards)) {\n\t\tif (!binding || !db) {\n\t\t\tcontinue;\n\t\t}\n\n\t\ttasks.push(async () => {\n\t\t\ttry {\n\t\t\t\treturn {\n\t\t\t\t\tshard: binding,\n\t\t\t\t\tsize: await getDatabaseSize(db),\n\t\t\t\t\tsuccess: true\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tshard: binding,\n\t\t\t\t\tsize: null,\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: error instanceof Error ? error.message : String(error)\n\t\t\t\t};\n\t\t\t}\n\t\t});\n\t}\n\n\tconst results: ShardSizeResult[] = [];\n\tfor (let i = 0; i < tasks.length; i += normalizedBatchSize) {\n\t\tconst batch = tasks.slice(i, i + normalizedBatchSize).map((task) => task());\n\t\tresults.push(...(await Promise.all(batch)));\n\t}\n\n\treturn results;\n}\n\n/**\n * Gets the combined size in bytes across all shards.\n *\n * Failed shard size checks are excluded from the sum.\n *\n * @param batchSize - Number of concurrent shard queries (default: 50)\n * @returns Total size in bytes across successfully measured shards\n * @since 1.1.4\n */\nexport async function getTotalDatabaseSize(batchSize: number = 50): Promise<number> {\n\tconst sizes = await getDatabaseSizesAllShards(batchSize);\n\treturn sizes.reduce((sum, result) => sum + (result.size ?? 0), 0);\n}\n",
9
- "/**\n * @fileoverview Durable Object for coordinating shard allocation and maintaining statistics\n *\n * This module provides the ShardCoordinator Durable Object that manages shard allocation\n * strategies and maintains real-time statistics about shard utilization. It provides\n * an HTTP API for other parts of the system to interact with the coordinator.\n *\n * @example\n * ```typescript\n * // In wrangler.jsonc:\n * // {\n * // \"durable_objects\": {\n * // \"bindings\": [\n * // { \"name\": \"ShardCoordinator\", \"class_name\": \"ShardCoordinator\" }\n * // ]\n * // }\n * // }\n *\n * // Usage in a Worker:\n * const coordinatorId = env.ShardCoordinator.idFromName('default');\n * const coordinator = env.ShardCoordinator.get(coordinatorId);\n * const response = await coordinator.fetch('http://coordinator/allocate', {\n * method: 'POST',\n * body: JSON.stringify({ primaryKey: 'user-123', strategy: 'hash' })\n * });\n * ```\n *\n * @author CollegeDB Team\n * @since 1.0.0\n */\n\nimport type { DurableObjectState } from '@cloudflare/workers-types';\nimport { CollegeDBError } from './errors';\nimport type { D1Region, MixedShardingStrategy, OperationType, ShardCoordinatorState, ShardingStrategy } from './types';\n\n/**\n * Durable Object for coordinating shard allocation and maintaining statistics\n *\n * The ShardCoordinator is a Cloudflare Durable Object that provides centralized\n * coordination for shard allocation across multiple D1 databases. It maintains\n * state about available shards, allocation strategies, and usage statistics.\n *\n * Key responsibilities:\n * - Track available D1 shards and their current load\n * - Implement allocation strategies (round-robin, random, hash-based)\n * - Provide HTTP API for shard allocation and management\n * - Maintain persistent state using Durable Object storage\n *\n * @example\n * ```typescript\n * // Allocate a shard for a new primary key\n * const response = await coordinator.fetch('http://coordinator/allocate', {\n * method: 'POST',\n * body: JSON.stringify({ primaryKey: 'user-456', strategy: 'hash' })\n * });\n * const { shard } = await response.json();\n * ```\n */\nexport class ShardCoordinator {\n\t/**\n\t * Durable Object state handle for persistent storage\n\t * @private\n\t */\n\tprivate state: DurableObjectState;\n\n\t/**\n\t * Creates a new ShardCoordinator instance\n\t * @param state - Durable Object state provided by Cloudflare runtime\n\t */\n\tconstructor(state: DurableObjectState) {\n\t\tthis.state = state;\n\t}\n\n\t/**\n\t * Gets the current coordinator state from persistent storage\n\t *\n\t * Retrieves the coordinator state from Durable Object storage, returning\n\t * a default state if none exists. The state includes known shards, statistics,\n\t * allocation strategy, and round-robin counter.\n\t *\n\t * @private\n\t * @returns Promise resolving to the current coordinator state\n\t * @throws {Error} If storage access fails\n\t */\n\tprivate async getState(): Promise<ShardCoordinatorState> {\n\t\tconst state = await this.state.storage.get<ShardCoordinatorState>('coordinator_state');\n\t\treturn (\n\t\t\tstate || {\n\t\t\t\tknownShards: [],\n\t\t\t\tshardStats: {},\n\t\t\t\tstrategy: 'round-robin',\n\t\t\t\troundRobinIndex: 0\n\t\t\t}\n\t\t);\n\t}\n\n\t/**\n\t * Saves the coordinator state to persistent storage\n\t *\n\t * Persists the coordinator state to Durable Object storage. This includes\n\t * all shard information, statistics, and configuration.\n\t *\n\t * @private\n\t * @param state - The coordinator state to persist\n\t * @returns Promise that resolves when state is saved\n\t * @throws {Error} If storage write fails\n\t */\n\tprivate async saveState(state: ShardCoordinatorState): Promise<void> {\n\t\tawait this.state.storage.put('coordinator_state', state);\n\t}\n\n\t/**\n\t * Handles HTTP requests to the Durable Object\n\t *\n\t * Main entry point for all HTTP requests to the ShardCoordinator. Routes\n\t * requests based on method and path to appropriate handler functions.\n\t *\n\t * Supported endpoints:\n\t * - GET /shards - List all known shards\n\t * - POST /shards - Add a new shard\n\t * - DELETE /shards - Remove a shard\n\t * - GET /stats - Get shard statistics\n\t * - POST /stats - Update shard statistics\n\t * - POST /allocate - Allocate a shard for a primary key\n\t * - POST /flush - Clear all coordinator state (development only)\n\t * - GET /health - Health check endpoint\n\t *\n\t * @param request - The incoming HTTP request\n\t * @returns Promise resolving to HTTP response\n\t * @example\n\t * ```typescript\n\t * // Allocate a shard\n\t * const response = await coordinator.fetch('http://coordinator/allocate', {\n\t * method: 'POST',\n\t * headers: { 'Content-Type': 'application/json' },\n\t * body: JSON.stringify({ primaryKey: 'user-123' })\n\t * });\n\t * ```\n\t */\n\tasync fetch(request: Request): Promise<Response> {\n\t\tconst url = new URL(request.url);\n\t\tconst path = url.pathname;\n\t\tconst method = request.method;\n\n\t\ttry {\n\t\t\tswitch (`${method} ${path}`) {\n\t\t\t\tcase 'GET /shards':\n\t\t\t\t\treturn this.handleListShards();\n\t\t\t\tcase 'POST /shards':\n\t\t\t\t\treturn this.handleAddShard(request);\n\t\t\t\tcase 'DELETE /shards':\n\t\t\t\t\treturn this.handleRemoveShard(request);\n\t\t\t\tcase 'GET /stats':\n\t\t\t\t\treturn this.handleGetStats();\n\t\t\t\tcase 'POST /stats':\n\t\t\t\t\treturn this.handleUpdateStats(request);\n\t\t\t\tcase 'POST /allocate':\n\t\t\t\t\treturn this.handleAllocateShard(request);\n\t\t\t\tcase 'POST /flush':\n\t\t\t\t\treturn this.handleFlush();\n\t\t\t\tcase 'GET /health':\n\t\t\t\t\treturn new Response('OK', { status: 200 });\n\t\t\t\tdefault:\n\t\t\t\t\treturn new Response('Not Found', { status: 404 });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error('ShardCoordinator error:', error);\n\t\t\treturn new Response('Internal Server Error', { status: 500 });\n\t\t}\n\t}\n\n\t/**\n\t * Retrieves all known shards as a JSON array of all D1 binding names that have been registered\n\t * with the coordinator.\n\t * @private\n\t * @returns Promise resolving to HTTP response with shard list\n\t * @example Response body: `[\"db-east\", \"db-west\", \"db-central\"]`\n\t */\n\tprivate async handleListShards(): Promise<Response> {\n\t\tconst state = await this.getState();\n\t\treturn new Response(JSON.stringify(state.knownShards), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t});\n\t}\n\n\t/**\n\t * Registers a new D1 database binding with the coordinator. If the shard\n\t * is already known, this operation is idempotent. Initializes statistics\n\t * for the new shard.\n\t * @private\n\t * @param request - HTTP request containing shard binding name in JSON body\n\t * @returns Promise resolving to HTTP response indicating success\n\t * @throws {Error} If request body is invalid JSON\n\t * @example Request body: `{\"shard\": \"db-new-region\"}`\n\t */\n\tprivate async handleAddShard(request: Request): Promise<Response> {\n\t\tconst { shard } = (await request.json()) as { shard: string };\n\n\t\t// Validate required parameters\n\t\tif (!shard || typeof shard !== 'string') {\n\t\t\treturn new Response(JSON.stringify({ error: 'Missing or invalid shard parameter' }), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t\t});\n\t\t}\n\n\t\tconst state = await this.getState();\n\n\t\tif (!state.knownShards.includes(shard)) {\n\t\t\tstate.knownShards.push(shard);\n\t\t\tstate.shardStats[shard] = {\n\t\t\t\tbinding: shard,\n\t\t\t\tcount: 0,\n\t\t\t\tlastUpdated: Date.now()\n\t\t\t};\n\t\t\tawait this.saveState(state);\n\t\t}\n\n\t\treturn new Response(JSON.stringify({ success: true }), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t});\n\t}\n\n\t/**\n\t * Unregisters a D1 database binding from the coordinator. Removes the shard\n\t * from the known shards list and deletes its statistics. Adjusts the round-robin\n\t * index if necessary to prevent out-of-bounds access.\n\t * @private\n\t * @param request - HTTP request containing shard binding name in JSON body\n\t * @returns Promise resolving to HTTP response indicating success\n\t * @throws {Error} If request body is invalid JSON\n\t * @example Request body: `{\"shard\": \"db-old-region\"}`\n\t */\n\tprivate async handleRemoveShard(request: Request): Promise<Response> {\n\t\tconst { shard } = (await request.json()) as { shard: string };\n\n\t\t// Validate required parameters\n\t\tif (!shard || typeof shard !== 'string') {\n\t\t\treturn new Response(JSON.stringify({ error: 'Missing or invalid shard parameter' }), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t\t});\n\t\t}\n\n\t\tconst state = await this.getState();\n\n\t\tconst index = state.knownShards.indexOf(shard);\n\t\tif (index > -1) {\n\t\t\tstate.knownShards.splice(index, 1);\n\t\t\tdelete state.shardStats[shard];\n\t\t\t// Adjust round-robin index if necessary\n\t\t\tif (state.roundRobinIndex >= state.knownShards.length) {\n\t\t\t\tstate.roundRobinIndex = 0;\n\t\t\t}\n\t\t\tawait this.saveState(state);\n\t\t}\n\n\t\treturn new Response(JSON.stringify({ success: true }), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t});\n\t}\n\n\t/**\n\t * Returns an array of statistics for all known shards, including\n\t * binding names, key counts, and last updated timestamps.\n\t * @private\n\t * @returns Promise resolving to HTTP response with statistics array\n\t * @example Response body: `[{\"binding\": \"db-east\", \"count\": 1234, \"lastUpdated\": 1672531200000}]`\n\t */\n\tprivate async handleGetStats(): Promise<Response> {\n\t\tconst state = await this.getState();\n\t\tconst stats = Object.values(state.shardStats);\n\t\treturn new Response(JSON.stringify(stats), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t});\n\t}\n\n\t/**\n\t * Updates the key count and last updated timestamp for a specific shard.\n\t * Used by other parts of the system to report changes in shard utilization.\n\t * @private\n\t * @param request - HTTP request containing shard name and count in JSON body\n\t * @returns Promise resolving to HTTP response indicating success\n\t * @throws {Error} If request body is invalid JSON or shard doesn't exist\n\t * @example Request body: `{\"shard\": \"db-east\", \"count\": 1500}`\n\t */\n\tprivate async handleUpdateStats(request: Request): Promise<Response> {\n\t\tconst { shard, count } = (await request.json()) as { shard: string; count: number };\n\n\t\t// Validate required parameters\n\t\tif (!shard || typeof shard !== 'string') {\n\t\t\treturn new Response(JSON.stringify({ error: 'Missing or invalid shard parameter' }), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t\t});\n\t\t}\n\n\t\tif (count === undefined || typeof count !== 'number') {\n\t\t\treturn new Response(JSON.stringify({ error: 'Missing or invalid count parameter' }), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t\t});\n\t\t}\n\n\t\tconst state = await this.getState();\n\n\t\tif (state.shardStats[shard]) {\n\t\t\tstate.shardStats[shard].count = count;\n\t\t\tstate.shardStats[shard].lastUpdated = Date.now();\n\t\t\tawait this.saveState(state);\n\t\t}\n\n\t\treturn new Response(JSON.stringify({ success: true }), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t});\n\t}\n\n\t/**\n\t * Selects an appropriate shard for a new primary key using the specified\n\t * allocation strategy. Updates internal state for round-robin allocation.\n\t *\n\t * Supported strategies:\n\t * - round-robin: Cycles through shards in order\n\t * - random: Selects a random shard\n\t * - hash: Uses consistent hashing based on primary key\n\t *\n\t * @private\n\t * @param request - HTTP request containing primary key and optional strategy\n\t * @returns Promise resolving to HTTP response with selected shard\n\t * @throws {Error} If no shards are available or request body is invalid\n\t * @example Request body: `{\"primaryKey\": \"user-123\", \"strategy\": \"hash\"}`\n\t * @example Response body: `{\"shard\": \"db-west\"}`\n\t */\n\tprivate async handleAllocateShard(request: Request): Promise<Response> {\n\t\tconst { primaryKey, strategy, operationType, availableShards } = (await request.json()) as {\n\t\t\tprimaryKey: string;\n\t\t\tstrategy?: ShardingStrategy;\n\t\t\toperationType?: OperationType;\n\t\t\tavailableShards?: string[];\n\t\t};\n\n\t\tif (!primaryKey || typeof primaryKey !== 'string') {\n\t\t\treturn new Response(JSON.stringify({ error: 'Missing or invalid primaryKey parameter' }), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t\t});\n\t\t}\n\n\t\tconst state = await this.getState();\n\t\tconst eligibleShards = availableShards || state.knownShards;\n\n\t\tif (eligibleShards.length === 0) {\n\t\t\treturn new Response(JSON.stringify({ error: 'No shards available' }), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t\t});\n\t\t}\n\n\t\tconst effectiveStrategy = this.resolveStrategy(state.strategy, strategy, operationType || 'write');\n\t\tconst selectedShard = this.selectShard(primaryKey, state, effectiveStrategy, eligibleShards);\n\n\t\tif (effectiveStrategy === 'round-robin') {\n\t\t\tstate.roundRobinIndex = (state.roundRobinIndex + 1) % eligibleShards.length;\n\t\t\tawait this.saveState(state);\n\t\t}\n\n\t\treturn new Response(JSON.stringify({ shard: selectedShard }), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t});\n\t}\n\n\t/**\n\t * Completely clears all coordinator state from Durable Object storage.\n\t * This removes all shard registrations, statistics, and configuration.\n\t *\n\t * **WARNING**: This operation is destructive and should only be used\n\t * in development environments or during testing.\n\t *\n\t * @private\n\t * @returns Promise resolving to HTTP response indicating success\n\t * @example Response body: `{\"success\": true}`\n\t */\n\tprivate async handleFlush(): Promise<Response> {\n\t\tawait this.state.storage.deleteAll();\n\t\treturn new Response(JSON.stringify({ success: true }), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t});\n\t}\n\n\t/**\n\t * Resolves the effective sharding strategy for a given operation type\n\t *\n\t * @private\n\t * @param configStrategy - The strategy from state configuration\n\t * @param requestStrategy - Optional strategy override from request\n\t * @param operationType - The type of operation (read/write)\n\t * @returns The effective sharding strategy to use\n\t */\n\tprivate resolveStrategy(\n\t\tconfigStrategy: ShardingStrategy | MixedShardingStrategy,\n\t\trequestStrategy?: ShardingStrategy,\n\t\toperationType: OperationType = 'write'\n\t): ShardingStrategy {\n\t\t// Request strategy overrides everything\n\t\tif (requestStrategy) {\n\t\t\treturn requestStrategy;\n\t\t}\n\n\t\t// If config strategy is a string, use it for all operations\n\t\tif (typeof configStrategy === 'string') {\n\t\t\treturn configStrategy;\n\t\t}\n\n\t\t// If config strategy is a mixed strategy object, use the appropriate strategy for the operation type\n\t\treturn configStrategy[operationType];\n\t}\n\n\t/**\n\t * Implements the core shard selection logic for different allocation strategies.\n\t * Uses consistent algorithms to ensure predictable shard assignment.\n\t *\n\t * Strategy details:\n\t * - round-robin: Uses roundRobinIndex to cycle through shards\n\t * - random: Uses Math.random() for uniform distribution\n\t * - hash: Uses string hash function for consistent assignment\n\t *\n\t * @private\n\t * @param primaryKey - The primary key to allocate a shard for\n\t * @param state - Current coordinator state containing available shards\n\t * @param strategy - The allocation strategy to use\n\t * @param eligibleShards - Optional filtered list of shards to choose from\n\t * @returns The selected shard binding name\n\t * @throws {CollegeDBError} If no shards are available\n\t * @example\n\t * ```typescript\n\t * const shard = this.selectShard('user-123', state, 'hash');\n\t * // Returns: \"db-west\" (consistent for this key)\n\t * ```\n\t */\n\tprivate selectShard(primaryKey: string, state: ShardCoordinatorState, strategy: ShardingStrategy, eligibleShards?: string[]): string {\n\t\tconst shards = eligibleShards || state.knownShards;\n\n\t\tif (shards.length === 0) {\n\t\t\tthrow new CollegeDBError('No shards available', 'NO_SHARDS');\n\t\t}\n\n\t\tswitch (strategy) {\n\t\t\tcase 'round-robin':\n\t\t\t\treturn shards[state.roundRobinIndex] ?? shards[0]!;\n\t\t\tcase 'random':\n\t\t\t\treturn shards[Math.floor(Math.random() * shards.length)]!;\n\t\t\tcase 'hash': {\n\t\t\t\tlet hash = 0;\n\t\t\t\tfor (let i = 0; i < primaryKey.length; i++) {\n\t\t\t\t\tconst char = primaryKey.charCodeAt(i);\n\t\t\t\t\thash = (hash << 5) - hash + char;\n\t\t\t\t\thash = hash & hash; // Convert to 32-bit integer\n\t\t\t\t}\n\t\t\t\tconst index = Math.abs(hash) % shards.length;\n\t\t\t\treturn shards[index]!;\n\t\t\t}\n\t\t\tcase 'location': {\n\t\t\t\t// If location config missing, fallback to hash\n\t\t\t\tconst region = state.targetRegion;\n\t\t\t\tconst locations = state.shardLocations || {};\n\t\t\t\tconst located = shards.filter((s) => locations[s]);\n\t\t\t\tif (!region || located.length === 0) {\n\t\t\t\t\tlet h = 0;\n\t\t\t\t\tfor (let i = 0; i < primaryKey.length; i++) {\n\t\t\t\t\t\tconst c = primaryKey.charCodeAt(i);\n\t\t\t\t\t\th = (h << 5) - h + c;\n\t\t\t\t\t\th = h & h;\n\t\t\t\t\t}\n\t\t\t\t\tconst idx = Math.abs(h) % shards.length;\n\t\t\t\t\treturn shards[idx]!;\n\t\t\t\t}\n\n\t\t\t\t// Simple location scoring similar to router.ts\n\t\t\t\tconst coords: Record<D1Region, { lat: number; lon: number }> = {\n\t\t\t\t\t// Western North America - San Francisco, CA\n\t\t\t\t\twnam: { lat: 37.7749, lon: -122.4194 },\n\t\t\t\t\t// Eastern North America - Newark, NJ\n\t\t\t\t\tenam: { lat: 40.7357, lon: -74.1724 },\n\t\t\t\t\t// Western Europe - London, UK\n\t\t\t\t\tweur: { lat: 51.5074, lon: -0.1278 },\n\t\t\t\t\t// Eastern Europe - Warsaw, Poland\n\t\t\t\t\teeur: { lat: 52.2297, lon: 21.0122 },\n\t\t\t\t\t// Asia Pacific - Tokyo, Japan\n\t\t\t\t\tapac: { lat: 35.6762, lon: 139.6503 },\n\t\t\t\t\t// Oceania - Sydney, Australia\n\t\t\t\t\toc: { lat: -33.8688, lon: 151.2093 },\n\t\t\t\t\t// Middle East - Dubai, UAE\n\t\t\t\t\tme: { lat: 25.2048, lon: 55.2708 },\n\t\t\t\t\t// Africa - Johannesburg, South Africa\n\t\t\t\t\taf: { lat: -26.2041, lon: 28.0473 }\n\t\t\t\t};\n\n\t\t\t\tconst hasCoordKey = (obj: typeof coords, key: D1Region) => key in obj;\n\t\t\t\tconst getKey = (k: D1Region): keyof typeof coords => (hasCoordKey(coords, k) ? (k as keyof typeof coords) : 'wnam');\n\t\t\t\tconst dist = (from: D1Region, to: D1Region) => {\n\t\t\t\t\tconst a = coords[getKey(from)];\n\t\t\t\t\tconst b = coords[getKey(to)];\n\t\t\t\t\tconst lat = a.lat - b.lat;\n\t\t\t\t\tconst lon = a.lon - b.lon;\n\t\t\t\t\treturn Math.sqrt(lat * lat + lon * lon);\n\t\t\t\t};\n\n\t\t\t\tconst scores = located.map((shard) => {\n\t\t\t\t\tconst meta = locations[shard]!;\n\t\t\t\t\tconst distance = dist(region, meta.region);\n\t\t\t\t\tconst priority = meta.priority || 1;\n\t\t\t\t\treturn { shard, score: distance - priority * 0.1 };\n\t\t\t\t});\n\n\t\t\t\tscores.sort((a, b) => a.score - b.score);\n\t\t\t\tconst bestScore = scores[0]!.score;\n\t\t\t\tconst best = scores.filter((s) => Math.abs(s.score - bestScore) < 0.01);\n\t\t\t\tif (best.length === 1) return best[0]!.shard;\n\n\t\t\t\t// Tie-breaker by consistent hash\n\t\t\t\tlet h2 = 0;\n\t\t\t\tfor (let i = 0; i < primaryKey.length; i++) {\n\t\t\t\t\tconst c = primaryKey.charCodeAt(i);\n\t\t\t\t\th2 = (h2 << 5) - h2 + c;\n\t\t\t\t\th2 = h2 & h2;\n\t\t\t\t}\n\t\t\t\tconst idx2 = Math.abs(h2) % best.length;\n\t\t\t\treturn best[idx2]!.shard;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\treturn shards[0]!;\n\t\t}\n\t}\n\n\t/**\n\t * Atomically increments the key count for a specific shard and updates\n\t * the last modified timestamp. Used when new primary keys are assigned\n\t * to a shard.\n\t * @param shard - The shard binding name to increment\n\t * @returns Promise that resolves when the count is updated\n\t * @throws {Error} If the shard is not known to the coordinator\n\t * @example\n\t * ```typescript\n\t * await coordinator.incrementShardCount('db-east');\n\t * ```\n\t */\n\tasync incrementShardCount(shard: string): Promise<void> {\n\t\tconst state = await this.getState();\n\t\tif (state.shardStats[shard]) {\n\t\t\tstate.shardStats[shard].count++;\n\t\t\tstate.shardStats[shard].lastUpdated = Date.now();\n\t\t\tawait this.saveState(state);\n\t\t}\n\t}\n\n\t/**\n\t * Atomically decrements the key count for a specific shard and updates\n\t * the last modified timestamp. Used when primary keys are removed or\n\t * moved from a shard. Prevents negative counts.\n\t * @param shard - The shard binding name to decrement\n\t * @returns Promise that resolves when the count is updated\n\t * @throws {CollegeDBError} If the shard is not known to the coordinator\n\t * @example\n\t * ```typescript\n\t * await coordinator.decrementShardCount('db-west');\n\t * ```\n\t */\n\tasync decrementShardCount(shard: string): Promise<void> {\n\t\tconst state = await this.getState();\n\t\tif (state.shardStats[shard] && state.shardStats[shard].count > 0) {\n\t\t\tstate.shardStats[shard].count--;\n\t\t\tstate.shardStats[shard].lastUpdated = Date.now();\n\t\t\tawait this.saveState(state);\n\t\t}\n\t}\n}\n\n//#region Tests - Only run in test environment\nif (process.env.NODE_ENV === 'test' || typeof global !== 'undefined') {\n\t/**\n\t * Mock Durable Object Storage for testing\n\t */\n\tclass MockDurableObjectStorage {\n\t\tprivate data = new Map<string, any>();\n\n\t\tasync get<T = unknown>(key: string): Promise<T | undefined> {\n\t\t\treturn this.data.get(key);\n\t\t}\n\n\t\tasync put<T = unknown>(key: string, value: T): Promise<void> {\n\t\t\tthis.data.set(key, value);\n\t\t}\n\n\t\tasync delete(key: string): Promise<boolean> {\n\t\t\treturn this.data.delete(key);\n\t\t}\n\n\t\tasync deleteAll(): Promise<void> {\n\t\t\tthis.data.clear();\n\t\t}\n\n\t\tasync list(options?: { prefix?: string }): Promise<Map<string, any>> {\n\t\t\tif (!options?.prefix) return new Map(this.data);\n\n\t\t\tconst filtered = new Map();\n\t\t\tfor (const [key, value] of this.data.entries()) {\n\t\t\t\tif (key.startsWith(options.prefix)) {\n\t\t\t\t\tfiltered.set(key, value);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn filtered;\n\t\t}\n\t}\n\n\t/**\n\t * Mock Durable Object State for testing\n\t */\n\tclass MockDurableObjectState {\n\t\tstorage: MockDurableObjectStorage;\n\n\t\tconstructor() {\n\t\t\tthis.storage = new MockDurableObjectStorage();\n\t\t}\n\t}\n\n\t/**\n\t * Tests for ShardCoordinator class\n\t * These tests verify the core functionality of the ShardCoordinator\n\t * including state management, shard allocation, and HTTP API endpoints\n\t */\n\tclass ShardCoordinatorTests {\n\t\tprivate coordinator: ShardCoordinator;\n\t\tprivate mockState: MockDurableObjectState;\n\n\t\tconstructor() {\n\t\t\tthis.mockState = new MockDurableObjectState();\n\t\t\tthis.coordinator = new ShardCoordinator(this.mockState as any);\n\t\t}\n\n\t\t/**\n\t\t * Test shard allocation strategies\n\t\t */\n\t\tasync testShardAllocation() {\n\t\t\t// Add some shards first\n\t\t\tawait this.coordinator.fetch(\n\t\t\t\tnew Request('http://test/shards', {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\tbody: JSON.stringify({ shard: 'db-east' })\n\t\t\t\t})\n\t\t\t);\n\n\t\t\tawait this.coordinator.fetch(\n\t\t\t\tnew Request('http://test/shards', {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\tbody: JSON.stringify({ shard: 'db-west' })\n\t\t\t\t})\n\t\t\t);\n\n\t\t\t// Test round-robin allocation\n\t\t\tconst allocation1 = await this.coordinator.fetch(\n\t\t\t\tnew Request('http://test/allocate', {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\tbody: JSON.stringify({ primaryKey: 'user-1', strategy: 'round-robin' })\n\t\t\t\t})\n\t\t\t);\n\t\t\tconst result1 = (await allocation1.json()) as { shard: string };\n\n\t\t\tconst allocation2 = await this.coordinator.fetch(\n\t\t\t\tnew Request('http://test/allocate', {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\tbody: JSON.stringify({ primaryKey: 'user-2', strategy: 'round-robin' })\n\t\t\t\t})\n\t\t\t);\n\t\t\tconst result2 = (await allocation2.json()) as { shard: string };\n\n\t\t\t// Should allocate to different shards with round-robin\n\t\t\tconsole.assert(result1.shard !== result2.shard, 'Round-robin should alternate shards');\n\n\t\t\t// Test hash allocation (should be consistent)\n\t\t\tconst hashAllocation1 = await this.coordinator.fetch(\n\t\t\t\tnew Request('http://test/allocate', {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\tbody: JSON.stringify({ primaryKey: 'consistent-key', strategy: 'hash' })\n\t\t\t\t})\n\t\t\t);\n\t\t\tconst hashResult1 = (await hashAllocation1.json()) as { shard: string };\n\n\t\t\tconst hashAllocation2 = await this.coordinator.fetch(\n\t\t\t\tnew Request('http://test/allocate', {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\tbody: JSON.stringify({ primaryKey: 'consistent-key', strategy: 'hash' })\n\t\t\t\t})\n\t\t\t);\n\t\t\tconst hashResult2 = (await hashAllocation2.json()) as { shard: string };\n\n\t\t\t// Hash should be consistent for same key\n\t\t\tconsole.assert(hashResult1.shard === hashResult2.shard, 'Hash allocation should be consistent');\n\n\t\t\tconsole.log('✅ Shard allocation tests passed');\n\t\t}\n\n\t\t/**\n\t\t * Test shard statistics management\n\t\t */\n\t\tasync testShardStats() {\n\t\t\t// Clear state\n\t\t\tawait this.coordinator.fetch(new Request('http://test/flush', { method: 'POST' }));\n\n\t\t\t// Add shard\n\t\t\tawait this.coordinator.fetch(\n\t\t\t\tnew Request('http://test/shards', {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\tbody: JSON.stringify({ shard: 'db-stats-test' })\n\t\t\t\t})\n\t\t\t);\n\n\t\t\t// Update stats\n\t\t\tawait this.coordinator.fetch(\n\t\t\t\tnew Request('http://test/stats', {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\tbody: JSON.stringify({ shard: 'db-stats-test', count: 42 })\n\t\t\t\t})\n\t\t\t);\n\n\t\t\t// Get stats\n\t\t\tconst statsResponse = await this.coordinator.fetch(new Request('http://test/stats', { method: 'GET' }));\n\t\t\tconst stats = (await statsResponse.json()) as Array<{ binding: string; count: number }>;\n\n\t\t\tconsole.assert(stats.length === 1, 'Should have one shard stat');\n\t\t\tconsole.assert(stats[0]?.binding === 'db-stats-test', 'Should have correct binding name');\n\t\t\tconsole.assert(stats[0]?.count === 42, 'Should have correct count');\n\n\t\t\tconsole.log('✅ Shard stats tests passed');\n\t\t}\n\n\t\t/**\n\t\t * Test error handling\n\t\t */\n\t\tasync testErrorHandling() {\n\t\t\t// Clear state\n\t\t\tawait this.coordinator.fetch(new Request('http://test/flush', { method: 'POST' }));\n\n\t\t\t// Try to allocate with no shards\n\t\t\tconst emptyAllocation = await this.coordinator.fetch(\n\t\t\t\tnew Request('http://test/allocate', {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\tbody: JSON.stringify({ primaryKey: 'test-key' })\n\t\t\t\t})\n\t\t\t);\n\n\t\t\tconsole.assert(emptyAllocation.status === 400, 'Should return 400 for no shards available');\n\n\t\t\t// Test invalid endpoint\n\t\t\tconst invalidEndpoint = await this.coordinator.fetch(new Request('http://test/invalid', { method: 'GET' }));\n\t\t\tconsole.assert(invalidEndpoint.status === 404, 'Should return 404 for invalid endpoint');\n\n\t\t\tconsole.log('✅ Error handling tests passed');\n\t\t}\n\n\t\t/**\n\t\t * Test the increment/decrement functionality\n\t\t */\n\t\tasync testCountManagement() {\n\t\t\t// Add a shard\n\t\t\tawait this.coordinator.fetch(\n\t\t\t\tnew Request('http://test/shards', {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\tbody: JSON.stringify({ shard: 'db-count-test' })\n\t\t\t\t})\n\t\t\t);\n\n\t\t\t// Increment count\n\t\t\tawait this.coordinator.incrementShardCount('db-count-test');\n\t\t\tawait this.coordinator.incrementShardCount('db-count-test');\n\n\t\t\t// Check stats\n\t\t\tlet statsResponse = await this.coordinator.fetch(new Request('http://test/stats', { method: 'GET' }));\n\t\t\tlet stats = (await statsResponse.json()) as Array<{ binding: string; count: number }>;\n\n\t\t\tconst shard = stats.find((s) => s.binding === 'db-count-test');\n\t\t\tconsole.assert(shard?.count === 2, 'Count should be 2 after two increments');\n\n\t\t\t// Decrement count\n\t\t\tawait this.coordinator.decrementShardCount('db-count-test');\n\n\t\t\tstatsResponse = await this.coordinator.fetch(new Request('http://test/stats', { method: 'GET' }));\n\t\t\tstats = (await statsResponse.json()) as Array<{ binding: string; count: number }>;\n\n\t\t\tconst updatedShard = stats.find((s) => s.binding === 'db-count-test');\n\t\t\tconsole.assert(updatedShard?.count === 1, 'Count should be 1 after decrement');\n\n\t\t\tconsole.log('✅ Count management tests passed');\n\t\t}\n\n\t\t/**\n\t\t * Run all tests\n\t\t */\n\t\tasync runAllTests() {\n\t\t\tconsole.log('🧪 Running ShardCoordinator tests...');\n\n\t\t\ttry {\n\t\t\t\tawait this.testShardAllocation();\n\t\t\t\tawait this.testShardStats();\n\t\t\t\tawait this.testErrorHandling();\n\t\t\t\tawait this.testCountManagement();\n\n\t\t\t\tconsole.log('🎉 All ShardCoordinator tests passed!');\n\t\t\t\treturn true;\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('❌ ShardCoordinator tests failed:', error);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Auto-run tests if this file is executed directly\n\tif (typeof require !== 'undefined' && require.main === module) {\n\t\tconst tests = new ShardCoordinatorTests();\n\t\ttests.runAllTests().then((success) => {\n\t\t\tprocess.exit(success ? 0 : 1);\n\t\t});\n\t}\n\n\t// Export for external testing\n\t(globalThis as any).testShardCoordinator = () => new ShardCoordinatorTests();\n}\n//#endregion\n",
10
- "/**\n * CollegeDB - Cloudflare D1 Sharding Router\n *\n * A TypeScript library for horizontal scaling of SQLite-style databases on Cloudflare\n * using D1 and KV. Routes queries to the correct D1 database instance using primary\n * key mappings stored in Cloudflare KV.\n *\n * @author Gregory Mitchell\n * @license MIT\n */\n\n// Export main API functions\nexport {\n\tall,\n\tallAllShards,\n\tallAllShardsGlobal,\n\tallByLookupKey,\n\tallShard,\n\tcollegedb,\n\tcount,\n\tcountAllShards,\n\tcountShard,\n\tcreateSchema,\n\texplain,\n\texplainAllShards,\n\texplainShard,\n\tfirst,\n\tfirstAllShards,\n\tfirstAllShardsGlobal,\n\tfirstByLookupKey,\n\tfirstShard,\n\tflush,\n\tgetClosestRegionFromIP,\n\tgetDatabaseSizeForKey,\n\tgetDatabaseSizeForShard,\n\tgetDatabaseSizesAllShards,\n\tgetShardStats,\n\tgetTotalDatabaseSize,\n\tindex,\n\tindexAllShards,\n\tindexShard,\n\tinitialize,\n\tinitializeAsync,\n\tlistKnownShards,\n\tprepare,\n\treassignShard,\n\tresetConfig,\n\trun,\n\trunAllShards,\n\trunShard\n} from './router';\n\nexport type {\n\tCreateIndexOptions,\n\tExplainOptions,\n\tGlobalAllShardsOptions,\n\tIndexColumnDefinition,\n\tShardSizeResult,\n\tShardTableCount\n} from './router';\n\n// Export utility classes\nexport { ShardCoordinator } from './durable';\nexport { CollegeDBError } from './errors';\nexport { KVShardMapper } from './kvmap';\n\n// Export provider adapters\nexport {\n\tcreateDrizzleSQLProvider,\n\tcreateHyperdriveMySQLProvider,\n\tcreateHyperdrivePostgresProvider,\n\tcreateMySQLProvider,\n\tcreateNuxtHubKVProvider,\n\tcreatePostgreSQLProvider,\n\tcreateRedisKVProvider,\n\tcreateSQLiteProvider,\n\tcreateValkeyKVProvider,\n\tisKVStorage,\n\tisSQLDatabase,\n\ttype DrizzleClientLike,\n\ttype DrizzleSqlChunkLike,\n\ttype DrizzleSqlTagLike,\n\ttype HyperdriveBindingLike,\n\ttype HyperdriveMySQLClientFactory,\n\ttype HyperdrivePostgresClientFactory,\n\ttype MySQLClientLike,\n\ttype NuxtHubKVLike,\n\ttype PostgresClientLike,\n\ttype RedisLikeClient,\n\ttype SQLiteClientLike\n} from './providers';\n\n// Export migration functions\nexport {\n\tautoDetectAndMigrate,\n\tcheckMigrationNeeded,\n\tclearMigrationCache,\n\tclearShardMigrationCache,\n\tcreateMappingsForExistingKeys,\n\tcreateSchemaAcrossShards,\n\tdiscoverExistingPrimaryKeys,\n\tdiscoverExistingRecordsWithColumns,\n\tdropSchema,\n\tintegrateExistingDatabase,\n\tlistTables,\n\tmigrateRecord,\n\tschemaExists,\n\tvalidateTableForSharding,\n\ttype IntegrationOptions,\n\ttype IntegrationResult,\n\ttype ValidationResult\n} from './migrations';\n\n// Export types\nexport type {\n\tCollegeDBConfig,\n\tD1Region,\n\tEnv,\n\tKVListResult,\n\tKVStorage,\n\tMixedShardingStrategy,\n\tOperationType,\n\tPreparedStatement,\n\tQueryResult,\n\tQueryResultMeta,\n\tSQLDatabase,\n\tShardCoordinatorState,\n\tShardLocation,\n\tShardMapping,\n\tShardStats,\n\tShardingStrategy\n} from './types';\n",
11
- "/**\n * @fileoverview Provider adapters for non-Cloudflare backends.\n *\n * This module defines maintainable adapter factories that allow CollegeDB to run\n * on multiple storage backends while preserving Cloudflare compatibility.\n *\n * Supported KV backends:\n * - Cloudflare KV (native shape)\n * - Redis\n * - Valkey\n * - NuxtHub KV / Unstorage-compatible clients\n *\n * Supported SQL backends:\n * - Cloudflare D1 (native shape)\n * - PostgreSQL compatible clients\n * - MySQL / MariaDB compatible clients\n * - SQLite clients\n * - Drizzle ORM database instances\n * - Hyperdrive-backed PostgreSQL / MySQL clients\n *\n * @author CollegeDB Team\n * @since 1.1.0\n */\n\nimport { CollegeDBError } from './errors';\nimport type { KVListResult, KVStorage, PreparedStatement, QueryResult, QueryResultMeta, SQLDatabase } from './types';\n\nconst DEFAULT_REDIS_SCAN_COUNT = 500;\n\n/**\n * Minimal Redis/Valkey client contract used by the KV adapter.\n */\nexport interface RedisLikeClient {\n\tget(key: string): Promise<string | null>;\n\tset(key: string, value: string): unknown | Promise<unknown>;\n\tdel(key: string): unknown | Promise<unknown>;\n\tscan(cursor: string, ...args: any[]): RedisScanResult | Promise<RedisScanResult>;\n}\n\n/**\n * Redis/Valkey SCAN response in ioredis tuple form.\n */\nexport type RedisScanTupleResult = [string, string[]];\n\n/**\n * Redis/Valkey SCAN response in node-redis object form.\n */\nexport interface RedisScanObjectResult {\n\tcursor: string | number;\n\tkeys: string[];\n}\n\n/**\n * Accepted SCAN response formats.\n */\nexport type RedisScanResult = RedisScanTupleResult | RedisScanObjectResult;\n\n/**\n * PostgreSQL result shape used by adapters.\n */\nexport interface PostgresQueryResult<T = Record<string, unknown>> {\n\trows: T[];\n\trowCount?: number | null;\n\tcommand?: string;\n\t[key: string]: unknown;\n}\n\n/**\n * Minimal PostgreSQL client contract used by the SQL adapter.\n */\nexport interface PostgresClientLike {\n\tquery<T = Record<string, unknown>>(sql: string, bindings?: any[]): Promise<PostgresQueryResult<T>>;\n}\n\n/**\n * Optional lifecycle methods used by Hyperdrive helpers.\n */\nexport interface PostgresLifecycleClientLike extends PostgresClientLike {\n\tconnect?: () => void | Promise<void>;\n\tend?: () => void | Promise<void>;\n\trelease?: () => void;\n}\n\n/**\n * MySQL/MariaDB OK packet shape.\n */\nexport interface MySQLOkPacket {\n\taffectedRows?: number;\n\tinsertId?: number;\n\twarningStatus?: number;\n\t[key: string]: unknown;\n}\n\n/**\n * Minimal MySQL/MariaDB client contract used by adapters.\n */\nexport interface MySQLClientLike {\n\texecute?: (sql: string, bindings?: any[]) => any | Promise<any>;\n\tquery?: (sql: string, bindings?: any[]) => any | Promise<any>;\n}\n\n/**\n * Optional lifecycle methods used by Hyperdrive helpers.\n */\nexport interface MySQLLifecycleClientLike extends MySQLClientLike {\n\tend?: () => void | Promise<void>;\n\tclose?: () => void | Promise<void>;\n\tdestroy?: () => void;\n}\n\n/**\n * Statement contract for SQLite adapters.\n */\nexport interface SQLiteStatementLike {\n\trun?: (...bindings: any[]) => unknown | Promise<unknown>;\n\tall?: (...bindings: any[]) => unknown[] | Promise<unknown[]>;\n\tget?: (...bindings: any[]) => unknown | Promise<unknown>;\n}\n\n/**\n * Minimal SQLite client contract used by adapters.\n */\nexport interface SQLiteClientLike {\n\tprepare?: (sql: string) => SQLiteStatementLike;\n\texecute?: (sql: string, bindings?: any[]) => any | Promise<any>;\n}\n\n/**\n * Hyperdrive binding shape used by helper factories.\n */\nexport interface HyperdriveBindingLike {\n\tconnectionString: string;\n\tlocalConnectionString?: string;\n}\n\n/**\n * Factory for creating PostgreSQL clients from a Hyperdrive connection string.\n */\nexport type HyperdrivePostgresClientFactory = (connectionString: string) => PostgresLifecycleClientLike;\n\n/**\n * Factory for creating MySQL clients from a Hyperdrive connection string.\n */\nexport type HyperdriveMySQLClientFactory = (connectionString: string) => MySQLLifecycleClientLike;\n\n/**\n * Minimal SQL chunk contract produced by Drizzle's `sql` helper.\n */\nexport interface DrizzleSqlChunkLike {\n\tappend(chunk: DrizzleSqlChunkLike): void;\n}\n\n/**\n * Minimal Drizzle `sql` tag contract used to build parameterized raw statements.\n */\nexport interface DrizzleSqlTagLike {\n\t(strings: TemplateStringsArray, ...params: any[]): DrizzleSqlChunkLike;\n\traw(sql: string): DrizzleSqlChunkLike;\n\tempty?: () => DrizzleSqlChunkLike;\n}\n\n/**\n * Minimal Drizzle database contract used by the SQL adapter.\n */\nexport interface DrizzleClientLike {\n\texecute?: (query: any) => any | Promise<any>;\n\trun?: (query: any) => any | Promise<any>;\n\tall?: (query: any) => any | Promise<any>;\n\tget?: (query: any) => any | Promise<any>;\n}\n\n/**\n * NuxtHub/Unstorage-like KV contract used by the adapter.\n */\nexport interface NuxtHubKVLike {\n\tget?<T = any>(key: string): T | null | undefined | Promise<T | null | undefined>;\n\tset?(key: string, value: any, options?: { ttl?: number }): any | Promise<any>;\n\tdel?(key: string): any | Promise<any>;\n\tkeys?(prefix?: string): string[] | readonly string[] | Promise<string[] | readonly string[]>;\n\tgetItem?<T = any>(key: string): T | null | undefined | Promise<T | null | undefined>;\n\tsetItem?(key: string, value: any): any | Promise<any>;\n\tremoveItem?(key: string): any | Promise<any>;\n\tgetKeys?(prefix?: string): string[] | readonly string[] | Promise<string[] | readonly string[]>;\n}\n\n/**\n * Creates a Redis-backed KV provider adapter.\n *\n * The adapter supports both node-redis and ioredis scan formats.\n *\n * @param client - Redis/Valkey client\n * @param options - Adapter tuning options\n * @returns KVStorage-compatible adapter\n */\nexport function createRedisKVProvider(client: RedisLikeClient, options: { scanCount?: number } = {}): KVStorage {\n\tconst scanCount = options.scanCount ?? DEFAULT_REDIS_SCAN_COUNT;\n\n\treturn {\n\t\tasync get<T = unknown>(key: string, type: 'text' | 'json' = 'text'): Promise<T | string | null> {\n\t\t\tconst raw = await client.get(key);\n\t\t\tif (raw === null) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif (type !== 'json') {\n\t\t\t\treturn raw;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(raw) as T;\n\t\t\t} catch (error) {\n\t\t\t\tthrow new CollegeDBError(\n\t\t\t\t\t`Failed to parse JSON from Redis for key ${key}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t'KV_JSON_PARSE_FAILED'\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\n\t\tasync put(key: string, value: string): Promise<void> {\n\t\t\tawait client.set(key, value);\n\t\t},\n\n\t\tasync delete(key: string): Promise<void> {\n\t\t\tawait client.del(key);\n\t\t},\n\n\t\tasync list(options?: { prefix?: string; cursor?: string; limit?: number }): Promise<KVListResult> {\n\t\t\tconst prefix = options?.prefix ?? '';\n\t\t\tconst pattern = `${prefix}*`;\n\t\t\tlet cursor = options?.cursor ?? '0';\n\t\t\tconst limit = options?.limit;\n\t\t\tconst keys: string[] = [];\n\n\t\t\tdo {\n\t\t\t\tconst scanResult = await executeRedisScan(client, cursor, pattern, scanCount);\n\t\t\t\tcursor = scanResult.cursor;\n\n\t\t\t\tfor (const key of scanResult.keys) {\n\t\t\t\t\tif (!prefix || key.startsWith(prefix)) {\n\t\t\t\t\t\tkeys.push(key);\n\t\t\t\t\t}\n\t\t\t\t\tif (limit && keys.length >= limit) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (limit && keys.length >= limit) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} while (cursor !== '0');\n\n\t\t\treturn {\n\t\t\t\tkeys: keys.map((name) => ({ name })),\n\t\t\t\tcursor,\n\t\t\t\tlist_complete: cursor === '0'\n\t\t\t};\n\t\t}\n\t};\n}\n\n/**\n * Creates a Valkey-backed KV provider adapter.\n *\n * Valkey and Redis have compatible command surfaces for this adapter.\n *\n * @param client - Valkey client\n * @param options - Adapter tuning options\n * @returns KVStorage-compatible adapter\n */\nexport function createValkeyKVProvider(client: RedisLikeClient, options: { scanCount?: number } = {}): KVStorage {\n\treturn createRedisKVProvider(client, options);\n}\n\n/**\n * Creates a PostgreSQL adapter implementing CollegeDB's SQL contract.\n *\n * Supports `pg` Client, Pool, and compatible implementations.\n * SQL using `?` placeholders is automatically rewritten to `$1..$n`.\n *\n * For Drizzle-backed PostgreSQL clients, pass the Drizzle DB instance as\n * `client` and the Drizzle `sql` helper as the second argument.\n *\n * @param client - PostgreSQL client/pool\n * @param sqlTag - Optional Drizzle `sql` helper for Drizzle interop\n * @returns SQLDatabase-compatible adapter\n */\nexport function createPostgreSQLProvider(client: PostgresClientLike): SQLDatabase;\nexport function createPostgreSQLProvider(client: DrizzleClientLike, sqlTag: DrizzleSqlTagLike): SQLDatabase;\nexport function createPostgreSQLProvider(client: PostgresClientLike | DrizzleClientLike, sqlTag?: DrizzleSqlTagLike): SQLDatabase {\n\tif (sqlTag) {\n\t\treturn createDrizzleSQLProvider(client as DrizzleClientLike, sqlTag);\n\t}\n\n\treturn {\n\t\tprepare(sql: string): PreparedStatement {\n\t\t\treturn new PostgresPreparedStatement(client as PostgresClientLike, sql);\n\t\t}\n\t};\n}\n\n/**\n * Creates a MySQL/MariaDB adapter implementing CollegeDB's SQL contract.\n *\n * Supports mysql2/promise clients, pools, and compatible wrappers.\n *\n * For Drizzle-backed MySQL/MariaDB clients, pass the Drizzle DB instance as\n * `client` and the Drizzle `sql` helper as the second argument.\n *\n * @param client - MySQL/MariaDB client or pool\n * @param sqlTag - Optional Drizzle `sql` helper for Drizzle interop\n * @returns SQLDatabase-compatible adapter\n */\nexport function createMySQLProvider(client: MySQLClientLike): SQLDatabase;\nexport function createMySQLProvider(client: DrizzleClientLike, sqlTag: DrizzleSqlTagLike): SQLDatabase;\nexport function createMySQLProvider(client: MySQLClientLike | DrizzleClientLike, sqlTag?: DrizzleSqlTagLike): SQLDatabase {\n\tif (sqlTag) {\n\t\treturn createDrizzleSQLProvider(client as DrizzleClientLike, sqlTag);\n\t}\n\n\treturn {\n\t\tprepare(sql: string): PreparedStatement {\n\t\t\treturn new MySQLPreparedStatement(client as MySQLClientLike, sql);\n\t\t}\n\t};\n}\n\n/**\n * Creates a SQLite adapter implementing CollegeDB's SQL contract.\n *\n * Supports both execute-style clients and prepare/run/get/all statement clients.\n *\n * For Drizzle-backed SQLite/D1 clients, pass the Drizzle DB instance as\n * `client` and the Drizzle `sql` helper as the second argument.\n *\n * @param client - SQLite client\n * @param sqlTag - Optional Drizzle `sql` helper for Drizzle interop\n * @returns SQLDatabase-compatible adapter\n */\nexport function createSQLiteProvider(client: SQLiteClientLike): SQLDatabase;\nexport function createSQLiteProvider(client: DrizzleClientLike, sqlTag: DrizzleSqlTagLike): SQLDatabase;\nexport function createSQLiteProvider(client: SQLiteClientLike | DrizzleClientLike, sqlTag?: DrizzleSqlTagLike): SQLDatabase {\n\tif (sqlTag) {\n\t\treturn createDrizzleSQLProvider(client as DrizzleClientLike, sqlTag);\n\t}\n\n\treturn {\n\t\tprepare(sql: string): PreparedStatement {\n\t\t\treturn new SQLitePreparedStatement(client as SQLiteClientLike, sql);\n\t\t}\n\t};\n}\n\n/**\n * Creates a Drizzle-backed SQL adapter implementing CollegeDB's SQL contract.\n *\n * This adapter enables using Drizzle database instances (including NuxtHub's\n * `db` from `@nuxthub/db` or `hub:db`) as shard providers while CollegeDB keeps\n * query routing and key->shard mapping responsibilities.\n *\n * @param client - Drizzle database instance\n * @param sqlTag - Drizzle `sql` helper from `drizzle-orm`\n * @returns SQLDatabase-compatible adapter\n */\nexport function createDrizzleSQLProvider(client: DrizzleClientLike, sqlTag: DrizzleSqlTagLike): SQLDatabase {\n\treturn {\n\t\tprepare(sql: string): PreparedStatement {\n\t\t\treturn new DrizzlePreparedStatement(client, sqlTag, sql);\n\t\t}\n\t};\n}\n\n/**\n * Creates a NuxtHub KV adapter implementing CollegeDB's KV contract.\n *\n * Supports both `@nuxthub/kv` (`get/set/del/keys`) and unstorage-like\n * implementations (`getItem/setItem/removeItem/getKeys`).\n *\n * @param client - NuxtHub KV/Unstorage-like client\n * @returns KVStorage-compatible adapter\n */\nexport function createNuxtHubKVProvider(client: NuxtHubKVLike): KVStorage {\n\treturn {\n\t\tasync get<T = unknown>(key: string, type: 'text' | 'json' = 'text'): Promise<T | string | null> {\n\t\t\tconst raw = await getNuxtHubKVValue(client, key);\n\t\t\tif (raw === null || raw === undefined) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif (type === 'json') {\n\t\t\t\tif (typeof raw === 'string') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn JSON.parse(raw) as T;\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthrow new CollegeDBError(\n\t\t\t\t\t\t\t`Failed to parse JSON from NuxtHub KV for key ${key}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t\t\t'KV_JSON_PARSE_FAILED'\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn raw as T;\n\t\t\t}\n\n\t\t\treturn typeof raw === 'string' ? raw : JSON.stringify(raw);\n\t\t},\n\n\t\tasync put(key: string, value: string): Promise<void> {\n\t\t\tawait setNuxtHubKVValue(client, key, value);\n\t\t},\n\n\t\tasync delete(key: string): Promise<void> {\n\t\t\tawait deleteNuxtHubKVValue(client, key);\n\t\t},\n\n\t\tasync list(options?: { prefix?: string; cursor?: string; limit?: number }): Promise<KVListResult> {\n\t\t\tconst prefix = options?.prefix ?? '';\n\t\t\tconst allKeys = await listNuxtHubKVKeys(client, prefix);\n\t\t\tconst limitedKeys = typeof options?.limit === 'number' ? allKeys.slice(0, options.limit) : allKeys;\n\n\t\t\treturn {\n\t\t\t\tkeys: limitedKeys.map((name) => ({ name })),\n\t\t\t\tlist_complete: true\n\t\t\t};\n\t\t}\n\t};\n}\n\n/**\n * Creates a PostgreSQL adapter wired to a Hyperdrive binding.\n *\n * The returned provider creates a transient client for each statement execution.\n * Hyperdrive handles connection pooling at the edge, so this pattern remains fast\n * and scalable in Workers.\n *\n * @param hyperdrive - Hyperdrive binding\n * @param clientFactory - Client factory (e.g. `connectionString => new Client({ connectionString })`)\n * @returns SQLDatabase-compatible adapter\n */\nexport function createHyperdrivePostgresProvider(\n\thyperdrive: HyperdriveBindingLike,\n\tclientFactory: HyperdrivePostgresClientFactory\n): SQLDatabase {\n\tconst delegatedClient: PostgresClientLike = {\n\t\tquery: async <T = Record<string, unknown>>(sql: string, bindings: any[] = []) => {\n\t\t\tconst client = clientFactory(hyperdrive.connectionString);\n\t\t\tif (typeof client.connect === 'function') {\n\t\t\t\tawait client.connect();\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\treturn await client.query<T>(sql, bindings);\n\t\t\t} finally {\n\t\t\t\tif (typeof client.release === 'function') {\n\t\t\t\t\tclient.release();\n\t\t\t\t} else if (typeof client.end === 'function') {\n\t\t\t\t\tawait client.end();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\treturn createPostgreSQLProvider(delegatedClient);\n}\n\n/**\n * Creates a MySQL/MariaDB adapter wired to a Hyperdrive binding.\n *\n * The returned provider creates a transient client for each statement execution.\n * Hyperdrive handles connection pooling under the hood.\n *\n * @param hyperdrive - Hyperdrive binding\n * @param clientFactory - Client factory (e.g. `connectionString => mysql.createConnection(connectionString)`)\n * @returns SQLDatabase-compatible adapter\n */\nexport function createHyperdriveMySQLProvider(hyperdrive: HyperdriveBindingLike, clientFactory: HyperdriveMySQLClientFactory): SQLDatabase {\n\tconst delegatedClient: MySQLClientLike = {\n\t\texecute: async (sql: string, bindings: any[] = []) => {\n\t\t\tconst client = clientFactory(hyperdrive.connectionString);\n\t\t\ttry {\n\t\t\t\tif (typeof client.execute === 'function') {\n\t\t\t\t\treturn await client.execute(sql, bindings);\n\t\t\t\t}\n\t\t\t\tif (typeof client.query === 'function') {\n\t\t\t\t\treturn await client.query(sql, bindings);\n\t\t\t\t}\n\n\t\t\t\tthrow new CollegeDBError('Hyperdrive MySQL client is missing execute/query methods', 'MYSQL_CLIENT_INVALID');\n\t\t\t} finally {\n\t\t\t\tif (typeof client.end === 'function') {\n\t\t\t\t\tawait client.end();\n\t\t\t\t} else if (typeof client.close === 'function') {\n\t\t\t\t\tawait client.close();\n\t\t\t\t} else if (typeof client.destroy === 'function') {\n\t\t\t\t\tclient.destroy();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\treturn createMySQLProvider(delegatedClient);\n}\n\n/**\n * Returns `true` when a value looks like an SQL database provider.\n */\nexport function isSQLDatabase(value: unknown): value is SQLDatabase {\n\tif (!value || typeof value !== 'object') {\n\t\treturn false;\n\t}\n\n\treturn typeof (value as SQLDatabase).prepare === 'function';\n}\n\n/**\n * Returns `true` when a value looks like a KV storage provider.\n */\nexport function isKVStorage(value: unknown): value is KVStorage {\n\tif (!value || typeof value !== 'object') {\n\t\treturn false;\n\t}\n\n\tconst kv = value as KVStorage;\n\treturn typeof kv.get === 'function' && typeof kv.put === 'function' && typeof kv.delete === 'function' && typeof kv.list === 'function';\n}\n\nclass PostgresPreparedStatement implements PreparedStatement {\n\tprivate readonly client: PostgresClientLike;\n\tprivate readonly sql: string;\n\tprivate readonly bindings: any[];\n\n\tconstructor(client: PostgresClientLike, sql: string, bindings: any[] = []) {\n\t\tthis.client = client;\n\t\tthis.sql = sql;\n\t\tthis.bindings = bindings;\n\t}\n\n\tbind(...bindings: any[]): PreparedStatement {\n\t\treturn new PostgresPreparedStatement(this.client, this.sql, bindings);\n\t}\n\n\tasync run<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\t\tconst sql = rewriteQuestionPlaceholders(this.sql);\n\t\tconst result = await this.client.query<T>(sql, this.bindings);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: result.rows ?? [],\n\t\t\tmeta: createMeta(startedAt, {\n\t\t\t\tchanges: typeof result.rowCount === 'number' ? result.rowCount : undefined,\n\t\t\t\tcommand: result.command\n\t\t\t})\n\t\t};\n\t}\n\n\tasync all<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\t\tconst sql = rewriteQuestionPlaceholders(this.sql);\n\t\tconst result = await this.client.query<T>(sql, this.bindings);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: result.rows ?? [],\n\t\t\tmeta: createMeta(startedAt, {\n\t\t\t\tchanges: typeof result.rowCount === 'number' ? result.rowCount : undefined,\n\t\t\t\tcommand: result.command\n\t\t\t})\n\t\t};\n\t}\n\n\tasync first<T = Record<string, unknown>>(): Promise<T | null> {\n\t\tconst sql = rewriteQuestionPlaceholders(this.sql);\n\t\tconst result = await this.client.query<T>(sql, this.bindings);\n\t\treturn result.rows?.[0] ?? null;\n\t}\n}\n\nclass MySQLPreparedStatement implements PreparedStatement {\n\tprivate readonly client: MySQLClientLike;\n\tprivate readonly sql: string;\n\tprivate readonly bindings: any[];\n\n\tconstructor(client: MySQLClientLike, sql: string, bindings: any[] = []) {\n\t\tthis.client = client;\n\t\tthis.sql = sql;\n\t\tthis.bindings = bindings;\n\t}\n\n\tbind(...bindings: any[]): PreparedStatement {\n\t\treturn new MySQLPreparedStatement(this.client, this.sql, bindings);\n\t}\n\n\tasync run<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\t\tconst rows = await executeMySQL(this.client, this.sql, this.bindings);\n\n\t\tif (Array.isArray(rows)) {\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tresults: rows as T[],\n\t\t\t\tmeta: createMeta(startedAt)\n\t\t\t};\n\t\t}\n\n\t\tconst packet = rows as MySQLOkPacket;\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: [],\n\t\t\tmeta: createMeta(startedAt, {\n\t\t\t\tchanges: packet.affectedRows,\n\t\t\t\tlast_row_id: packet.insertId,\n\t\t\t\twarningStatus: packet.warningStatus\n\t\t\t})\n\t\t};\n\t}\n\n\tasync all<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\t\tconst rows = await executeMySQL(this.client, this.sql, this.bindings);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: Array.isArray(rows) ? (rows as T[]) : [],\n\t\t\tmeta: createMeta(startedAt, {\n\t\t\t\tchanges: !Array.isArray(rows) ? (rows as MySQLOkPacket).affectedRows : undefined\n\t\t\t})\n\t\t};\n\t}\n\n\tasync first<T = Record<string, unknown>>(): Promise<T | null> {\n\t\tconst rows = await executeMySQL(this.client, this.sql, this.bindings);\n\t\tif (!Array.isArray(rows) || rows.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn rows[0] as T;\n\t}\n}\n\nclass SQLitePreparedStatement implements PreparedStatement {\n\tprivate readonly client: SQLiteClientLike;\n\tprivate readonly sql: string;\n\tprivate readonly bindings: any[];\n\n\tconstructor(client: SQLiteClientLike, sql: string, bindings: any[] = []) {\n\t\tthis.client = client;\n\t\tthis.sql = sql;\n\t\tthis.bindings = bindings;\n\t}\n\n\tbind(...bindings: any[]): PreparedStatement {\n\t\treturn new SQLitePreparedStatement(this.client, this.sql, bindings);\n\t}\n\n\tasync run<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\n\t\tif (typeof this.client.execute === 'function') {\n\t\t\tconst result = await this.client.execute(this.sql, this.bindings);\n\t\t\tconst rows = extractRowsFromSQLiteExecute<T>(result);\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tresults: rows,\n\t\t\t\tmeta: createMeta(startedAt)\n\t\t\t};\n\t\t}\n\n\t\tconst statement = this.client.prepare?.(this.sql);\n\t\tif (!statement || typeof statement.run !== 'function') {\n\t\t\tthrow new CollegeDBError('SQLite client must expose execute() or prepare().run()', 'SQLITE_CLIENT_INVALID');\n\t\t}\n\n\t\tconst runResult = await statement.run(...this.bindings);\n\t\tconst runMeta = (runResult ?? {}) as Record<string, unknown>;\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: [],\n\t\t\tmeta: createMeta(startedAt, {\n\t\t\t\tchanges: toMaybeNumber(runMeta.changes),\n\t\t\t\tlast_row_id: (runMeta.lastInsertRowid ?? runMeta.lastID) as number | string | undefined\n\t\t\t})\n\t\t};\n\t}\n\n\tasync all<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\n\t\tif (typeof this.client.execute === 'function') {\n\t\t\tconst result = await this.client.execute(this.sql, this.bindings);\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tresults: extractRowsFromSQLiteExecute<T>(result),\n\t\t\t\tmeta: createMeta(startedAt)\n\t\t\t};\n\t\t}\n\n\t\tconst statement = this.client.prepare?.(this.sql);\n\t\tif (!statement || typeof statement.all !== 'function') {\n\t\t\tthrow new CollegeDBError('SQLite client must expose execute() or prepare().all()', 'SQLITE_CLIENT_INVALID');\n\t\t}\n\n\t\tconst rows = await statement.all(...this.bindings);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: (Array.isArray(rows) ? rows : []) as T[],\n\t\t\tmeta: createMeta(startedAt)\n\t\t};\n\t}\n\n\tasync first<T = Record<string, unknown>>(): Promise<T | null> {\n\t\tif (typeof this.client.execute === 'function') {\n\t\t\tconst result = await this.client.execute(this.sql, this.bindings);\n\t\t\tconst rows = extractRowsFromSQLiteExecute<T>(result);\n\t\t\treturn rows[0] ?? null;\n\t\t}\n\n\t\tconst statement = this.client.prepare?.(this.sql);\n\t\tif (!statement) {\n\t\t\tthrow new CollegeDBError('SQLite client must expose execute() or prepare().get()', 'SQLITE_CLIENT_INVALID');\n\t\t}\n\n\t\tif (typeof statement.get === 'function') {\n\t\t\tconst row = await statement.get(...this.bindings);\n\t\t\treturn row === undefined || row === null ? null : (row as T);\n\t\t}\n\n\t\tif (typeof statement.all === 'function') {\n\t\t\tconst rows = await statement.all(...this.bindings);\n\t\t\tif (!Array.isArray(rows) || rows.length === 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst firstRow = rows[0];\n\t\t\treturn firstRow === undefined || firstRow === null ? null : (firstRow as T);\n\t\t}\n\n\t\tthrow new CollegeDBError('SQLite prepare() result must expose get() or all()', 'SQLITE_CLIENT_INVALID');\n\t}\n}\n\nclass DrizzlePreparedStatement implements PreparedStatement {\n\tprivate readonly client: DrizzleClientLike;\n\tprivate readonly sqlTag: DrizzleSqlTagLike;\n\tprivate readonly sqlText: string;\n\tprivate readonly bindings: any[];\n\n\tconstructor(client: DrizzleClientLike, sqlTag: DrizzleSqlTagLike, sqlText: string, bindings: any[] = []) {\n\t\tthis.client = client;\n\t\tthis.sqlTag = sqlTag;\n\t\tthis.sqlText = sqlText;\n\t\tthis.bindings = bindings;\n\t}\n\n\tbind(...bindings: any[]): PreparedStatement {\n\t\treturn new DrizzlePreparedStatement(this.client, this.sqlTag, this.sqlText, bindings);\n\t}\n\n\tasync run<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\t\tconst query = buildDrizzleQuery(this.sqlTag, this.sqlText, this.bindings);\n\t\tconst result = await executeDrizzleRun(this.client, query);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: extractRowsFromDrizzleExecute<T>(result),\n\t\t\tmeta: createMeta(startedAt, extractMetaFromDrizzleExecute(result))\n\t\t};\n\t}\n\n\tasync all<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\t\tconst query = buildDrizzleQuery(this.sqlTag, this.sqlText, this.bindings);\n\t\tconst result = await executeDrizzleAll(this.client, query);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: extractRowsFromDrizzleExecute<T>(result),\n\t\t\tmeta: createMeta(startedAt, extractMetaFromDrizzleExecute(result))\n\t\t};\n\t}\n\n\tasync first<T = Record<string, unknown>>(): Promise<T | null> {\n\t\tconst query = buildDrizzleQuery(this.sqlTag, this.sqlText, this.bindings);\n\t\tconst result = await executeDrizzleFirst(this.client, query);\n\t\tconst rows = extractRowsFromDrizzleExecute<T>(result);\n\t\tif (rows.length > 0) {\n\t\t\treturn rows[0] ?? null;\n\t\t}\n\n\t\tif (result && typeof result === 'object' && 'row' in result) {\n\t\t\tconst row = (result as Record<string, unknown>).row;\n\t\t\treturn row === undefined || row === null ? null : (row as T);\n\t\t}\n\n\t\tif (\n\t\t\tresult &&\n\t\t\ttypeof result === 'object' &&\n\t\t\t!Array.isArray(result) &&\n\t\t\t!('rows' in result) &&\n\t\t\t!('results' in result) &&\n\t\t\t!('data' in result)\n\t\t) {\n\t\t\treturn result as T;\n\t\t}\n\n\t\treturn null;\n\t}\n}\n\nasync function executeRedisScan(\n\tclient: RedisLikeClient,\n\tcursor: string,\n\tpattern: string,\n\tscanCount: number\n): Promise<{ cursor: string; keys: string[] }> {\n\ttry {\n\t\tconst objectResult = await client.scan(cursor, { MATCH: pattern, COUNT: scanCount });\n\t\treturn normalizeRedisScanResult(objectResult);\n\t} catch {\n\t\tconst tupleResult = await client.scan(cursor, 'MATCH', pattern, 'COUNT', String(scanCount));\n\t\treturn normalizeRedisScanResult(tupleResult);\n\t}\n}\n\nfunction normalizeRedisScanResult(result: RedisScanResult): { cursor: string; keys: string[] } {\n\tif (Array.isArray(result)) {\n\t\treturn {\n\t\t\tcursor: String(result[0] ?? '0'),\n\t\t\tkeys: Array.isArray(result[1]) ? result[1] : []\n\t\t};\n\t}\n\n\treturn {\n\t\tcursor: String(result.cursor ?? '0'),\n\t\tkeys: Array.isArray(result.keys) ? result.keys : []\n\t};\n}\n\nasync function executeMySQL(client: MySQLClientLike, sql: string, bindings: any[]): Promise<unknown> {\n\tif (typeof client.execute === 'function') {\n\t\tconst result = await client.execute(sql, bindings);\n\t\tif (Array.isArray(result)) {\n\t\t\treturn result[0];\n\t\t}\n\t\treturn result;\n\t}\n\n\tif (typeof client.query === 'function') {\n\t\tconst result = await client.query(sql, bindings);\n\t\tif (Array.isArray(result)) {\n\t\t\treturn result[0];\n\t\t}\n\t\treturn result;\n\t}\n\n\tthrow new CollegeDBError('MySQL client must expose execute() or query()', 'MYSQL_CLIENT_INVALID');\n}\n\nasync function executeDrizzleRun(client: DrizzleClientLike, query: DrizzleSqlChunkLike): Promise<unknown> {\n\tif (typeof client.run === 'function') {\n\t\treturn await client.run(query);\n\t}\n\n\tif (typeof client.execute === 'function') {\n\t\treturn await client.execute(query);\n\t}\n\n\tif (typeof client.all === 'function') {\n\t\treturn await client.all(query);\n\t}\n\n\tthrow new CollegeDBError('Drizzle client must expose run(), execute(), or all()', 'DRIZZLE_CLIENT_INVALID');\n}\n\nasync function executeDrizzleAll(client: DrizzleClientLike, query: DrizzleSqlChunkLike): Promise<unknown> {\n\tif (typeof client.all === 'function') {\n\t\treturn await client.all(query);\n\t}\n\n\tif (typeof client.execute === 'function') {\n\t\treturn await client.execute(query);\n\t}\n\n\tif (typeof client.run === 'function') {\n\t\treturn await client.run(query);\n\t}\n\n\tthrow new CollegeDBError('Drizzle client must expose all(), execute(), or run()', 'DRIZZLE_CLIENT_INVALID');\n}\n\nasync function executeDrizzleFirst(client: DrizzleClientLike, query: DrizzleSqlChunkLike): Promise<unknown> {\n\tif (typeof client.get === 'function') {\n\t\treturn await client.get(query);\n\t}\n\n\treturn await executeDrizzleAll(client, query);\n}\n\nfunction buildDrizzleQuery(sqlTag: DrizzleSqlTagLike, sqlText: string, bindings: any[]): DrizzleSqlChunkLike {\n\tconst segments = splitQuestionPlaceholders(sqlText);\n\tconst placeholderCount = segments.length - 1;\n\n\tif (placeholderCount !== bindings.length) {\n\t\tthrow new CollegeDBError(\n\t\t\t`Drizzle binding mismatch: expected ${placeholderCount} bindings, received ${bindings.length}`,\n\t\t\t'DRIZZLE_BINDINGS_MISMATCH'\n\t\t);\n\t}\n\n\tif (placeholderCount === 0) {\n\t\treturn sqlTag.raw(sqlText);\n\t}\n\n\tconst statement = typeof sqlTag.empty === 'function' ? sqlTag.empty() : sqlTag.raw('');\n\n\tfor (let i = 0; i < segments.length; i++) {\n\t\tconst segment = segments[i];\n\t\tif (segment) {\n\t\t\tstatement.append(sqlTag.raw(segment));\n\t\t}\n\n\t\tif (i < placeholderCount) {\n\t\t\tstatement.append(sqlTag`${bindings[i]}`);\n\t\t}\n\t}\n\n\treturn statement;\n}\n\nfunction splitQuestionPlaceholders(sql: string): string[] {\n\tconst segments: string[] = [];\n\tlet segmentStart = 0;\n\n\tlet inSingleQuote = false;\n\tlet inDoubleQuote = false;\n\tlet inLineComment = false;\n\tlet inBlockComment = false;\n\n\tfor (let i = 0; i < sql.length; i++) {\n\t\tconst char = sql[i]!;\n\t\tconst next = i + 1 < sql.length ? sql[i + 1] : '';\n\n\t\tif (inLineComment) {\n\t\t\tif (char === '\\n') {\n\t\t\t\tinLineComment = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (inBlockComment) {\n\t\t\tif (char === '*' && next === '/') {\n\t\t\t\ti++;\n\t\t\t\tinBlockComment = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!inSingleQuote && !inDoubleQuote) {\n\t\t\tif (char === '-' && next === '-') {\n\t\t\t\ti++;\n\t\t\t\tinLineComment = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (char === '/' && next === '*') {\n\t\t\t\ti++;\n\t\t\t\tinBlockComment = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (char === \"'\" && !inDoubleQuote) {\n\t\t\tif (inSingleQuote && next === \"'\") {\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tinSingleQuote = !inSingleQuote;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === '\"' && !inSingleQuote) {\n\t\t\tif (inDoubleQuote && next === '\"') {\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tinDoubleQuote = !inDoubleQuote;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === '?' && !inSingleQuote && !inDoubleQuote) {\n\t\t\tsegments.push(sql.slice(segmentStart, i));\n\t\t\tsegmentStart = i + 1;\n\t\t}\n\t}\n\n\tsegments.push(sql.slice(segmentStart));\n\treturn segments;\n}\n\nfunction extractRowsFromDrizzleExecute<T>(result: unknown): T[] {\n\tif (Array.isArray(result)) {\n\t\tif (result.length === 2 && Array.isArray(result[0])) {\n\t\t\treturn result[0] as T[];\n\t\t}\n\n\t\tif (\n\t\t\tresult.length === 2 &&\n\t\t\tresult[0] &&\n\t\t\ttypeof result[0] === 'object' &&\n\t\t\t!Array.isArray(result[0]) &&\n\t\t\t(Array.isArray(result[1]) || result[1] === null || result[1] === undefined)\n\t\t) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn result as T[];\n\t}\n\n\tif (result && typeof result === 'object') {\n\t\tconst objectResult = result as Record<string, unknown>;\n\n\t\tif (Array.isArray(objectResult.rows)) {\n\t\t\treturn objectResult.rows as T[];\n\t\t}\n\n\t\tif (Array.isArray(objectResult.results)) {\n\t\t\treturn objectResult.results as T[];\n\t\t}\n\n\t\tif (Array.isArray(objectResult.data)) {\n\t\t\treturn objectResult.data as T[];\n\t\t}\n\t}\n\n\treturn [];\n}\n\nfunction extractMetaFromDrizzleExecute(result: unknown): Record<string, unknown> {\n\tif (!result) {\n\t\treturn {};\n\t}\n\n\tlet objectResult: Record<string, unknown> | undefined;\n\n\tif (Array.isArray(result) && result.length === 2 && result[0] && typeof result[0] === 'object' && !Array.isArray(result[0])) {\n\t\tobjectResult = result[0] as Record<string, unknown>;\n\t} else if (typeof result === 'object' && !Array.isArray(result)) {\n\t\tobjectResult = result as Record<string, unknown>;\n\t}\n\n\tif (!objectResult) {\n\t\treturn {};\n\t}\n\n\tconst meta: Record<string, unknown> = {};\n\n\tconst changes = toMaybeNumber(objectResult.rowCount) ?? toMaybeNumber(objectResult.changes) ?? toMaybeNumber(objectResult.affectedRows);\n\tif (changes !== undefined) {\n\t\tmeta.changes = changes;\n\t}\n\n\tconst lastRowId = objectResult.lastInsertRowid ?? objectResult.lastInsertId ?? objectResult.insertId;\n\tif (typeof lastRowId === 'number' || typeof lastRowId === 'string') {\n\t\tmeta.last_row_id = lastRowId;\n\t}\n\n\tif (objectResult.meta && typeof objectResult.meta === 'object') {\n\t\tObject.assign(meta, objectResult.meta as Record<string, unknown>);\n\t}\n\n\treturn meta;\n}\n\nasync function getNuxtHubKVValue<T = unknown>(client: NuxtHubKVLike, key: string): Promise<T | null | undefined> {\n\tif (typeof client.get === 'function') {\n\t\treturn await client.get<T>(key);\n\t}\n\n\tif (typeof client.getItem === 'function') {\n\t\treturn await client.getItem<T>(key);\n\t}\n\n\tthrow new CollegeDBError('NuxtHub KV client must expose get() or getItem()', 'NUXTHUB_KV_CLIENT_INVALID');\n}\n\nasync function setNuxtHubKVValue(client: NuxtHubKVLike, key: string, value: string): Promise<void> {\n\tif (typeof client.set === 'function') {\n\t\tawait client.set(key, value);\n\t\treturn;\n\t}\n\n\tif (typeof client.setItem === 'function') {\n\t\tawait client.setItem(key, value);\n\t\treturn;\n\t}\n\n\tthrow new CollegeDBError('NuxtHub KV client must expose set() or setItem()', 'NUXTHUB_KV_CLIENT_INVALID');\n}\n\nasync function deleteNuxtHubKVValue(client: NuxtHubKVLike, key: string): Promise<void> {\n\tif (typeof client.del === 'function') {\n\t\tawait client.del(key);\n\t\treturn;\n\t}\n\n\tif (typeof client.removeItem === 'function') {\n\t\tawait client.removeItem(key);\n\t\treturn;\n\t}\n\n\tthrow new CollegeDBError('NuxtHub KV client must expose del() or removeItem()', 'NUXTHUB_KV_CLIENT_INVALID');\n}\n\nasync function listNuxtHubKVKeys(client: NuxtHubKVLike, prefix: string): Promise<string[]> {\n\tlet keys: readonly string[];\n\n\tif (typeof client.keys === 'function') {\n\t\tkeys = await client.keys(prefix);\n\t} else if (typeof client.getKeys === 'function') {\n\t\tkeys = await client.getKeys(prefix);\n\t} else {\n\t\tthrow new CollegeDBError('NuxtHub KV client must expose keys() or getKeys()', 'NUXTHUB_KV_CLIENT_INVALID');\n\t}\n\n\tif (!Array.isArray(keys)) {\n\t\treturn [];\n\t}\n\n\tif (!prefix) {\n\t\treturn [...keys];\n\t}\n\n\treturn keys.filter((key) => key.startsWith(prefix));\n}\n\nfunction extractRowsFromSQLiteExecute<T>(result: unknown): T[] {\n\tif (Array.isArray(result)) {\n\t\treturn result as T[];\n\t}\n\n\tif (result && typeof result === 'object') {\n\t\tconst objectResult = result as Record<string, unknown>;\n\n\t\tif (Array.isArray(objectResult.rows)) {\n\t\t\treturn objectResult.rows as T[];\n\t\t}\n\t\tif (Array.isArray(objectResult.results)) {\n\t\t\treturn objectResult.results as T[];\n\t\t}\n\t}\n\n\treturn [];\n}\n\nfunction createMeta(startedAt: number, extra: Record<string, unknown> = {}): QueryResultMeta {\n\treturn {\n\t\tduration: Date.now() - startedAt,\n\t\t...extra\n\t};\n}\n\nfunction toMaybeNumber(value: unknown): number | undefined {\n\tif (typeof value === 'number' && Number.isFinite(value)) {\n\t\treturn value;\n\t}\n\treturn undefined;\n}\n\nconst postgresPlaceholderCache = new Map<string, string>();\n\nfunction rewriteQuestionPlaceholders(sql: string): string {\n\tconst cached = postgresPlaceholderCache.get(sql);\n\tif (cached) {\n\t\treturn cached;\n\t}\n\n\tlet output = '';\n\tlet placeholderIndex = 0;\n\tlet inSingleQuote = false;\n\tlet inDoubleQuote = false;\n\tlet inLineComment = false;\n\tlet inBlockComment = false;\n\n\tfor (let i = 0; i < sql.length; i++) {\n\t\tconst char = sql[i]!;\n\t\tconst next = i + 1 < sql.length ? sql[i + 1] : '';\n\n\t\tif (inLineComment) {\n\t\t\toutput += char;\n\t\t\tif (char === '\\n') {\n\t\t\t\tinLineComment = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (inBlockComment) {\n\t\t\toutput += char;\n\t\t\tif (char === '*' && next === '/') {\n\t\t\t\toutput += '/';\n\t\t\t\ti++;\n\t\t\t\tinBlockComment = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!inSingleQuote && !inDoubleQuote) {\n\t\t\tif (char === '-' && next === '-') {\n\t\t\t\toutput += '--';\n\t\t\t\ti++;\n\t\t\t\tinLineComment = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (char === '/' && next === '*') {\n\t\t\t\toutput += '/*';\n\t\t\t\ti++;\n\t\t\t\tinBlockComment = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (char === \"'\" && !inDoubleQuote) {\n\t\t\tinSingleQuote = !inSingleQuote;\n\t\t\toutput += char;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === '\"' && !inSingleQuote) {\n\t\t\tinDoubleQuote = !inDoubleQuote;\n\t\t\toutput += char;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === '?' && !inSingleQuote && !inDoubleQuote) {\n\t\t\tplaceholderIndex++;\n\t\t\toutput += `$${placeholderIndex}`;\n\t\t\tcontinue;\n\t\t}\n\n\t\toutput += char;\n\t}\n\n\tpostgresPlaceholderCache.set(sql, output);\n\tif (postgresPlaceholderCache.size > 5000) {\n\t\tconst firstKey = postgresPlaceholderCache.keys().next().value;\n\t\tif (firstKey) {\n\t\t\tpostgresPlaceholderCache.delete(firstKey);\n\t\t}\n\t}\n\n\treturn output;\n}\n"
8
+ "/**\n * @fileoverview Main routing and query distribution logic for CollegeDB\n *\n * This module provides the core functionality for routing database queries to the\n * appropriate D1 shard based on primary key mappings. It handles shard selection,\n * database routing, and provides a unified API for CRUD operations across multiple\n * distributed D1 databases.\n *\n * Key responsibilities:\n * - Initialize and manage the global CollegeDB configuration\n * - Route queries to appropriate shards based on primary key mappings\n * - Implement shard allocation strategies (round-robin, random, hash-based)\n * - Provide unified CRUD operations across distributed shards\n * - Coordinate with Durable Objects for centralized shard management\n * - Handle shard rebalancing and data migration\n *\n * @example\n * ```typescript\n * import { initialize, insert, first, run } from 'collegedb';\n *\n * // Initialize the system\n * initialize({\n * kv: env.KV,\n * coordinator: env.ShardCoordinator,\n * shards: {\n * 'db-east': env.DB_EAST,\n * 'db-west': env.DB_WEST\n * },\n * strategy: 'hash'\n * });\n *\n * // Insert a record (automatically routed to appropriate shard)\n * await run('user-123', 'INSERT INTO users (id, name) VALUES (?, ?)', ['user-123', 'John']);\n *\n * // Query the record (routed to same shard)\n * const result = await first('user-123', 'SELECT * FROM users WHERE id = ?', ['user-123']);\n * ```\n *\n * @author CollegeDB Team\n * @since 1.0.0\n */\n\nimport type { Request } from '@cloudflare/workers-types';\nimport { CollegeDBError } from './errors';\nimport { KVShardMapper } from './kvmap';\nimport type {\n\tCollegeDBConfig,\n\tD1Region,\n\tOperationType,\n\tPreparedStatement,\n\tQueryResult,\n\tSQLDatabase,\n\tShardLocation,\n\tShardStats,\n\tShardingStrategy\n} from './types';\n\n/**\n * Global configuration for the collegedb instance\n *\n * Stores the system-wide configuration including KV namespace, available shards,\n * coordinator settings, and allocation strategy. Must be initialized before\n * any routing operations can be performed.\n *\n * @private\n */\nlet globalConfig: CollegeDBConfig | null = null;\n\n/**\n * Shared mapper instance for the active configuration.\n *\n * Reusing a single mapper preserves in-memory caches and avoids repeated\n * constructor/setup overhead on each operation.\n *\n * @private\n */\nlet globalMapper: KVShardMapper | null = null;\n\n/**\n * In-memory cache for per-shard size checks.\n * @private\n */\nconst shardSizeCache = new Map<string, { size: number; expiresAt: number }>();\n\nlet generatedInsertRoundRobinIndex = 0;\n\n/**\n * Gets the shared mapper for the active configuration.\n * @private\n */\nfunction getMapper(config: CollegeDBConfig): KVShardMapper {\n\tif (!globalMapper) {\n\t\tglobalMapper = new KVShardMapper(config.kv, {\n\t\t\thashShardMappings: config.hashShardMappings,\n\t\t\tmappingCacheTtlMs: config.mappingCacheTtlMs,\n\t\t\tknownShardsCacheTtlMs: config.knownShardsCacheTtlMs\n\t\t});\n\t}\n\n\treturn globalMapper;\n}\n\n/**\n * Sets up the global configuration for the CollegeDB system. This must be called\n * before any other operations can be performed. The configuration includes KV\n * storage, available D1 shards, optional coordinator, and allocation strategy.\n *\n * This will also automatically detect and migrate existing databases without requiring\n * additional setup. If shards contain existing data with primary keys, CollegeDB\n * will automatically create the necessary mappings for seamless operation.\n *\n * @param config - Configuration object containing all necessary bindings and settings\n * @throws {Error} If configuration is invalid or required bindings are missing\n * @example\n * ```typescript\n * // Basic setup with multiple shards - auto-migration happens automatically\n * initialize({\n * kv: env.KV,\n * shards: {\n * 'db-primary': env.DB_PRIMARY, // Existing DB with data\n * 'db-secondary': env.DB_SECONDARY // Another existing DB\n * },\n * strategy: 'round-robin'\n * });\n * // Existing data is now automatically accessible via CollegeDB!\n *\n * // Advanced setup with coordinator\n * initialize({\n * kv: env.KV,\n * coordinator: env.ShardCoordinator,\n * shards: {\n * 'db-east': env.DB_EAST,\n * 'db-west': env.DB_WEST,\n * 'db-central': env.DB_CENTRAL\n * },\n * strategy: 'hash'\n * });\n * ```\n */\nexport function initialize(config: CollegeDBConfig) {\n\tglobalConfig = config;\n\tglobalMapper = new KVShardMapper(config.kv, {\n\t\thashShardMappings: config.hashShardMappings,\n\t\tmappingCacheTtlMs: config.mappingCacheTtlMs,\n\t\tknownShardsCacheTtlMs: config.knownShardsCacheTtlMs\n\t});\n\tshardSizeCache.clear();\n\tgeneratedInsertRoundRobinIndex = 0;\n\n\t// Background: sync KV known shards with configured shards\n\ttry {\n\t\tconst mapper = getMapper(config);\n\t\tPromise.resolve()\n\t\t\t.then(async () => {\n\t\t\t\tconst existing = await mapper.getKnownShards();\n\t\t\t\tconst merged = Array.from(new Set([...existing, ...Object.keys(config.shards)]));\n\t\t\t\tawait mapper.setKnownShards(merged);\n\t\t\t})\n\t\t\t.catch(() => void 0);\n\t} catch {}\n\n\tif (config.shards && Object.keys(config.shards).length > 0 && !config.disableAutoMigration) {\n\t\tperformAutoMigration(config).catch((error) => {\n\t\t\tconsole.warn('Background auto-migration failed:', error);\n\t\t});\n\t}\n}\n\n/**\n * Sets up the global configuration for the CollegeDB system asynchronously.\n * This must be called before any other operations can be performed. The\n * configuration includes KVstorage, available D1 shards, optional coordinator,\n * and allocation strategy.\n *\n * This will also automatically detect and migrate existing databases without requiring\n * additional setup. If shards contain existing data with primary keys, CollegeDB\n * will automatically create the necessary mappings for seamless operation.\n *\n * Compared to `initialize`, this method waits for the background check to finish.\n *\n * @param config - Configuration object containing all necessary bindings and settings\n * @throws {Error} If configuration is invalid or required bindings are missing\n * @example\n * ```typescript\n * // Basic setup with multiple shards - auto-migration happens automatically\n * initializeAsync({\n * kv: env.KV,\n * shards: {\n * 'db-primary': env.DB_PRIMARY, // Existing DB with data\n * 'db-secondary': env.DB_SECONDARY // Another existing DB\n * },\n * strategy: 'round-robin'\n * });\n * // Existing data is now automatically accessible via CollegeDB!\n *\n * // Advanced setup with coordinator\n * initializeAsync({\n * kv: env.KV,\n * coordinator: env.ShardCoordinator,\n * shards: {\n * 'db-east': env.DB_EAST,\n * 'db-west': env.DB_WEST,\n * 'db-central': env.DB_CENTRAL\n * },\n * strategy: 'hash'\n * });\n * ```\n */\nexport async function initializeAsync(config: CollegeDBConfig) {\n\tglobalConfig = config;\n\tglobalMapper = new KVShardMapper(config.kv, {\n\t\thashShardMappings: config.hashShardMappings,\n\t\tmappingCacheTtlMs: config.mappingCacheTtlMs,\n\t\tknownShardsCacheTtlMs: config.knownShardsCacheTtlMs\n\t});\n\tshardSizeCache.clear();\n\tgeneratedInsertRoundRobinIndex = 0;\n\n\t// Sync KV known shards with configured shards (awaited in async init)\n\ttry {\n\t\tconst mapper = getMapper(config);\n\t\tconst existing = await mapper.getKnownShards();\n\t\tconst merged = Array.from(new Set([...existing, ...Object.keys(config.shards)]));\n\t\tawait mapper.setKnownShards(merged);\n\t} catch {}\n\n\tif (config.shards && Object.keys(config.shards).length > 0 && !config.disableAutoMigration)\n\t\ttry {\n\t\t\tawait performAutoMigration(config);\n\t\t} catch (error) {\n\t\t\tconsole.warn('Auto migration failed:', error);\n\t\t}\n}\n\n/**\n * Initializes the configuration and then performs a callback once the configuration\n * has finished initializing.\n *\n * @param config - CollegeDB Configuration\n * @param callback - The callback to perform after the initialization\n * @returns The result of the callback\n * @example\n * ```\n * import { collegedb, first } from 'collegedb'\n *\n * const result = collegedb({\n * kv: env.KV,\n * shards: {\n * 'db-primary': env.DB_PRIMARY, // Existing DB with data\n * 'db-secondary': env.DB_SECONDARY // Another existing DB\n * },\n * strategy: 'hash'\n * }, async () => {\n * return await first('user-123', 'SELECT * FROM users WHERE id = ?', ['user-123']);\n * });\n * ```\n */\nexport async function collegedb<T>(config: CollegeDBConfig, callback: () => T) {\n\tawait initializeAsync(config);\n\treturn await callback();\n}\n\n/**\n * Performs automatic migration detection for all shards in the background\n *\n * This function runs asynchronously after initialization to check all configured\n * shards for existing data that needs migration. It's designed to be non-blocking\n * and won't interfere with immediate database operations.\n *\n * @private\n * @param config - CollegeDB configuration\n */\nasync function performAutoMigration(config: CollegeDBConfig): Promise<void> {\n\ttry {\n\t\tconst { autoDetectAndMigrate } = await import('./migrations');\n\t\tconst shardNames = Object.keys(config.shards);\n\n\t\tif (config.debug) {\n\t\t\tconsole.log(`🔍 Checking ${shardNames.length} shards for existing data...`);\n\t\t}\n\n\t\t// Check each shard for migration needs\n\t\tconst migrationPromises = shardNames.map(async (shardName) => {\n\t\t\tconst database = config.shards[shardName];\n\t\t\tif (!database) return null;\n\n\t\t\ttry {\n\t\t\t\tconst result = await autoDetectAndMigrate(database, shardName, config, {\n\t\t\t\t\tmaxRecordsToCheck: 1000\n\t\t\t\t});\n\n\t\t\t\treturn {\n\t\t\t\t\tshardName,\n\t\t\t\t\t...result\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(`Auto-migration failed for shard ${shardName}:`, error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t});\n\n\t\tconst results = await Promise.all(migrationPromises);\n\t\tconst successfulMigrations = results.filter((r) => r?.migrationPerformed);\n\n\t\tif (config.debug) {\n\t\t\tif (successfulMigrations.length > 0) {\n\t\t\t\tconst totalRecords = successfulMigrations.reduce((sum, r) => sum + (r?.recordsMigrated || 0), 0);\n\t\t\t\tconsole.log(`🎉 Auto-migration completed! Migrated ${totalRecords} records across ${successfulMigrations.length} shards`);\n\t\t\t\tsuccessfulMigrations.forEach((result) => {\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\tconsole.log(` ✅ ${result.shardName}: ${result.recordsMigrated} records from ${result.tablesProcessed} tables`);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconsole.log('✅ All shards ready - no migration needed');\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tconsole.warn('Background auto-migration setup failed:', error);\n\t}\n}\n\n/**\n * Resets the global configuration (for testing purposes only)\n *\n * @private\n * @internal\n */\nexport function resetConfig(): void {\n\tglobalConfig = null;\n\tglobalMapper = null;\n\tshardSizeCache.clear();\n\tgeneratedInsertRoundRobinIndex = 0;\n}\n\n/**\n * Gets the global configuration, throwing an error if not initialized\n *\n * Internal utility function that retrieves the global configuration and\n * ensures the system has been properly initialized before performing\n * any operations.\n *\n * @private\n * @returns The global CollegeDB configuration\n * @throws {Error} If initialize() has not been called yet\n */\nfunction getConfig(): CollegeDBConfig {\n\tif (!globalConfig) {\n\t\tthrow new CollegeDBError('CollegeDB not initialized. Call initialize() first.', 'NOT_INITIALIZED');\n\t}\n\treturn globalConfig;\n}\n\n/**\n * Determines the operation type from a SQL statement\n * @private\n * @param sql - The SQL statement to analyze\n * @returns The operation type ('read' for SELECT, 'write' for INSERT/UPDATE/DELETE)\n */\nfunction getOperationType(sql: string): OperationType {\n\tconst sql0 = sql.trim().toUpperCase();\n\n\tif (\n\t\tsql0.startsWith('SELECT') ||\n\t\tsql0.startsWith('VALUES') ||\n\t\tsql0.startsWith('TABLE') ||\n\t\tsql0.startsWith('PRAGMA') ||\n\t\tsql0.startsWith('EXPLAIN') ||\n\t\tsql0.startsWith('WITH') ||\n\t\tsql0.startsWith('SHOW')\n\t) {\n\t\treturn 'read';\n\t}\n\n\t// All other operations (INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, etc.) are considered writes\n\treturn 'write';\n}\n\n/**\n * Resolves the effective sharding strategy based on configuration and operation type\n * @private\n * @param config - CollegeDB configuration\n * @param type - The type of operation being performed\n * @returns The effective sharding strategy to use\n */\nfunction resolveStrategy(config: CollegeDBConfig, type: OperationType): ShardingStrategy {\n\tconst strategy = config.strategy || 'hash';\n\n\tif (typeof strategy === 'string') {\n\t\treturn strategy;\n\t}\n\n\t// Fallbacks for partially specified mixed strategies\n\tconst mixed = strategy as Partial<Record<OperationType, ShardingStrategy>>;\n\treturn (mixed[type] || mixed.write || mixed.read || 'hash') as ShardingStrategy;\n}\n\n/**\n * Calculates the relative distance between two D1 regions for location-based sharding.\n * Lower values indicate closer regions with better expected latency.\n *\n * @private\n * @param from - Source region\n * @param to - Target region\n * @returns Relative distance score (lower is better)\n */\nfunction calculateRegionDistance(from: D1Region, to: D1Region): number {\n\t// Same region = optimal\n\tif (from === to) return 0;\n\n\t// Define region coordinates (approximate)\n\tconst regionCoords: Record<D1Region, { lat: number; lon: number }> = {\n\t\twnam: { lat: 37.7749, lon: -122.4194 }, // San Francisco\n\t\tenam: { lat: 40.7128, lon: -74.006 }, // New York\n\t\tweur: { lat: 51.5074, lon: -0.1278 }, // London\n\t\teeur: { lat: 52.52, lon: 13.405 }, // Berlin\n\t\tapac: { lat: 35.6762, lon: 139.6503 }, // Tokyo\n\t\toc: { lat: -33.8688, lon: 151.2093 }, // Sydney\n\t\tme: { lat: 25.2048, lon: 55.2708 }, // Dubai\n\t\taf: { lat: -26.2041, lon: 28.0473 } // Johannesburg\n\t};\n\n\tconst fromCoord = regionCoords[from];\n\tconst toCoord = regionCoords[to];\n\n\t// Simple Euclidean distance calculation\n\tconst latDiff = fromCoord.lat - toCoord.lat;\n\tconst lonDiff = fromCoord.lon - toCoord.lon;\n\treturn Math.sqrt(latDiff * latDiff + lonDiff * lonDiff);\n}\n\n/**\n * Determines the closest D1 region based on an IP address.\n * Uses IP geolocation to estimate the user's location and find the nearest D1 region.\n *\n * This function uses Cloudflare's CF object which provides geolocation data\n * in Cloudflare Workers environment. Falls back to 'wnam' if geolocation fails.\n *\n * @param request - The incoming Request object (contains CF geolocation data in Cloudflare Workers)\n * @returns The closest D1Region based on IP geolocation\n * @example\n * ```typescript\n * // In a Cloudflare Worker\n * export default {\n * async fetch(request: Request, env: Env) {\n * const userRegion = getClosestRegionFromIP(request);\n *\n * initialize({\n * kv: env.KV,\n * strategy: 'location',\n * targetRegion: userRegion, // Automatically optimized for user location\n * shardLocations: { ... },\n * shards: { ... }\n * });\n * }\n * };\n * ```\n */\nexport function getClosestRegionFromIP(request: Request): D1Region {\n\tconst cf = request.cf;\n\n\tif (!cf || !cf.country) {\n\t\treturn 'wnam';\n\t}\n\n\tconst country = cf.country as string;\n\tconst continent = cf.continent as string;\n\n\t// Western North America\n\tif (['US', 'CA', 'MX'].includes(country)) {\n\t\t// Further refine by region/state if available\n\t\tconst region = (cf.region || cf.regionCode || '') as string;\n\t\tconst timezone = (cf.timezone || '') as string;\n\n\t\t// West Coast indicators\n\t\tif (\n\t\t\tregion.includes('CA') ||\n\t\t\tregion.includes('WA') ||\n\t\t\tregion.includes('OR') ||\n\t\t\tregion.includes('NV') ||\n\t\t\tregion.includes('AZ') ||\n\t\t\tregion.includes('UT') ||\n\t\t\ttimezone.includes('Pacific') ||\n\t\t\ttimezone.includes('America/Los_Angeles')\n\t\t) {\n\t\t\treturn 'wnam';\n\t\t}\n\n\t\t// East Coast and Central - default to Eastern North America\n\t\treturn 'enam';\n\t}\n\n\t// Eastern North America (broader North America)\n\tif (['GL', 'PM', 'BM'].includes(country)) {\n\t\treturn 'enam';\n\t}\n\n\t// Western Europe\n\tif (['GB', 'IE', 'FR', 'ES', 'PT', 'NL', 'BE', 'LU', 'CH', 'AT', 'IT'].includes(country)) {\n\t\treturn 'weur';\n\t}\n\n\t// Eastern Europe\n\tif (\n\t\t[\n\t\t\t'DE',\n\t\t\t'PL',\n\t\t\t'CZ',\n\t\t\t'SK',\n\t\t\t'HU',\n\t\t\t'SI',\n\t\t\t'HR',\n\t\t\t'BA',\n\t\t\t'RS',\n\t\t\t'ME',\n\t\t\t'MK',\n\t\t\t'AL',\n\t\t\t'BG',\n\t\t\t'RO',\n\t\t\t'MD',\n\t\t\t'UA',\n\t\t\t'BY',\n\t\t\t'LT',\n\t\t\t'LV',\n\t\t\t'EE',\n\t\t\t'FI',\n\t\t\t'SE',\n\t\t\t'NO',\n\t\t\t'DK',\n\t\t\t'IS'\n\t\t].includes(country)\n\t) {\n\t\treturn 'eeur';\n\t}\n\n\t// Russia - closer to Eastern Europe for most population centers\n\tif (country === 'RU') {\n\t\treturn 'eeur';\n\t}\n\n\t// Asia Pacific\n\tif (['JP', 'KR', 'CN', 'HK', 'TW', 'MO', 'MN', 'KP'].includes(country)) {\n\t\treturn 'apac';\n\t}\n\n\t// Southeast Asia and South Asia -> APAC\n\tif (\n\t\t['TH', 'VN', 'SG', 'MY', 'ID', 'PH', 'BN', 'KH', 'LA', 'MM', 'TL', 'IN', 'PK', 'BD', 'LK', 'NP', 'BT', 'MV', 'AF'].includes(country)\n\t) {\n\t\treturn 'apac';\n\t}\n\n\t// Oceania\n\tif (['AU', 'NZ', 'PG', 'FJ', 'NC', 'VU', 'SB', 'WS', 'TO', 'KI', 'NR', 'PW', 'FM', 'MH', 'TV'].includes(country)) {\n\t\treturn 'oc';\n\t}\n\n\t// Middle East\n\tif (['AE', 'SA', 'QA', 'KW', 'BH', 'OM', 'YE', 'IQ', 'IR', 'SY', 'LB', 'JO', 'IL', 'PS', 'TR', 'CY'].includes(country)) {\n\t\treturn 'me';\n\t}\n\n\t// Africa\n\tif (continent === 'AF' || ['EG', 'LY', 'TN', 'DZ', 'MA', 'SD', 'SS', 'ET', 'ER', 'DJ', 'SO'].includes(country)) {\n\t\treturn 'af';\n\t}\n\n\t// Central Asia -> closer to Eastern Europe\n\tif (['KZ', 'UZ', 'TM', 'TJ', 'KG'].includes(country)) {\n\t\treturn 'eeur';\n\t}\n\n\t// South America -> geographically closer to Eastern North America\n\tif (continent === 'SA' || ['BR', 'AR', 'CL', 'PE', 'CO', 'VE', 'EC', 'BO', 'PY', 'UY', 'GY', 'SR', 'GF'].includes(country)) {\n\t\treturn 'enam';\n\t}\n\n\t// Central America and Caribbean -> Eastern North America\n\tif (\n\t\t['GT', 'BZ', 'SV', 'HN', 'NI', 'CR', 'PA', 'CU', 'JM', 'HT', 'DO', 'PR', 'TT', 'BB', 'GD', 'VC', 'LC', 'DM', 'AG', 'KN'].includes(\n\t\t\tcountry\n\t\t)\n\t) {\n\t\treturn 'enam';\n\t}\n\n\t// Default fallback - Western North America (major Cloudflare hub)\n\treturn 'wnam';\n}\n\nfunction parseRegion(location: ShardLocation | D1Region): D1Region {\n\tif (typeof location === 'string') {\n\t\treturn location;\n\t}\n\n\treturn location.region || 'wnam';\n}\n\n/**\n * Gets the approximate size of a D1 database in bytes using an efficient SQL query.\n * Uses SQLite's page_count and page_size pragmas for accurate size calculation.\n *\n * @private\n * @param database - The SQL database instance to measure\n * @returns Promise resolving to the database size in bytes\n * @throws {CollegeDBError} If the size query fails\n */\nasync function getDatabaseSize(database: SQLDatabase): Promise<number> {\n\ttry {\n\t\t// Get page count and page size efficiently\n\t\tconst [pageCountResult, pageSizeResult] = await Promise.all([\n\t\t\tdatabase.prepare('PRAGMA page_count').first<{ page_count: number }>(),\n\t\t\tdatabase.prepare('PRAGMA page_size').first<{ page_size: number }>()\n\t\t]);\n\n\t\tif (!pageCountResult?.page_count || !pageSizeResult?.page_size) {\n\t\t\tthrow new CollegeDBError('Failed to retrieve database size information', 'SIZE_QUERY_FAILED');\n\t\t}\n\n\t\treturn pageCountResult.page_count * pageSizeResult.page_size;\n\t} catch (error) {\n\t\tthrow new CollegeDBError(\n\t\t\t`Failed to get database size: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t\t'SIZE_QUERY_FAILED'\n\t\t);\n\t}\n}\n\n/**\n * Retrieves a shard size using a short-lived in-memory cache.\n * @private\n */\nasync function getDatabaseSizeForAllocation(shardName: string, config: CollegeDBConfig): Promise<number> {\n\tconst cacheTtlMs = Math.max(0, config.sizeCacheTtlMs ?? 30_000);\n\tconst cached = shardSizeCache.get(shardName);\n\n\tif (cached && cached.expiresAt >= Date.now()) {\n\t\treturn cached.size;\n\t}\n\n\tconst database = config.shards[shardName];\n\tif (!database) {\n\t\tthrow new CollegeDBError(`Shard ${shardName} not found in configuration`, 'SHARD_NOT_FOUND');\n\t}\n\n\tconst size = await getDatabaseSize(database);\n\tif (cacheTtlMs > 0) {\n\t\tshardSizeCache.set(shardName, {\n\t\t\tsize,\n\t\t\texpiresAt: Date.now() + cacheTtlMs\n\t\t});\n\t}\n\n\treturn size;\n}\n\n/**\n * Filters available shards to exclude those that exceed the configured maximum size.\n * This is used during shard allocation to prevent new data from being assigned to\n * shards that are approaching or exceeding their size limits.\n *\n * @private\n * @param availableShards - List of shard names to filter\n * @param config - CollegeDB configuration containing maxDatabaseSize setting\n * @returns Promise resolving to filtered list of shard names\n */\nasync function filterShardsBySize(availableShards: string[], config: CollegeDBConfig): Promise<string[]> {\n\tif (typeof config.maxDatabaseSize !== 'number' || !Number.isFinite(config.maxDatabaseSize) || config.maxDatabaseSize <= 0) {\n\t\treturn availableShards;\n\t}\n\n\tconst limit = config.maxDatabaseSize;\n\n\tconst sizeChecks = await Promise.allSettled(\n\t\tavailableShards.map(async (shardName) => {\n\t\t\tconst size = await getDatabaseSizeForAllocation(shardName, config);\n\t\t\treturn {\n\t\t\t\tshard: shardName,\n\t\t\t\tsize,\n\t\t\t\twithinLimit: size < limit\n\t\t\t};\n\t\t})\n\t);\n\n\tconst validShards = sizeChecks\n\t\t.filter(\n\t\t\t(result): result is PromiseFulfilledResult<{ shard: string; size: number; withinLimit: boolean }> =>\n\t\t\t\tresult.status === 'fulfilled' && result.value.withinLimit\n\t\t)\n\t\t.map((result) => result.value.shard);\n\n\t// If all shards exceed the size limit, log warning and return all shards\n\t// to prevent complete failure (existing mappings should still work)\n\tif (validShards.length === 0) {\n\t\tif (config.debug) {\n\t\t\tconsole.warn('All shards exceed maxDatabaseSize limit. Allowing allocation to prevent failure.');\n\t\t}\n\t\treturn availableShards;\n\t}\n\n\tif (config.debug && validShards.length < availableShards.length) {\n\t\tconst excludedShards = availableShards.filter((shard) => !validShards.includes(shard));\n\t\tconsole.log(`Excluded ${excludedShards.length} shards due to size limits: ${excludedShards.join(', ')}`);\n\t}\n\n\treturn validShards;\n}\n\n/**\n * Selects the optimal shard for location-based allocation strategy.\n * Prioritizes shards in the target region, then nearby regions by distance.\n *\n * @private\n * @param targetRegion - The preferred region for allocation\n * @param availableShards - List of available shard names\n * @param shardLocations - Geographic locations of each shard\n * @param primaryKey - The primary key being allocated (for consistent tiebreaking)\n * @returns Selected shard name\n */\nfunction selectShardByLocation(\n\ttargetRegion: D1Region,\n\tavailableShards: string[],\n\tshardLocations: Record<string, ShardLocation | D1Region>,\n\tprimaryKey: string\n): string {\n\t// Filter shards that have location information\n\tconst locatedShards = availableShards.filter((shard) => shardLocations[shard]);\n\n\tif (locatedShards.length === 0) {\n\t\t// Fallback to hash if no location info available\n\t\tlet hash = 0;\n\t\tfor (let i = 0; i < primaryKey.length; i++) {\n\t\t\tconst char = primaryKey.charCodeAt(i);\n\t\t\thash = (hash << 5) - hash + char;\n\t\t\thash = hash & hash;\n\t\t}\n\t\tconst index = Math.abs(hash) % availableShards.length;\n\t\treturn availableShards[index]!;\n\t}\n\n\t// Calculate distances and priorities\n\tconst shardScores = locatedShards.map((shard) => {\n\t\tconst location = shardLocations[shard]!;\n\t\tconst distance = calculateRegionDistance(targetRegion, parseRegion(location));\n\n\t\tconst priority = typeof location === 'object' ? location.priority || 1 : 1;\n\t\tconst score = distance - priority * 0.1;\n\n\t\treturn { shard, score, distance, priority };\n\t});\n\n\t// Sort by score (lower is better)\n\tshardScores.sort((a, b) => a.score - b.score);\n\n\tconst bestScore = shardScores[0]!.score;\n\tconst bestShards = shardScores.filter((s) => Math.abs(s.score - bestScore) < 0.01);\n\n\tif (bestShards.length === 1) {\n\t\treturn bestShards[0]!.shard;\n\t}\n\n\t// Consistent selection among best candidates\n\tlet hash = 0;\n\tfor (let i = 0; i < primaryKey.length; i++) {\n\t\tconst char = primaryKey.charCodeAt(i);\n\t\thash = (hash << 5) - hash + char;\n\t\thash = hash & hash;\n\t}\n\tconst index = Math.abs(hash) % bestShards.length;\n\treturn bestShards[index]!.shard;\n}\n\n/**\n * Helper to select a shard locally based on the effective strategy when the coordinator\n * is unavailable or not configured. Provides sensible fallbacks to avoid hotspotting.\n * @private\n */\nfunction selectShardByStrategy(\n\teffectiveStrategy: ShardingStrategy,\n\tprimaryKey: string,\n\tavailableShards: string[],\n\tconfig: CollegeDBConfig\n): string {\n\tswitch (effectiveStrategy) {\n\t\tcase 'hash': {\n\t\t\tlet hash = 0;\n\t\t\tfor (let i = 0; i < primaryKey.length; i++) {\n\t\t\t\tconst char = primaryKey.charCodeAt(i);\n\t\t\t\thash = (hash << 5) - hash + char;\n\t\t\t\thash = hash & hash;\n\t\t\t}\n\t\t\tconst index = Math.abs(hash) % availableShards.length;\n\t\t\treturn availableShards[index] || availableShards[0]!;\n\t\t}\n\t\tcase 'location': {\n\t\t\tif (!config.targetRegion) {\n\t\t\t\treturn selectShardByStrategy('hash', primaryKey, availableShards, config);\n\t\t\t}\n\t\t\treturn selectShardByLocation(config.targetRegion, availableShards, config.shardLocations || {}, primaryKey);\n\t\t}\n\t\tcase 'random': {\n\t\t\treturn availableShards[Math.floor(Math.random() * availableShards.length)] || availableShards[0]!;\n\t\t}\n\t\tdefault: {\n\t\t\treturn selectShardByStrategy('hash', primaryKey, availableShards, config);\n\t\t}\n\t}\n}\n\n/**\n * Gets or allocates a shard for a primary key with operation-specific strategy\n *\n * This is the core routing function that determines which shard should handle\n * a given primary key. If a mapping already exists, it returns the existing\n * shard. If not, it allocates a new shard using the configured strategy.\n *\n * Allocation strategies:\n * - **round-robin**: Cycles through shards in order (with coordinator)\n * - **random**: Randomly selects from available shards\n * - **hash**: Uses consistent hashing for deterministic assignment\n * - **location**: Selects shards based on geographic proximity to target region\n *\n * The function prefers using the Durable Object coordinator when available\n * for centralized allocation decisions, falling back to local strategies\n * when the coordinator is unavailable.\n *\n * @private\n * @param primaryKey - The primary key to route\n * @param operationType - The type of operation (read/write) for mixed strategy support\n * @returns Promise resolving to the shard binding name\n * @throws {Error} If no shards are configured or allocation fails\n * @example\n * ```typescript\n * // This function is called internally by CRUD operations\n * const readShard = await getShardForKey('user-123', 'read');\n * const writeShard = await getShardForKey('user-123', 'write');\n * console.log(`User 123 reads from: ${readShard}, writes to: ${writeShard}`);\n * ```\n */\nasync function getShardForKey(primaryKey: string, operationType: OperationType = 'write'): Promise<string> {\n\tconst config = getConfig();\n\tconst mapper = getMapper(config);\n\n\t// Check if mapping already exists\n\tconst existingMapping = await mapper.getShardMapping(primaryKey);\n\tif (existingMapping) {\n\t\treturn existingMapping.shard;\n\t}\n\n\t// Before allocating a new shard, check if any existing shards contain this key\n\tconst availableShards = Object.keys(config.shards);\n\tif (availableShards.length === 0) {\n\t\tthrow new CollegeDBError('No shards configured', 'NO_SHARDS');\n\t}\n\n\t// Filter shards by size limit if configured\n\tconst eligibleShards = await filterShardsBySize(availableShards, config);\n\n\t// If no existing mapping found after auto-migration, allocate a new shard\n\tlet selectedShard: string;\n\tconst effectiveStrategy = resolveStrategy(config, operationType);\n\n\t// Use coordinator if available for allocation\n\tif (config.coordinator) {\n\t\ttry {\n\t\t\tconst coordinatorId = config.coordinator.idFromName('default');\n\t\t\tconst coordinator = config.coordinator.get(coordinatorId);\n\n\t\t\tconst response = await coordinator.fetch('http://coordinator/allocate', {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tprimaryKey,\n\t\t\t\t\tstrategy: effectiveStrategy, // Use resolved strategy instead of config.strategy\n\t\t\t\t\toperationType, // Pass operation type for coordinator awareness\n\t\t\t\t\ttargetRegion: config.targetRegion,\n\t\t\t\t\tshardLocations: config.shardLocations,\n\t\t\t\t\tavailableShards: eligibleShards // Pass filtered shards to coordinator\n\t\t\t\t})\n\t\t\t});\n\n\t\t\tif (response.ok) {\n\t\t\t\tconst result = (await response.json()) as { shard: string };\n\t\t\t\tselectedShard = result.shard;\n\t\t\t} else {\n\t\t\t\tselectedShard = selectShardByStrategy(effectiveStrategy, primaryKey, eligibleShards, config);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.warn('Coordinator allocation failed, falling back to local strategy:', error);\n\t\t\tselectedShard = selectShardByStrategy(effectiveStrategy, primaryKey, eligibleShards, config);\n\t\t}\n\t} else {\n\t\tselectedShard = selectShardByStrategy(effectiveStrategy, primaryKey, eligibleShards, config);\n\t}\n\n\t// Store the mapping\n\tawait mapper.setShardMapping(primaryKey, selectedShard);\n\treturn selectedShard;\n}\n\n/**\n * Gets the D1 database instance for a primary key with operation-specific routing\n *\n * Resolves the primary key to its assigned shard and returns the corresponding\n * D1 database instance. This function handles the complete routing process\n * from primary key to database connection, with support for different strategies\n * based on operation type.\n *\n * @private\n * @param primaryKey - The primary key to route\n * @param operationType - The type of operation (read/write) for mixed strategy support\n * @returns Promise resolving to the D1 database instance\n * @throws {Error} If shard routing fails or database instance not found\n */\nasync function getDatabase(primaryKey: string, operationType: OperationType = 'write'): Promise<SQLDatabase> {\n\tconst config = getConfig();\n\tconst shard = await getShardForKey(primaryKey, operationType);\n\tconst database = config.shards[shard];\n\n\tif (!database) {\n\t\tthrow new CollegeDBError(`Shard ${shard} not found in configuration`, 'SHARD_NOT_FOUND');\n\t}\n\n\treturn database;\n}\n\n/**\n * Creates the database schema in the specified D1 database\n *\n * @param d1 - The D1 database instance to create schema in\n * @param schema - The SQL schema definition to execute\n * @returns Promise that resolves when schema creation is complete\n * @throws {Error} If schema creation fails\n * @example\n * ```typescript\n * const userSchema = `\n * CREATE TABLE users (\n * id TEXT PRIMARY KEY,\n * name TEXT NOT NULL,\n * email TEXT UNIQUE\n * );\n * `;\n * await createSchema(env.DB_NEW_SHARD, userSchema);\n * ```\n */\nexport async function createSchema(d1: SQLDatabase, schema: string): Promise<void> {\n\tconst { createSchema: createSchemaImpl } = await import('./migrations');\n\tawait createSchemaImpl(d1, schema);\n}\n\n/**\n * Prepares a SQL statement for execution with operation-aware routing.\n *\n * @param key - The primary key to route the query\n * @param sql - The SQL statement to prepare\n * @returns Promise that resolves to a prepared statement\n * @throws {Error} If preparation fails\n */\nexport async function prepare(key: string, sql: string): Promise<PreparedStatement> {\n\tconst operationType = getOperationType(sql);\n\tconst db = await getDatabase(key, operationType);\n\tconst result = db.prepare(sql);\n\treturn result;\n}\n\n/**\n * Executes a statement on the appropriate shard based on the primary key.\n * The primary key is used to determine which shard should store the record,\n * ensuring consistent routing for future queries.\n *\n * Use this helper when your application already knows the routing key before\n * issuing the write. For database-generated primary keys, use {@link insert}\n * so the returned generated id can be captured and reused for follow-up reads.\n *\n * @template T - Type of the result records\n * @param key - Primary key to route the query (should match the record's primary key)\n * @param sql - SQL statement with parameter placeholders\n * @param bindings - Parameter values to bind to the SQL statement\n * @returns Promise that resolves when the statement is complete\n * @throws {Error} If statement fails or routing fails\n * @example\n * ```typescript\n * // Insert a new user\n * await run('user-123',\n * 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)',\n * ['user-123', 'John Doe', 'john@example.com']\n * );\n *\n * // Insert a post linked to a user\n * await run('post-456',\n * 'INSERT INTO posts (id, user_id, title, content) VALUES (?, ?, ?, ?)',\n * ['post-456', 'user-123', 'Hello World', 'My first post!']\n * );\n * ```\n *\n * @example\n * ```typescript\n * // Update user information\n * await run('user-123',\n * 'UPDATE users SET name = ?, email = ? WHERE id = ?',\n * ['John Smith', 'johnsmith@example.com', 'user-123']\n * );\n *\n * // Update post content\n * await run('post-456',\n * 'UPDATE posts SET title = ?, content = ?, updated_at = strftime(\"%s\", \"now\") WHERE id = ?',\n * ['Updated Title', 'Updated content here', 'post-456']\n * );\n * ```\n *\n * @example\n * ```typescript\n * // Delete a specific user\n * await run('user-123',\n * 'DELETE FROM users WHERE id = ?',\n * ['user-123']\n * );\n *\n * // Delete user's posts (cascade delete)\n * await run('user-123',\n * 'DELETE FROM posts WHERE user_id = ?',\n * ['user-123']\n * );\n *\n * // Delete with conditions\n * await run('user-123',\n * 'DELETE FROM posts WHERE user_id = ? AND created_at < ?',\n * ['user-123', Date.now() - 86400000] // Posts older than 1 day\n * );\n * ```\n */\nexport async function run<T = Record<string, unknown>>(key: string, sql: string, bindings: any[] = []): Promise<QueryResult<T>> {\n\tconst prepared = await prepare(key, sql);\n\tconst result = await prepared.bind(...bindings).run<T>();\n\n\tif (!result.success) {\n\t\tthrow new CollegeDBError(`Query failed: ${result.error || 'Unknown error'}`, 'QUERY_FAILED');\n\t}\n\n\treturn result;\n}\n\n/**\n * Result returned by {@link insert} and {@link insertShard}.\n *\n * The helper keeps the normal query payload but also exposes the generated\n * primary key when the backend returns one through `RETURNING` rows or\n * provider metadata.\n *\n * @since 1.1.4\n */\nexport interface InsertResult<T = Record<string, unknown>> extends QueryResult<T> {\n\t/** Generated primary key returned by the database or driver. */\n\tgeneratedId: number | string;\n}\n\nfunction extractGeneratedId<T = Record<string, unknown>>(result: QueryResult<T>): number | string | undefined {\n\tconst firstRow = result.results[0] as Record<string, unknown> | undefined;\n\tif (firstRow && typeof firstRow === 'object') {\n\t\t// Prefer explicit RETURNING rows over provider metadata when available.\n\t\tfor (const key of ['id', 'ID', 'Id', 'rowid', 'ROWID', 'RowId', 'last_row_id', 'lastInsertId', 'insertId']) {\n\t\t\tconst value = firstRow[key];\n\t\t\tif (value !== undefined && value !== null) {\n\t\t\t\treturn value as number | string;\n\t\t\t}\n\t\t}\n\n\t\tfor (const [key, value] of Object.entries(firstRow)) {\n\t\t\tconst lowerKey = key.toLowerCase();\n\t\t\tif ((lowerKey === 'id' || lowerKey === 'rowid') && (typeof value === 'number' || typeof value === 'string')) {\n\t\t\t\treturn value as number | string;\n\t\t\t}\n\t\t}\n\n\t\tfor (const value of Object.values(firstRow)) {\n\t\t\tif (typeof value === 'number' || typeof value === 'string') {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst metaId = result.meta.last_row_id;\n\tif (metaId !== undefined && metaId !== null) {\n\t\treturn metaId;\n\t}\n\n\treturn undefined;\n}\n\nfunction createInsertAllocatorKey(): string {\n\treturn `insert:${Date.now()}:${Math.random().toString(36).slice(2)}`;\n}\n\nasync function allocateInsertShard(): Promise<string> {\n\tconst config = getConfig();\n\tconst availableShards = Object.keys(config.shards);\n\n\tif (availableShards.length === 0) {\n\t\tthrow new CollegeDBError('No shards configured', 'NO_SHARDS');\n\t}\n\n\tconst eligibleShards = await filterShardsBySize(availableShards, config);\n\tif (eligibleShards.length === 0) {\n\t\tthrow new CollegeDBError('No shards available for insert', 'NO_SHARDS');\n\t}\n\n\tconst effectiveStrategy = resolveStrategy(config, 'write');\n\tconst allocatorKey = createInsertAllocatorKey();\n\n\tif (config.coordinator) {\n\t\ttry {\n\t\t\tconst coordinatorId = config.coordinator.idFromName('default');\n\t\t\tconst coordinator = config.coordinator.get(coordinatorId);\n\n\t\t\tconst response = await coordinator.fetch('http://coordinator/allocate', {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tprimaryKey: allocatorKey,\n\t\t\t\t\tstrategy: effectiveStrategy,\n\t\t\t\t\toperationType: 'write',\n\t\t\t\t\ttargetRegion: config.targetRegion,\n\t\t\t\t\tshardLocations: config.shardLocations,\n\t\t\t\t\tavailableShards: eligibleShards\n\t\t\t\t})\n\t\t\t});\n\n\t\t\tif (response.ok) {\n\t\t\t\tconst result = (await response.json()) as { shard: string };\n\t\t\t\treturn result.shard;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.warn('Coordinator allocation for insert failed, falling back to local strategy:', error);\n\t\t}\n\t}\n\n\tif (effectiveStrategy === 'round-robin') {\n\t\tconst shard = eligibleShards[generatedInsertRoundRobinIndex % eligibleShards.length]!;\n\t\tgeneratedInsertRoundRobinIndex = (generatedInsertRoundRobinIndex + 1) % eligibleShards.length;\n\t\treturn shard;\n\t}\n\n\treturn selectShardByStrategy(effectiveStrategy, allocatorKey, eligibleShards, config);\n}\n\nasync function executeInsertOnShard<T = Record<string, unknown>>(\n\tshardBinding: string,\n\tsql: string,\n\tbindings: any[] = []\n): Promise<InsertResult<T>> {\n\tconst config = getConfig();\n\tif (!config.shards[shardBinding]) {\n\t\tthrow new CollegeDBError(`Shard ${shardBinding} not found`, 'SHARD_NOT_FOUND');\n\t}\n\n\tconst returning = /\\breturning\\b/i.test(sql);\n\tconst result = returning ? await allShard<T>(shardBinding, sql, bindings) : await runShard<T>(shardBinding, sql, bindings);\n\tconst generatedId = extractGeneratedId(result);\n\n\tif (generatedId === undefined) {\n\t\tthrow new CollegeDBError('Insert did not return a generated primary key', 'GENERATED_KEY_UNAVAILABLE');\n\t}\n\n\tconst mapper = getMapper(config);\n\tawait mapper.setShardMapping(String(generatedId), shardBinding);\n\n\treturn {\n\t\t...result,\n\t\tgeneratedId\n\t};\n}\n\n/**\n * Executes an insert on an automatically selected shard and returns the generated primary key.\n *\n * This is the default helper for generated-key tables. CollegeDB picks a shard\n * using the configured allocation strategy, then stores the generated primary\n * key -> shard mapping so routed reads can find the row later.\n *\n * @template T - Type of returned rows when the insert uses `RETURNING`\n * @param sql - The INSERT statement to execute\n * @param bindings - Parameter values to bind to the statement\n * @returns Promise resolving to the write result plus the generated id\n * @throws {CollegeDBError} If the insert succeeds but no generated id can be determined\n * @since 1.1.4\n * @example\n * ```typescript\n * const created = await insert(\n * 'INSERT INTO auto_users (name, email) VALUES (?, ?)',\n * ['Ada', 'ada@example.com']\n * );\n *\n * const row = await first(String(created.generatedId), 'SELECT * FROM auto_users WHERE id = ?', [created.generatedId]);\n * ```\n */\nexport async function insert<T = Record<string, unknown>>(sql: string, bindings: any[] = []): Promise<InsertResult<T>> {\n\tconst shardBinding = await allocateInsertShard();\n\treturn await executeInsertOnShard<T>(shardBinding, sql, bindings);\n}\n\n/**\n * Executes an insert directly on a named shard and returns the generated primary key.\n *\n * Use this helper when you already know the shard you want to target.\n * The helper still captures the generated id and stores the mapping so routed\n * reads can find the new row later.\n *\n * @template T - Type of returned rows when the insert uses `RETURNING`\n * @param shardBinding - The shard binding to execute the insert on\n * @param sql - The INSERT statement to execute\n * @param bindings - Parameter values to bind to the statement\n * @returns Promise resolving to the write result plus the generated id\n * @throws {CollegeDBError} If the insert succeeds but no generated id can be determined\n * @since 1.1.4\n * @example\n * ```typescript\n * const created = await insertShard('db-east',\n * 'INSERT INTO auto_users (name, email, created_at) VALUES (?, ?, ?)',\n * ['Ada', 'ada@example.com', Date.now()]\n * );\n *\n * console.log(created.generatedId);\n * ```\n * @example\n * ```typescript\n * const created = await insertShard('db-east',\n * 'INSERT INTO auto_users (name, email) VALUES (?, ?) RETURNING id',\n * ['Ada', 'ada@example.com']\n * );\n * ```\n */\nexport async function insertShard<T = Record<string, unknown>>(\n\tshardBinding: string,\n\tsql: string,\n\tbindings: any[] = []\n): Promise<InsertResult<T>> {\n\treturn await executeInsertOnShard<T>(shardBinding, sql, bindings);\n}\n\n/**\n * Retrieves all records matching the query for a given primary key.\n *\n * This function is useful for fetching multiple records based on a primary key.\n * It automatically routes the query to the correct shard based on the provided\n * primary key, ensuring consistent data access.\n * @param key - Primary key to route the query\n * @param sql - The SQL statement to execute\n * @param bindings - Parameter values to bind to the SQL statement\n * @returns Promise that resolves to the result of the update operation\n * @throws {Error} If update fails or routing fails\n *\n * @example\n * ```typescript\n * type Post = {\n * id: string;\n * user_id: string;\n * title: string;\n * content: string;\n * };\n *\n *\n * // Get user's posts\n * const postsResult = await all<Post>('user-123',\n * 'SELECT * FROM posts WHERE user_id = ? ORDER BY created_at DESC',\n * ['user-123']\n * );\n *\n * console.log(`User has ${postsResult.meta.count} posts`);\n * ```\n */\nexport async function all<T = Record<string, unknown>>(key: string, sql: string, bindings: any[] = []): Promise<QueryResult<T>> {\n\tconst prepared = await prepare(key, sql);\n\tconst result = await prepared.bind(...bindings).all<T>();\n\n\tif (!result.success) {\n\t\tthrow new CollegeDBError(`Query failed: ${result.error || 'Unknown error'}`, 'QUERY_FAILED');\n\t}\n\n\treturn result;\n}\n\n/**\n * Retrieves the first record matching the query for a given primary key.\n *\n * This function is useful for fetching a single record based on a primary key.\n * It automatically routes the query to the correct shard based on the provided\n * primary key, ensuring consistent data access.\n *\n * @template T - Type of the result record\n * @param key - Primary key to route the query\n * @param sql - SQL statement with parameter placeholders\n * @param bindings - Parameter values to bind to the SQL statement\n * @returns Promise that resolves to the first matching record, or null if not found\n * @throws {Error} If query fails or routing fails\n *\n * @example\n * ```typescript\n * type User = {\n * id: string;\n * name: string;\n * email: string;\n * };\n * // Get a specific user\n * const userResult = await first<User>('user-123',\n * 'SELECT * FROM users WHERE id = ?',\n * ['user-123']\n * );\n *\n * if (userResult) {\n * console.log(`Found user: ${userResult.name}`);\n * }\n */\nexport async function first<T = Record<string, unknown>>(key: string, sql: string, bindings: any[] = []): Promise<T | null> {\n\tconst prepared = await prepare(key, sql);\n\tconst result = await prepared.bind(...bindings).first<T>();\n\treturn result;\n}\n\n/**\n * Retrieves all records using a secondary lookup key when available.\n *\n * This helper attempts to resolve the lookup key through KV first. If a mapping\n * exists, the query executes on that shard directly. If the mapping is missing,\n * stale, or returns no rows, the helper safely falls back to fanout (`allAllShards`)\n * and returns merged results.\n *\n * @template T - Type of the result records\n * @param lookupKey - Secondary key such as `email:user@example.com` or `username:alice`\n * @param sql - SQL statement to execute\n * @param bindings - Parameter values to bind to the SQL statement\n * @param batchSize - Number of concurrent shard queries during fanout (default: 50)\n * @returns Promise resolving to merged query results\n * @since 1.1.4\n */\nexport async function allByLookupKey<T = Record<string, unknown>>(\n\tlookupKey: string,\n\tsql: string,\n\tbindings: any[] = [],\n\tbatchSize: number = 50\n): Promise<QueryResult<T>> {\n\tconst config = getConfig();\n\tconst mapper = getMapper(config);\n\tconst mapping = await mapper.getShardMapping(lookupKey);\n\n\tif (mapping) {\n\t\tconst mappedShardDb = config.shards[mapping.shard];\n\t\tif (mappedShardDb) {\n\t\t\tconst mappedResult = await allShard<T>(mapping.shard, sql, bindings);\n\t\t\tif (mappedResult.success && mappedResult.results.length > 0) {\n\t\t\t\treturn mappedResult;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst shardResults = await allAllShards<T>(sql, bindings, batchSize);\n\treturn mergeAllShardQueryResults(shardResults);\n}\n\n/**\n * Retrieves the first record using a secondary lookup key when available.\n *\n * This helper avoids creating new primary-key mappings for secondary identifiers.\n * It first checks KV for a lookup-key mapping and queries that shard directly.\n * If no mapping exists (or the mapping is stale), it falls back to fanout\n * (`firstAllShards`) and returns the first non-null result.\n *\n * @template T - Type of the result record\n * @param lookupKey - Secondary key such as `email:user@example.com` or `username:alice`\n * @param sql - SQL statement to execute\n * @param bindings - Parameter values to bind to the SQL statement\n * @param batchSize - Number of concurrent shard queries during fanout (default: 50)\n * @returns Promise resolving to the first matching record, or null\n * @since 1.1.4\n */\nexport async function firstByLookupKey<T = Record<string, unknown>>(\n\tlookupKey: string,\n\tsql: string,\n\tbindings: any[] = [],\n\tbatchSize: number = 50\n): Promise<T | null> {\n\tconst config = getConfig();\n\tconst mapper = getMapper(config);\n\tconst mapping = await mapper.getShardMapping(lookupKey);\n\n\tif (mapping) {\n\t\tconst mappedShardDb = config.shards[mapping.shard];\n\t\tif (mappedShardDb) {\n\t\t\tconst mappedFirst = await firstShard<T>(mapping.shard, sql, bindings);\n\t\t\tif (mappedFirst !== null) {\n\t\t\t\treturn mappedFirst;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst fanoutResults = await firstAllShards<T>(sql, bindings, batchSize);\n\treturn fanoutResults.find((row): row is T => row !== null) ?? null;\n}\n\n/**\n * Reassigns a primary key to a different shard\n *\n * Moves a primary key and its associated data from one shard to another. This\n * operation is useful for load balancing, shard maintenance, or geographic\n * redistribution of data.\n *\n * The reassignment process:\n * 1. Validates the target shard exists in configuration\n * 2. Checks that a mapping exists for the primary key\n * 3. If target shard differs from current, migrates the data\n * 4. Updates the KV mapping to point to the new shard\n *\n * **Note**: This operation involves data migration and should be used\n * carefully in production environments. Consider the impact on ongoing queries.\n *\n * @param primaryKey - Primary key to reassign to a different shard\n * @param newBinding - New shard binding name where the data should be moved\n * @param tableName - Name of the table containing the record to migrate\n * @returns Promise that resolves when reassignment and migration are complete\n * @throws {Error} If target shard not found, mapping doesn't exist, or migration fails\n * @example\n * ```typescript\n * // Move a user from east to west coast for better latency\n * try {\n * await reassignShard('user-california-123', 'db-west', 'users');\n * console.log('User successfully moved to west coast shard');\n * } catch (error) {\n * console.error('Reassignment failed:', error.message);\n * }\n *\n * // Load balancing: move high-activity user to dedicated shard\n * await reassignShard('user-enterprise-456', 'db-dedicated', 'users');\n * ```\n */\nexport async function reassignShard(primaryKey: string, newBinding: string, tableName: string): Promise<void> {\n\tconst config = getConfig();\n\n\tif (!config.shards[newBinding]) {\n\t\tthrow new CollegeDBError(`Shard ${newBinding} not found in configuration`, 'SHARD_NOT_FOUND');\n\t}\n\n\tconst mapper = getMapper(config);\n\tconst currentMapping = await mapper.getShardMapping(primaryKey);\n\n\tif (!currentMapping) {\n\t\tthrow new CollegeDBError(`No existing mapping found for primary key: ${primaryKey}`, 'MAPPING_NOT_FOUND');\n\t}\n\n\t// Migrate data if different shard\n\tif (currentMapping.shard !== newBinding) {\n\t\tconst { migrateRecord } = await import('./migrations');\n\t\tconst sourceDb = config.shards[currentMapping.shard];\n\t\tconst targetDb = config.shards[newBinding];\n\n\t\tif (!sourceDb || !targetDb) {\n\t\t\tthrow new CollegeDBError('Source or target shard not available', 'SHARD_UNAVAILABLE');\n\t\t}\n\n\t\tawait migrateRecord(sourceDb, targetDb, primaryKey, tableName);\n\t}\n\n\t// Update mapping\n\tawait mapper.updateShardMapping(primaryKey, newBinding);\n}\n\n/**\n * Lists all known shards\n *\n * Returns an array of all shard binding names known to the system. First\n * attempts to get the list from the Durable Object coordinator for the most\n * up-to-date information, then falls back to the configured shards if the\n * coordinator is unavailable.\n *\n * @returns Promise resolving to array of shard binding names\n * @example\n * ```typescript\n * const shards = await listKnownShards();\n * console.log('Available shards:', shards);\n * // Output: ['db-east', 'db-west', 'db-central']\n *\n * // Check if a specific shard is available\n * if (shards.includes('db-asia')) {\n * console.log('Asia region shard is available');\n * }\n * ```\n */\nexport async function listKnownShards(): Promise<string[]> {\n\tconst config = getConfig();\n\n\t// Try to get from coordinator first\n\tif (config.coordinator) {\n\t\ttry {\n\t\t\tconst coordinatorId = config.coordinator.idFromName('default');\n\t\t\tconst coordinator = config.coordinator.get(coordinatorId);\n\n\t\t\tconst response = await coordinator.fetch('http://coordinator/shards');\n\t\t\tif (response.ok) {\n\t\t\t\treturn await response.json();\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.warn('Failed to get shards from coordinator:', error);\n\t\t}\n\t}\n\n\t// Fallback: merge configured shards with KV-known shards\n\ttry {\n\t\tconst mapper = getMapper(config);\n\t\tconst kvShards = await mapper.getKnownShards();\n\t\tconst merged = new Set<string>([...Object.keys(config.shards), ...kvShards]);\n\t\treturn Array.from(merged);\n\t} catch {\n\t\t// If KV lookup fails, just return configured shards\n\t\treturn Object.keys(config.shards);\n\t}\n}\n\n/**\n * Gets statistics for all shards\n *\n * Returns usage statistics for all known shards, including key counts and\n * last updated timestamps. First attempts to get real-time statistics from\n * the Durable Object coordinator, then falls back to KV-based counting.\n *\n * This information is useful for:\n * - Load balancing decisions\n * - Monitoring shard utilization\n * - Capacity planning\n * - Performance analysis\n *\n * @returns Promise resolving to array of shard statistics\n * @example\n * ```typescript\n * const stats = await getShardStats();\n * stats.forEach(shard => {\n * console.log(`${shard.binding}: ${shard.count} keys`);\n * if (shard.lastUpdated) {\n * console.log(` Last updated: ${new Date(shard.lastUpdated)}`);\n * }\n * });\n *\n * // Find most loaded shard\n * const mostLoaded = stats.reduce((prev, current) =>\n * (prev.count > current.count) ? prev : current\n * );\n * console.log(`Most loaded shard: ${mostLoaded.binding} (${mostLoaded.count} keys)`);\n * ```\n */\nexport async function getShardStats(): Promise<ShardStats[]> {\n\tconst config = getConfig();\n\n\t// Try to get from coordinator first\n\tif (config.coordinator) {\n\t\ttry {\n\t\t\tconst coordinatorId = config.coordinator.idFromName('default');\n\t\t\tconst coordinator = config.coordinator.get(coordinatorId);\n\n\t\t\tconst response = await coordinator.fetch('http://coordinator/stats');\n\t\t\tif (response.ok) {\n\t\t\t\treturn await response.json();\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.warn('Failed to get stats from coordinator:', error);\n\t\t}\n\t}\n\n\t// Fallback to KV-based counting\n\tconst mapper = getMapper(config);\n\tconst counts = await mapper.getShardKeyCounts();\n\n\t// Merge shards from config and KV known shards\n\tlet shardNames = Object.keys(config.shards);\n\ttry {\n\t\tconst kvKnown = await mapper.getKnownShards();\n\t\tshardNames = Array.from(new Set([...shardNames, ...kvKnown]));\n\t} catch {}\n\n\treturn shardNames.map((binding) => ({\n\t\tbinding,\n\t\tcount: counts[binding] || 0\n\t}));\n}\n\n/**\n * Bypasses the normal routing logic to execute a query directly on a specified\n * shard. This is useful for administrative operations, cross-shard queries,\n * or when you need to query data that doesn't follow the primary key routing pattern.\n *\n * **Use with caution**: This function bypasses routing safeguards and should\n * be used only when you specifically need to target a particular shard.\n *\n * @param shardBinding - The shard binding name to execute the query on\n * @param sql - SQL statement to execute\n * @param bindings - Parameter values to bind to the SQL statement\n * @returns Promise resolving to the result of the query execution\n * @throws {Error} If shard not found or query fails\n * @example\n * ```typescript\n * // Administrative query: insert a new user directly into a specific shard\n * const result = await runShard('db-east',\n * 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)',\n * ['user-789', 'Alice', 'alice@example.com']\n * );\n * console.log(`Inserted user with ID: ${result.lastInsertId}`);\n * ```\n */\nexport async function runShard<T = Record<string, unknown>>(\n\tshardBinding: string,\n\tsql: string,\n\tbindings: any[] = []\n): Promise<QueryResult<T>> {\n\tconst config = getConfig();\n\tconst db = config.shards[shardBinding];\n\n\tif (!db) {\n\t\tthrow new CollegeDBError(`Shard ${shardBinding} not found`, 'SHARD_NOT_FOUND');\n\t}\n\n\tconst result = await db\n\t\t.prepare(sql)\n\t\t.bind(...bindings)\n\t\t.run<T>();\n\n\tif (!result.success) {\n\t\tthrow new CollegeDBError(`Query failed: ${result.error || 'Unknown error'}`, 'QUERY_FAILED');\n\t}\n\n\treturn result;\n}\n\n/**\n * Bypasses the normal routing logic to execute a query directly on a specified\n * shard. This is useful for administrative operations, cross-shard queries,\n * or when you need to query data that doesn't follow the primary key routing pattern.\n *\n * **Use with caution**: This function bypasses routing safeguards and should\n * be used only when you specifically need to target a particular shard.\n *\n * @param shardBinding - The shard binding name to execute the query on\n * @param sql - SQL statement to execute\n * @param bindings - Parameter values to bind to the SQL statement\n * @returns Promise resolving to structured query results\n * @throws {Error} If shard not found or query fails\n * @example\n * ```typescript\n * // Administrative query: count all users across a specific shard\n * const eastCoastStats = await allShard('db-east',\n * 'SELECT COUNT(*) as user_count FROM users'\n * );\n * console.log(`East coast users: ${eastCoastStats.results[0].user_count}`);\n *\n * // Cross-shard analytics: get recent posts from a specific region\n * const recentPosts = await allShard('db-west',\n * 'SELECT id, title, created_at FROM posts WHERE created_at > ? ORDER BY created_at DESC LIMIT ?',\n * [Date.now() - 86400000, 10] // Last 24 hours, limit 10\n * );\n *\n * // Schema inspection on specific shard\n * const tables = await allShard('db-central',\n * \"SELECT name FROM sqlite_master WHERE type='table'\"\n * );\n * ```\n */\nexport async function allShard<T = Record<string, unknown>>(\n\tshardBinding: string,\n\tsql: string,\n\tbindings: any[] = []\n): Promise<QueryResult<T>> {\n\tconst config = getConfig();\n\tconst db = config.shards[shardBinding];\n\n\tif (!db) {\n\t\tthrow new CollegeDBError(`Shard ${shardBinding} not found`, 'SHARD_NOT_FOUND');\n\t}\n\n\tconst result = await db\n\t\t.prepare(sql)\n\t\t.bind(...bindings)\n\t\t.all<T>();\n\n\treturn result;\n}\n\n/**\n * Bypasses the normal routing logic to execute a query directly on a specified\n * shard. This is useful for administrative operations, cross-shard queries,\n * or when you need to query data that doesn't follow the primary key routing pattern.\n *\n * **Use with caution**: This function bypasses routing safeguards and should\n * be used only when you specifically need to target a particular shard.\n *\n * @param shardBinding - The shard binding name to execute the query on\n * @param sql - SQL statement to execute\n * @param bindings - Parameter values to bind to the SQL statement\n * @returns Promise resolving to the first matching record, or null if not found\n * @throws {Error} If shard not found or query fails\n * @example\n * ```typescript\n * // Administrative query: get a specific user from a shard\n * const user = await firstShard('db-east',\n * 'SELECT * FROM users WHERE id = ?',\n * ['user-123']);\n * if (user) {\n * console.log(`Found user: ${user.name}`);\n * } else {\n * console.log('User not found in east shard');\n * }\n * ```\n */\nexport async function firstShard<T = Record<string, unknown>>(shardBinding: string, sql: string, bindings: any[] = []): Promise<T | null> {\n\tconst config = getConfig();\n\tconst db = config.shards[shardBinding];\n\n\tif (!db) {\n\t\tthrow new CollegeDBError(`Shard ${shardBinding} not found`, 'SHARD_NOT_FOUND');\n\t}\n\n\tconst result = await db\n\t\t.prepare(sql)\n\t\t.bind(...bindings)\n\t\t.first<T>();\n\n\treturn result;\n}\n\n/**\n * Executes a query on all shards and returns the results from each shard.\n *\n * This function is useful for scenarios where you need to aggregate data\n * from multiple shards, such as running analytics or cross-shard queries.\n * It executes the same SQL statement on each shard and collects the results.\n * @param sql - The SQL statement to execute on each shard\n * @param bindings - Parameter values to bind to the SQL statement\n * @param batchSize - Number of concurrent queries to run at once (default: 50)\n * @returns Promise resolving to an array of results from each shard\n * @since 1.0.4\n */\nexport async function runAllShards<T = Record<string, unknown>>(\n\tsql: string,\n\tbindings: any[] = [],\n\tbatchSize: number = 50\n): Promise<QueryResult<T>[]> {\n\tconst config = getConfig();\n\tconst tasks: Array<() => Promise<QueryResult<T>>> = [];\n\n\tfor (const [binding, db] of Object.entries(config.shards)) {\n\t\tif (!binding || !db) {\n\t\t\tconsole.error(`Shard ${binding ?? '<null>'} not found, skipping`);\n\t\t\tcontinue;\n\t\t}\n\n\t\ttasks.push(() =>\n\t\t\tdb\n\t\t\t\t.prepare(sql)\n\t\t\t\t.bind(...bindings)\n\t\t\t\t.run<T>()\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tconsole.error(`Error executing query on shard ${binding}:`, error);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\tresults: [],\n\t\t\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t\tmeta: { duration: 0 }\n\t\t\t\t\t} satisfies QueryResult<T>;\n\t\t\t\t})\n\t\t);\n\t}\n\n\tconst out: QueryResult<T>[] = [];\n\tfor (let i = 0; i < tasks.length; i += batchSize) {\n\t\tconst batch = tasks.slice(i, i + batchSize).map((fn) => fn());\n\t\tout.push(...(await Promise.all(batch)));\n\t}\n\n\treturn out;\n}\n\n/**\n * Executes a query on all shards and returns all matching records from each shard.\n *\n * This function is useful for scenarios where you need to retrieve all records\n * matching a query across multiple shards, such as aggregating data or running\n * cross-shard analytics.\n * @param sql - The SQL statement to execute on each shard\n * @param bindings - Parameter values to bind to the SQL statement\n * @param batchSize - Number of concurrent queries to run at once (default: 50)\n * @returns Promise resolving to an array of results from each shard\n * @since 1.0.4\n */\nexport async function allAllShards<T = Record<string, unknown>>(\n\tsql: string,\n\tbindings: any[] = [],\n\tbatchSize: number = 50\n): Promise<QueryResult<T>[]> {\n\tconst config = getConfig();\n\tconst tasks: Array<() => Promise<QueryResult<T>>> = [];\n\n\tfor (const [binding, db] of Object.entries(config.shards)) {\n\t\tif (!binding || !db) {\n\t\t\tconsole.error(`Shard ${binding ?? '<null>'} not found, skipping`);\n\t\t\tcontinue;\n\t\t}\n\n\t\ttasks.push(() =>\n\t\t\tdb\n\t\t\t\t.prepare(sql)\n\t\t\t\t.bind(...bindings)\n\t\t\t\t.all<T>()\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tconsole.error(`Error executing query on shard ${binding}:`, error);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\tresults: [],\n\t\t\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t\tmeta: { duration: 0 }\n\t\t\t\t\t} satisfies QueryResult<T>;\n\t\t\t\t})\n\t\t);\n\t}\n\n\tconst out: QueryResult<T>[] = [];\n\tfor (let i = 0; i < tasks.length; i += batchSize) {\n\t\tconst batch = tasks.slice(i, i + batchSize).map((fn) => fn());\n\t\tout.push(...(await Promise.all(batch)));\n\t}\n\n\treturn out;\n}\n\n/**\n * Options for global all-shards merge/sort/pagination.\n * @since 1.1.4\n */\nexport interface GlobalAllShardsOptions<T = Record<string, unknown>> {\n\t/** Number of concurrent shard queries to run at once (default: 50). */\n\tbatchSize?: number;\n\t/** Number of rows to skip after global merge/sort (default: 0). */\n\toffset?: number;\n\t/** Maximum rows to return after global merge/sort. */\n\tlimit?: number;\n\t/** Field name or selector used for global sorting. */\n\tsortBy?: keyof T | ((row: T) => unknown);\n\t/** Sort direction for `sortBy` (default: `asc`). */\n\tsortDirection?: 'asc' | 'desc';\n\t/** Optional custom comparator; takes precedence over `sortBy`. */\n\tcomparator?: (left: T, right: T) => number;\n\t/** Optional global row filter applied before sort/paginate. */\n\tfilter?: (row: T) => boolean;\n}\n\nfunction normalizeBatchSize(batchSize: number | undefined, defaultValue: number = 50): number {\n\tif (!Number.isFinite(batchSize ?? defaultValue)) {\n\t\treturn defaultValue;\n\t}\n\n\treturn Math.max(1, Math.floor(batchSize ?? defaultValue));\n}\n\nfunction normalizeOffset(offset: number | undefined): number {\n\tif (!Number.isFinite(offset ?? 0)) {\n\t\treturn 0;\n\t}\n\n\treturn Math.max(0, Math.floor(offset ?? 0));\n}\n\nfunction normalizeLimit(limit: number | undefined): number | undefined {\n\tif (limit === undefined) {\n\t\treturn undefined;\n\t}\n\n\tif (!Number.isFinite(limit)) {\n\t\treturn undefined;\n\t}\n\n\treturn Math.max(0, Math.floor(limit));\n}\n\nfunction getRowSortValue<T>(row: T, sortBy: GlobalAllShardsOptions<T>['sortBy']): unknown {\n\tif (typeof sortBy === 'function') {\n\t\treturn sortBy(row);\n\t}\n\n\tif (!sortBy || typeof row !== 'object' || row === null) {\n\t\treturn undefined;\n\t}\n\n\treturn (row as Record<string, unknown>)[String(sortBy)];\n}\n\nfunction compareUnknown(left: unknown, right: unknown): number {\n\tif (left === right) return 0;\n\tif (left === null || left === undefined) return 1;\n\tif (right === null || right === undefined) return -1;\n\n\tif (typeof left === 'number' && typeof right === 'number') {\n\t\treturn left - right;\n\t}\n\n\tif (typeof left === 'bigint' && typeof right === 'bigint') {\n\t\treturn left < right ? -1 : 1;\n\t}\n\n\tif (left instanceof Date && right instanceof Date) {\n\t\treturn left.getTime() - right.getTime();\n\t}\n\n\tif (typeof left === 'boolean' && typeof right === 'boolean') {\n\t\treturn Number(left) - Number(right);\n\t}\n\n\treturn String(left).localeCompare(String(right), undefined, { numeric: true, sensitivity: 'base' });\n}\n\nfunction mergeAllShardQueryResults<T = Record<string, unknown>>(shardResults: QueryResult<T>[]): QueryResult<T> {\n\tconst allResults = shardResults.flatMap((result) => result.results || []);\n\tconst failures = shardResults.filter((result) => !result.success);\n\tconst totalDuration = shardResults.reduce((sum, result) => sum + (result.meta?.duration || 0), 0);\n\n\tif (failures.length === 0) {\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: allResults,\n\t\t\tmeta: { duration: totalDuration }\n\t\t};\n\t}\n\n\tconst errorMessage = failures\n\t\t.map((failure) => failure.error || 'Unknown shard query error')\n\t\t.filter(Boolean)\n\t\t.join('; ');\n\n\treturn {\n\t\tsuccess: false,\n\t\tresults: allResults,\n\t\terror: errorMessage || 'One or more shard queries failed',\n\t\tmeta: { duration: totalDuration }\n\t};\n}\n\n/**\n * Executes a query on all shards and applies global merge/sort/pagination in-library.\n *\n * Unlike `allAllShards`, this helper returns a single merged `QueryResult` and can\n * sort/paginate across the full combined result set after fanout.\n *\n * @template T - Type of the result records\n * @param sql - SQL statement to execute on each shard\n * @param bindings - Parameter values to bind to the SQL statement\n * @param options - Global merge/sort/pagination options\n * @returns Promise resolving to one globally-processed query result\n * @since 1.1.4\n */\nexport async function allAllShardsGlobal<T = Record<string, unknown>>(\n\tsql: string,\n\tbindings: any[] = [],\n\toptions: GlobalAllShardsOptions<T> = {}\n): Promise<QueryResult<T>> {\n\tconst batchSize = normalizeBatchSize(options.batchSize);\n\tconst offset = normalizeOffset(options.offset);\n\tconst limit = normalizeLimit(options.limit);\n\n\tconst merged = mergeAllShardQueryResults(await allAllShards<T>(sql, bindings, batchSize));\n\tlet rows = merged.results;\n\n\tif (options.filter) {\n\t\trows = rows.filter((row) => options.filter?.(row));\n\t}\n\n\tif (options.comparator) {\n\t\trows = [...rows].sort(options.comparator);\n\t} else if (options.sortBy) {\n\t\tconst direction = options.sortDirection === 'desc' ? -1 : 1;\n\t\trows = [...rows].sort((left, right) => {\n\t\t\tconst leftValue = getRowSortValue(left, options.sortBy);\n\t\t\tconst rightValue = getRowSortValue(right, options.sortBy);\n\t\t\treturn compareUnknown(leftValue, rightValue) * direction;\n\t\t});\n\t}\n\n\tconst end = limit === undefined ? undefined : offset + limit;\n\tconst pagedRows = rows.slice(offset, end);\n\n\treturn {\n\t\t...merged,\n\t\tresults: pagedRows\n\t};\n}\n\n/**\n * Executes a query on all shards and returns the first matching record from each shard.\n *\n * This function is useful for scenarios where you need to retrieve a single record\n * from each shard, such as fetching the latest entry or a specific item that may\n * exist on multiple shards.\n * @param sql - The SQL statement to execute\n * @param bindings - Parameter values to bind to the SQL statement\n * @param batchSize - Number of concurrent queries to run at once (default: 50)\n * @returns Promise resolving to an array of first matching records from each shard\n * @since 1.0.4\n */\nexport async function firstAllShards<T = Record<string, unknown>>(\n\tsql: string,\n\tbindings: any[] = [],\n\tbatchSize: number = 50\n): Promise<(T | null)[]> {\n\tconst config = getConfig();\n\tconst tasks: Array<() => Promise<T | null>> = [];\n\n\tfor (const [binding, db] of Object.entries(config.shards)) {\n\t\tif (!binding || !db) {\n\t\t\tconsole.error(`Shard ${binding ?? '<null>'} not found, skipping`);\n\t\t\tcontinue;\n\t\t}\n\n\t\ttasks.push(() =>\n\t\t\tdb\n\t\t\t\t.prepare(sql)\n\t\t\t\t.bind(...bindings)\n\t\t\t\t.first<T>()\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tconsole.error(`Error executing query on shard ${binding}:`, error);\n\t\t\t\t\treturn null;\n\t\t\t\t})\n\t\t);\n\t}\n\n\tconst out: (T | null)[] = [];\n\tfor (let i = 0; i < tasks.length; i += batchSize) {\n\t\tconst batch = tasks.slice(i, i + batchSize).map((fn) => fn());\n\t\tout.push(...(await Promise.all(batch)));\n\t}\n\n\treturn out;\n}\n\n/**\n * Executes a query on all shards with global merge/sort/pagination and returns\n * the first row after global processing.\n *\n * @template T - Type of the result record\n * @param sql - SQL statement to execute on each shard\n * @param bindings - Parameter values to bind to the SQL statement\n * @param options - Global merge/sort/pagination options (batchSize, sort, offset)\n * @returns Promise resolving to the first globally-processed row, or null\n * @since 1.1.4\n */\nexport async function firstAllShardsGlobal<T = Record<string, unknown>>(\n\tsql: string,\n\tbindings: any[] = [],\n\toptions: Omit<GlobalAllShardsOptions<T>, 'limit'> = {}\n): Promise<T | null> {\n\tconst merged = await allAllShardsGlobal<T>(sql, bindings, {\n\t\t...options,\n\t\tlimit: 1\n\t});\n\n\treturn merged.results[0] ?? null;\n}\n\n/**\n * Flushes all shard mappings (development only)\n *\n * Completely clears all primary key to shard mappings from both KV storage\n * and the Durable Object coordinator. This operation resets the entire\n * routing system to a clean state.\n *\n * **DANGER**: This operation is destructive and irreversible. After flushing,\n * all existing primary keys will be treated as new and may be assigned to\n * different shards than before, causing data routing issues.\n *\n * **Use only for**:\n * - Development and testing environments\n * - Complete system resets\n * - Emergency recovery scenarios\n *\n * @returns Promise that resolves when all mappings are cleared\n * @example\n * ```typescript\n * // Only use in development!\n * if (process.env.NODE_ENV === 'development') {\n * await flush();\n * console.log('All shard mappings cleared for testing');\n *\n * // Now all keys will be reassigned on next access\n * await run('user-123', 'INSERT INTO users (id, name) VALUES (?, ?)',\n * ['user-123', 'Test User']);\n * }\n * ```\n */\nexport async function flush(): Promise<void> {\n\tconst config = getConfig();\n\tconst mapper = getMapper(config);\n\n\tawait mapper.clearAllMappings();\n\tshardSizeCache.clear();\n\n\t// Also flush coordinator if available\n\tif (config.coordinator) {\n\t\ttry {\n\t\t\tconst coordinatorId = config.coordinator.idFromName('default');\n\t\t\tconst coordinator = config.coordinator.get(coordinatorId);\n\n\t\t\tawait coordinator.fetch('http://coordinator/flush', { method: 'POST' });\n\t\t} catch (error) {\n\t\t\tconsole.warn('Failed to flush coordinator:', error);\n\t\t}\n\t}\n}\n\n/**\n * Gets the size of a specific D1 database in bytes.\n * Uses efficient SQLite pragma queries to determine database size.\n *\n * @param shardBinding - The shard binding name to check the size of\n * @returns Promise resolving to the database size in bytes\n * @throws {CollegeDBError} If shard not found or size query fails\n * @example\n * ```typescript\n * // Get size of a specific shard\n * const sizeInBytes = await getDatabaseSizeForShard('db-east');\n * console.log(`Database size: ${Math.round(sizeInBytes / 1024 / 1024)} MB`);\n * ```\n */\nexport async function getDatabaseSizeForShard(shardBinding: string): Promise<number> {\n\tconst config = getConfig();\n\tconst database = config.shards[shardBinding];\n\n\tif (!database) {\n\t\tthrow new CollegeDBError(`Shard ${shardBinding} not found`, 'SHARD_NOT_FOUND');\n\t}\n\n\treturn await getDatabaseSize(database);\n}\n\nconst SQL_IDENTIFIER_PART_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nfunction quoteIdentifier(identifier: string): string {\n\tconst trimmed = identifier.trim();\n\tif (!trimmed) {\n\t\tthrow new CollegeDBError('Identifier cannot be empty', 'INVALID_IDENTIFIER');\n\t}\n\n\tconst parts = trimmed.split('.').map((part) => part.trim());\n\tif (parts.some((part) => !part || !SQL_IDENTIFIER_PART_REGEX.test(part))) {\n\t\tthrow new CollegeDBError(`Invalid SQL identifier: ${identifier}`, 'INVALID_IDENTIFIER');\n\t}\n\n\treturn parts.map((part) => `\"${part}\"`).join('.');\n}\n\nfunction normalizeIndexNameSegment(value: string): string {\n\treturn value\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9_]+/g, '_')\n\t\t.replace(/_+/g, '_')\n\t\t.replace(/^_+|_+$/g, '');\n}\n\n/**\n * Column specification for index creation helpers.\n * @since 1.1.4\n */\nexport interface IndexColumnDefinition {\n\t/** Column name to include in the index. */\n\tname: string;\n\t/** Optional sort direction for this column. */\n\torder?: 'ASC' | 'DESC';\n\t/** Optional collation (e.g., NOCASE). */\n\tcollate?: string;\n}\n\n/**\n * Options for index creation helpers.\n * @since 1.1.4\n */\nexport interface CreateIndexOptions {\n\t/** Explicit index name. When omitted, a deterministic name is generated. */\n\tindexName?: string;\n\t/** Create a unique index. */\n\tunique?: boolean;\n\t/** Include `IF NOT EXISTS` in generated SQL. @default true */\n\tifNotExists?: boolean;\n\t/** Optional partial-index predicate (trusted SQL only). */\n\twhere?: string;\n\t/** Number of concurrent shard operations for all-shard variants. @default 50 */\n\tbatchSize?: number;\n}\n\nfunction normalizeIndexColumns(columns: string | string[] | IndexColumnDefinition[]): IndexColumnDefinition[] {\n\tif (typeof columns === 'string') {\n\t\treturn [{ name: columns }];\n\t}\n\n\tif (!Array.isArray(columns) || columns.length === 0) {\n\t\tthrow new CollegeDBError('At least one index column is required', 'INVALID_INDEX_COLUMNS');\n\t}\n\n\treturn columns.map((column) => {\n\t\tif (typeof column === 'string') {\n\t\t\treturn { name: column };\n\t\t}\n\n\t\tif (!column?.name) {\n\t\t\tthrow new CollegeDBError('Index column name is required', 'INVALID_INDEX_COLUMNS');\n\t\t}\n\n\t\treturn {\n\t\t\tname: column.name,\n\t\t\torder: column.order,\n\t\t\tcollate: column.collate\n\t\t};\n\t});\n}\n\nfunction buildCreateIndexSQL(\n\ttable: string,\n\tcolumns: string | string[] | IndexColumnDefinition[],\n\toptions: CreateIndexOptions = {}\n): string {\n\tconst normalizedColumns = normalizeIndexColumns(columns);\n\tconst quotedTable = quoteIdentifier(table);\n\tconst generatedIndexName = options.indexName\n\t\t? options.indexName\n\t\t: ['idx', normalizeIndexNameSegment(table), ...normalizedColumns.map((column) => normalizeIndexNameSegment(column.name))]\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.join('_')\n\t\t\t\t.slice(0, 120);\n\tconst quotedIndexName = quoteIdentifier(generatedIndexName || 'idx_auto');\n\n\tconst columnClauses = normalizedColumns\n\t\t.map((column) => {\n\t\t\tconst quotedColumn = quoteIdentifier(column.name);\n\t\t\tconst order = column.order ? ` ${column.order}` : '';\n\t\t\tconst collate = column.collate ? ` COLLATE ${quoteIdentifier(column.collate).replace(/\"/g, '')}` : '';\n\t\t\treturn `${quotedColumn}${collate}${order}`;\n\t\t})\n\t\t.join(', ');\n\n\tconst ifNotExistsClause = options.ifNotExists === false ? '' : ' IF NOT EXISTS';\n\tconst uniqueClause = options.unique ? 'UNIQUE ' : '';\n\tconst whereClause = options.where?.trim() ? ` WHERE ${options.where.trim()}` : '';\n\n\treturn `CREATE ${uniqueClause}INDEX${ifNotExistsClause} ${quotedIndexName} ON ${quotedTable} (${columnClauses})${whereClause}`;\n}\n\n/**\n * Creates an index on the shard resolved by the provided key.\n *\n * @param key - Primary key used for shard routing\n * @param table - Target table name\n * @param columns - One or more columns to index\n * @param options - Index creation options\n * @returns Query result for the DDL statement\n * @since 1.1.4\n */\nexport async function index<T = Record<string, unknown>>(\n\tkey: string,\n\ttable: string,\n\tcolumns: string | string[] | IndexColumnDefinition[],\n\toptions: Omit<CreateIndexOptions, 'batchSize'> = {}\n): Promise<QueryResult<T>> {\n\tconst sql = buildCreateIndexSQL(table, columns, options);\n\treturn run<T>(key, sql);\n}\n\n/**\n * Creates an index directly on a specific shard.\n *\n * @param shardBinding - Shard binding name\n * @param table - Target table name\n * @param columns - One or more columns to index\n * @param options - Index creation options\n * @returns Query result for the DDL statement\n * @since 1.1.4\n */\nexport async function indexShard<T = Record<string, unknown>>(\n\tshardBinding: string,\n\ttable: string,\n\tcolumns: string | string[] | IndexColumnDefinition[],\n\toptions: Omit<CreateIndexOptions, 'batchSize'> = {}\n): Promise<QueryResult<T>> {\n\tconst sql = buildCreateIndexSQL(table, columns, options);\n\treturn runShard<T>(shardBinding, sql);\n}\n\n/**\n * Creates an index across all configured shards.\n *\n * @param table - Target table name\n * @param columns - One or more columns to index\n * @param options - Index creation options, including `batchSize`\n * @returns Per-shard query results\n * @since 1.1.4\n */\nexport async function indexAllShards<T = Record<string, unknown>>(\n\ttable: string,\n\tcolumns: string | string[] | IndexColumnDefinition[],\n\toptions: CreateIndexOptions = {}\n): Promise<QueryResult<T>[]> {\n\tconst sql = buildCreateIndexSQL(table, columns, options);\n\treturn runAllShards<T>(sql, [], normalizeBatchSize(options.batchSize));\n}\n\n/**\n * Explain helpers options.\n * @since 1.1.4\n */\nexport interface ExplainOptions {\n\t/** Explain mode. @default query-plan */\n\tmode?: 'query-plan' | 'raw' | 'analyze';\n\t/** Number of concurrent shard operations for all-shard variants. @default 50 */\n\tbatchSize?: number;\n}\n\nfunction buildExplainSQL(sql: string, mode: ExplainOptions['mode'] = 'query-plan'): string {\n\tswitch (mode) {\n\t\tcase 'raw':\n\t\t\treturn `EXPLAIN ${sql}`;\n\t\tcase 'analyze':\n\t\t\treturn `EXPLAIN ANALYZE ${sql}`;\n\t\tcase 'query-plan':\n\t\tdefault:\n\t\t\treturn `EXPLAIN QUERY PLAN ${sql}`;\n\t}\n}\n\n/**\n * Executes an explain query on the shard resolved by key.\n *\n * @param key - Primary key used for shard routing\n * @param sql - SQL statement to inspect\n * @param bindings - Parameter values for the SQL statement\n * @param options - Explain mode options\n * @returns Explain rows as a QueryResult\n * @since 1.1.4\n */\nexport async function explain<T = Record<string, unknown>>(\n\tkey: string,\n\tsql: string,\n\tbindings: any[] = [],\n\toptions: Omit<ExplainOptions, 'batchSize'> = {}\n): Promise<QueryResult<T>> {\n\treturn all<T>(key, buildExplainSQL(sql, options.mode), bindings);\n}\n\n/**\n * Executes an explain query on a specific shard.\n *\n * @param shardBinding - Shard binding name\n * @param sql - SQL statement to inspect\n * @param bindings - Parameter values for the SQL statement\n * @param options - Explain mode options\n * @returns Explain rows as a QueryResult\n * @since 1.1.4\n */\nexport async function explainShard<T = Record<string, unknown>>(\n\tshardBinding: string,\n\tsql: string,\n\tbindings: any[] = [],\n\toptions: Omit<ExplainOptions, 'batchSize'> = {}\n): Promise<QueryResult<T>> {\n\treturn allShard<T>(shardBinding, buildExplainSQL(sql, options.mode), bindings);\n}\n\n/**\n * Executes an explain query across all shards.\n *\n * @param sql - SQL statement to inspect\n * @param bindings - Parameter values for the SQL statement\n * @param options - Explain options, including `batchSize`\n * @returns Per-shard explain query results\n * @since 1.1.4\n */\nexport async function explainAllShards<T = Record<string, unknown>>(\n\tsql: string,\n\tbindings: any[] = [],\n\toptions: ExplainOptions = {}\n): Promise<QueryResult<T>[]> {\n\treturn allAllShards<T>(buildExplainSQL(sql, options.mode), bindings, normalizeBatchSize(options.batchSize));\n}\n\n/**\n * Table row-count result for a shard.\n * @since 1.1.4\n */\nexport interface ShardTableCount {\n\tshard: string;\n\tcount: number | null;\n\tsuccess: boolean;\n\terror?: string;\n}\n\n/**\n * Counts rows for a table on the shard resolved by key.\n *\n * @param key - Primary key used for shard routing\n * @param table - Table name to count\n * @returns Row count for that routed shard\n * @since 1.1.4\n */\nexport async function count(key: string, table: string): Promise<number> {\n\tconst quotedTable = quoteIdentifier(table);\n\tconst row = await first<{ row_count?: number | string }>(key, `SELECT COUNT(*) AS row_count FROM ${quotedTable}`);\n\tif (!row || row.row_count === undefined || row.row_count === null) {\n\t\treturn 0;\n\t}\n\n\treturn Number(row.row_count) || 0;\n}\n\n/**\n * Counts rows for a table on a specific shard.\n *\n * @param shardBinding - Shard binding name\n * @param table - Table name to count\n * @returns Row count for the shard\n * @since 1.1.4\n */\nexport async function countShard(shardBinding: string, table: string): Promise<number> {\n\tconst quotedTable = quoteIdentifier(table);\n\tconst row = await firstShard<{ row_count?: number | string }>(shardBinding, `SELECT COUNT(*) AS row_count FROM ${quotedTable}`);\n\tif (!row || row.row_count === undefined || row.row_count === null) {\n\t\treturn 0;\n\t}\n\n\treturn Number(row.row_count) || 0;\n}\n\n/**\n * Counts rows for a table across all shards.\n *\n * @param table - Table name to count\n * @param batchSize - Number of concurrent shard queries (default: 50)\n * @returns Per-shard counts and global total\n * @since 1.1.4\n */\nexport async function countAllShards(table: string, batchSize: number = 50): Promise<{ total: number; shards: ShardTableCount[] }> {\n\tconst config = getConfig();\n\tconst normalizedBatchSize = normalizeBatchSize(batchSize);\n\tconst quotedTable = quoteIdentifier(table);\n\tconst sql = `SELECT COUNT(*) AS row_count FROM ${quotedTable}`;\n\tconst tasks: Array<() => Promise<ShardTableCount>> = [];\n\n\tfor (const [binding, db] of Object.entries(config.shards)) {\n\t\tif (!binding || !db) {\n\t\t\tcontinue;\n\t\t}\n\n\t\ttasks.push(async () => {\n\t\t\ttry {\n\t\t\t\tconst row = await db.prepare(sql).first<{ row_count?: number | string }>();\n\t\t\t\tconst parsed = Number(row?.row_count ?? 0);\n\t\t\t\treturn {\n\t\t\t\t\tshard: binding,\n\t\t\t\t\tcount: Number.isFinite(parsed) ? parsed : 0,\n\t\t\t\t\tsuccess: true\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tshard: binding,\n\t\t\t\t\tcount: null,\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: error instanceof Error ? error.message : String(error)\n\t\t\t\t};\n\t\t\t}\n\t\t});\n\t}\n\n\tconst shards: ShardTableCount[] = [];\n\tfor (let i = 0; i < tasks.length; i += normalizedBatchSize) {\n\t\tconst batch = tasks.slice(i, i + normalizedBatchSize).map((task) => task());\n\t\tshards.push(...(await Promise.all(batch)));\n\t}\n\n\tconst total = shards.reduce((sum, shard) => sum + (shard.count ?? 0), 0);\n\treturn { total, shards };\n}\n\n/**\n * Size information for a shard.\n * @since 1.1.4\n */\nexport interface ShardSizeResult {\n\tshard: string;\n\tsize: number | null;\n\tsuccess: boolean;\n\terror?: string;\n}\n\n/**\n * Gets the size in bytes for the shard resolved by key.\n *\n * @param key - Primary key used for shard routing\n * @returns Database size in bytes\n * @since 1.1.4\n */\nexport async function getDatabaseSizeForKey(key: string): Promise<number> {\n\tconst config = getConfig();\n\tconst shardBinding = await getShardForKey(key, 'read');\n\tconst database = config.shards[shardBinding];\n\n\tif (!database) {\n\t\tthrow new CollegeDBError(`Shard ${shardBinding} not found in configuration`, 'SHARD_NOT_FOUND');\n\t}\n\n\treturn getDatabaseSize(database);\n}\n\n/**\n * Gets database sizes for all shards.\n *\n * @param batchSize - Number of concurrent shard queries (default: 50)\n * @returns Per-shard size results with success/error status\n * @since 1.1.4\n */\nexport async function getDatabaseSizesAllShards(batchSize: number = 50): Promise<ShardSizeResult[]> {\n\tconst config = getConfig();\n\tconst normalizedBatchSize = normalizeBatchSize(batchSize);\n\tconst tasks: Array<() => Promise<ShardSizeResult>> = [];\n\n\tfor (const [binding, db] of Object.entries(config.shards)) {\n\t\tif (!binding || !db) {\n\t\t\tcontinue;\n\t\t}\n\n\t\ttasks.push(async () => {\n\t\t\ttry {\n\t\t\t\treturn {\n\t\t\t\t\tshard: binding,\n\t\t\t\t\tsize: await getDatabaseSize(db),\n\t\t\t\t\tsuccess: true\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tshard: binding,\n\t\t\t\t\tsize: null,\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: error instanceof Error ? error.message : String(error)\n\t\t\t\t};\n\t\t\t}\n\t\t});\n\t}\n\n\tconst results: ShardSizeResult[] = [];\n\tfor (let i = 0; i < tasks.length; i += normalizedBatchSize) {\n\t\tconst batch = tasks.slice(i, i + normalizedBatchSize).map((task) => task());\n\t\tresults.push(...(await Promise.all(batch)));\n\t}\n\n\treturn results;\n}\n\n/**\n * Gets the combined size in bytes across all shards.\n *\n * Failed shard size checks are excluded from the sum.\n *\n * @param batchSize - Number of concurrent shard queries (default: 50)\n * @returns Total size in bytes across successfully measured shards\n * @since 1.1.4\n */\nexport async function getTotalDatabaseSize(batchSize: number = 50): Promise<number> {\n\tconst sizes = await getDatabaseSizesAllShards(batchSize);\n\treturn sizes.reduce((sum, result) => sum + (result.size ?? 0), 0);\n}\n",
9
+ "/**\n * @fileoverview Durable Object for coordinating shard allocation and maintaining statistics\n *\n * This module provides the ShardCoordinator Durable Object that manages shard allocation\n * strategies and maintains real-time statistics about shard utilization. It provides\n * an HTTP API for other parts of the system to interact with the coordinator.\n *\n * @example\n * ```typescript\n * // In wrangler.jsonc:\n * // {\n * // \"durable_objects\": {\n * // \"bindings\": [\n * // { \"name\": \"ShardCoordinator\", \"class_name\": \"ShardCoordinator\" }\n * // ]\n * // }\n * // }\n *\n * // Usage in a Worker:\n * const coordinatorId = env.ShardCoordinator.idFromName('default');\n * const coordinator = env.ShardCoordinator.get(coordinatorId);\n * const response = await coordinator.fetch('http://coordinator/allocate', {\n * method: 'POST',\n * body: JSON.stringify({ primaryKey: 'user-123', strategy: 'hash' })\n * });\n * ```\n *\n * @author CollegeDB Team\n * @since 1.0.0\n */\n\nimport type { DurableObjectState } from '@cloudflare/workers-types';\nimport { CollegeDBError } from './errors';\nimport type { D1Region, MixedShardingStrategy, OperationType, ShardCoordinatorState, ShardingStrategy } from './types';\n\n/**\n * Durable Object for coordinating shard allocation and maintaining statistics\n *\n * The ShardCoordinator is a Cloudflare Durable Object that provides centralized\n * coordination for shard allocation across multiple D1 databases. It maintains\n * state about available shards, allocation strategies, and usage statistics.\n *\n * Key responsibilities:\n * - Track available D1 shards and their current load\n * - Implement allocation strategies (round-robin, random, hash-based)\n * - Provide HTTP API for shard allocation and management\n * - Maintain persistent state using Durable Object storage\n *\n * @example\n * ```typescript\n * // Allocate a shard for a new primary key\n * const response = await coordinator.fetch('http://coordinator/allocate', {\n * method: 'POST',\n * body: JSON.stringify({ primaryKey: 'user-456', strategy: 'hash' })\n * });\n * const { shard } = await response.json();\n * ```\n */\nexport class ShardCoordinator {\n\t/**\n\t * Durable Object state handle for persistent storage\n\t * @private\n\t */\n\tprivate state: DurableObjectState;\n\n\t/**\n\t * Creates a new ShardCoordinator instance\n\t * @param state - Durable Object state provided by Cloudflare runtime\n\t */\n\tconstructor(state: DurableObjectState) {\n\t\tthis.state = state;\n\t}\n\n\t/**\n\t * Gets the current coordinator state from persistent storage\n\t *\n\t * Retrieves the coordinator state from Durable Object storage, returning\n\t * a default state if none exists. The state includes known shards, statistics,\n\t * allocation strategy, and round-robin counter.\n\t *\n\t * @private\n\t * @returns Promise resolving to the current coordinator state\n\t * @throws {Error} If storage access fails\n\t */\n\tprivate async getState(): Promise<ShardCoordinatorState> {\n\t\tconst state = await this.state.storage.get<ShardCoordinatorState>('coordinator_state');\n\t\treturn (\n\t\t\tstate || {\n\t\t\t\tknownShards: [],\n\t\t\t\tshardStats: {},\n\t\t\t\tstrategy: 'round-robin',\n\t\t\t\troundRobinIndex: 0\n\t\t\t}\n\t\t);\n\t}\n\n\t/**\n\t * Saves the coordinator state to persistent storage\n\t *\n\t * Persists the coordinator state to Durable Object storage. This includes\n\t * all shard information, statistics, and configuration.\n\t *\n\t * @private\n\t * @param state - The coordinator state to persist\n\t * @returns Promise that resolves when state is saved\n\t * @throws {Error} If storage write fails\n\t */\n\tprivate async saveState(state: ShardCoordinatorState): Promise<void> {\n\t\tawait this.state.storage.put('coordinator_state', state);\n\t}\n\n\t/**\n\t * Handles HTTP requests to the Durable Object\n\t *\n\t * Main entry point for all HTTP requests to the ShardCoordinator. Routes\n\t * requests based on method and path to appropriate handler functions.\n\t *\n\t * Supported endpoints:\n\t * - GET /shards - List all known shards\n\t * - POST /shards - Add a new shard\n\t * - DELETE /shards - Remove a shard\n\t * - GET /stats - Get shard statistics\n\t * - POST /stats - Update shard statistics\n\t * - POST /allocate - Allocate a shard for a primary key\n\t * - POST /flush - Clear all coordinator state (development only)\n\t * - GET /health - Health check endpoint\n\t *\n\t * @param request - The incoming HTTP request\n\t * @returns Promise resolving to HTTP response\n\t * @example\n\t * ```typescript\n\t * // Allocate a shard\n\t * const response = await coordinator.fetch('http://coordinator/allocate', {\n\t * method: 'POST',\n\t * headers: { 'Content-Type': 'application/json' },\n\t * body: JSON.stringify({ primaryKey: 'user-123' })\n\t * });\n\t * ```\n\t */\n\tasync fetch(request: Request): Promise<Response> {\n\t\tconst url = new URL(request.url);\n\t\tconst path = url.pathname;\n\t\tconst method = request.method;\n\n\t\ttry {\n\t\t\tswitch (`${method} ${path}`) {\n\t\t\t\tcase 'GET /shards':\n\t\t\t\t\treturn this.handleListShards();\n\t\t\t\tcase 'POST /shards':\n\t\t\t\t\treturn this.handleAddShard(request);\n\t\t\t\tcase 'DELETE /shards':\n\t\t\t\t\treturn this.handleRemoveShard(request);\n\t\t\t\tcase 'GET /stats':\n\t\t\t\t\treturn this.handleGetStats();\n\t\t\t\tcase 'POST /stats':\n\t\t\t\t\treturn this.handleUpdateStats(request);\n\t\t\t\tcase 'POST /allocate':\n\t\t\t\t\treturn this.handleAllocateShard(request);\n\t\t\t\tcase 'POST /flush':\n\t\t\t\t\treturn this.handleFlush();\n\t\t\t\tcase 'GET /health':\n\t\t\t\t\treturn new Response('OK', { status: 200 });\n\t\t\t\tdefault:\n\t\t\t\t\treturn new Response('Not Found', { status: 404 });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error('ShardCoordinator error:', error);\n\t\t\treturn new Response('Internal Server Error', { status: 500 });\n\t\t}\n\t}\n\n\t/**\n\t * Retrieves all known shards as a JSON array of all D1 binding names that have been registered\n\t * with the coordinator.\n\t * @private\n\t * @returns Promise resolving to HTTP response with shard list\n\t * @example Response body: `[\"db-east\", \"db-west\", \"db-central\"]`\n\t */\n\tprivate async handleListShards(): Promise<Response> {\n\t\tconst state = await this.getState();\n\t\treturn new Response(JSON.stringify(state.knownShards), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t});\n\t}\n\n\t/**\n\t * Registers a new D1 database binding with the coordinator. If the shard\n\t * is already known, this operation is idempotent. Initializes statistics\n\t * for the new shard.\n\t * @private\n\t * @param request - HTTP request containing shard binding name in JSON body\n\t * @returns Promise resolving to HTTP response indicating success\n\t * @throws {Error} If request body is invalid JSON\n\t * @example Request body: `{\"shard\": \"db-new-region\"}`\n\t */\n\tprivate async handleAddShard(request: Request): Promise<Response> {\n\t\tconst { shard } = (await request.json()) as { shard: string };\n\n\t\t// Validate required parameters\n\t\tif (!shard || typeof shard !== 'string') {\n\t\t\treturn new Response(JSON.stringify({ error: 'Missing or invalid shard parameter' }), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t\t});\n\t\t}\n\n\t\tconst state = await this.getState();\n\n\t\tif (!state.knownShards.includes(shard)) {\n\t\t\tstate.knownShards.push(shard);\n\t\t\tstate.shardStats[shard] = {\n\t\t\t\tbinding: shard,\n\t\t\t\tcount: 0,\n\t\t\t\tlastUpdated: Date.now()\n\t\t\t};\n\t\t\tawait this.saveState(state);\n\t\t}\n\n\t\treturn new Response(JSON.stringify({ success: true }), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t});\n\t}\n\n\t/**\n\t * Unregisters a D1 database binding from the coordinator. Removes the shard\n\t * from the known shards list and deletes its statistics. Adjusts the round-robin\n\t * index if necessary to prevent out-of-bounds access.\n\t * @private\n\t * @param request - HTTP request containing shard binding name in JSON body\n\t * @returns Promise resolving to HTTP response indicating success\n\t * @throws {Error} If request body is invalid JSON\n\t * @example Request body: `{\"shard\": \"db-old-region\"}`\n\t */\n\tprivate async handleRemoveShard(request: Request): Promise<Response> {\n\t\tconst { shard } = (await request.json()) as { shard: string };\n\n\t\t// Validate required parameters\n\t\tif (!shard || typeof shard !== 'string') {\n\t\t\treturn new Response(JSON.stringify({ error: 'Missing or invalid shard parameter' }), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t\t});\n\t\t}\n\n\t\tconst state = await this.getState();\n\n\t\tconst index = state.knownShards.indexOf(shard);\n\t\tif (index > -1) {\n\t\t\tstate.knownShards.splice(index, 1);\n\t\t\tdelete state.shardStats[shard];\n\t\t\t// Adjust round-robin index if necessary\n\t\t\tif (state.roundRobinIndex >= state.knownShards.length) {\n\t\t\t\tstate.roundRobinIndex = 0;\n\t\t\t}\n\t\t\tawait this.saveState(state);\n\t\t}\n\n\t\treturn new Response(JSON.stringify({ success: true }), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t});\n\t}\n\n\t/**\n\t * Returns an array of statistics for all known shards, including\n\t * binding names, key counts, and last updated timestamps.\n\t * @private\n\t * @returns Promise resolving to HTTP response with statistics array\n\t * @example Response body: `[{\"binding\": \"db-east\", \"count\": 1234, \"lastUpdated\": 1672531200000}]`\n\t */\n\tprivate async handleGetStats(): Promise<Response> {\n\t\tconst state = await this.getState();\n\t\tconst stats = Object.values(state.shardStats);\n\t\treturn new Response(JSON.stringify(stats), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t});\n\t}\n\n\t/**\n\t * Updates the key count and last updated timestamp for a specific shard.\n\t * Used by other parts of the system to report changes in shard utilization.\n\t * @private\n\t * @param request - HTTP request containing shard name and count in JSON body\n\t * @returns Promise resolving to HTTP response indicating success\n\t * @throws {Error} If request body is invalid JSON or shard doesn't exist\n\t * @example Request body: `{\"shard\": \"db-east\", \"count\": 1500}`\n\t */\n\tprivate async handleUpdateStats(request: Request): Promise<Response> {\n\t\tconst { shard, count } = (await request.json()) as { shard: string; count: number };\n\n\t\t// Validate required parameters\n\t\tif (!shard || typeof shard !== 'string') {\n\t\t\treturn new Response(JSON.stringify({ error: 'Missing or invalid shard parameter' }), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t\t});\n\t\t}\n\n\t\tif (count === undefined || typeof count !== 'number') {\n\t\t\treturn new Response(JSON.stringify({ error: 'Missing or invalid count parameter' }), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t\t});\n\t\t}\n\n\t\tconst state = await this.getState();\n\n\t\tif (state.shardStats[shard]) {\n\t\t\tstate.shardStats[shard].count = count;\n\t\t\tstate.shardStats[shard].lastUpdated = Date.now();\n\t\t\tawait this.saveState(state);\n\t\t}\n\n\t\treturn new Response(JSON.stringify({ success: true }), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t});\n\t}\n\n\t/**\n\t * Selects an appropriate shard for a new primary key using the specified\n\t * allocation strategy. Updates internal state for round-robin allocation.\n\t *\n\t * Supported strategies:\n\t * - round-robin: Cycles through shards in order\n\t * - random: Selects a random shard\n\t * - hash: Uses consistent hashing based on primary key\n\t *\n\t * @private\n\t * @param request - HTTP request containing primary key and optional strategy\n\t * @returns Promise resolving to HTTP response with selected shard\n\t * @throws {Error} If no shards are available or request body is invalid\n\t * @example Request body: `{\"primaryKey\": \"user-123\", \"strategy\": \"hash\"}`\n\t * @example Response body: `{\"shard\": \"db-west\"}`\n\t */\n\tprivate async handleAllocateShard(request: Request): Promise<Response> {\n\t\tconst { primaryKey, strategy, operationType, availableShards } = (await request.json()) as {\n\t\t\tprimaryKey: string;\n\t\t\tstrategy?: ShardingStrategy;\n\t\t\toperationType?: OperationType;\n\t\t\tavailableShards?: string[];\n\t\t};\n\n\t\tif (!primaryKey || typeof primaryKey !== 'string') {\n\t\t\treturn new Response(JSON.stringify({ error: 'Missing or invalid primaryKey parameter' }), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t\t});\n\t\t}\n\n\t\tconst state = await this.getState();\n\t\tconst eligibleShards = availableShards || state.knownShards;\n\n\t\tif (eligibleShards.length === 0) {\n\t\t\treturn new Response(JSON.stringify({ error: 'No shards available' }), {\n\t\t\t\tstatus: 400,\n\t\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t\t});\n\t\t}\n\n\t\tconst effectiveStrategy = this.resolveStrategy(state.strategy, strategy, operationType || 'write');\n\t\tconst selectedShard = this.selectShard(primaryKey, state, effectiveStrategy, eligibleShards);\n\n\t\tif (effectiveStrategy === 'round-robin') {\n\t\t\tstate.roundRobinIndex = (state.roundRobinIndex + 1) % eligibleShards.length;\n\t\t\tawait this.saveState(state);\n\t\t}\n\n\t\treturn new Response(JSON.stringify({ shard: selectedShard }), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t});\n\t}\n\n\t/**\n\t * Completely clears all coordinator state from Durable Object storage.\n\t * This removes all shard registrations, statistics, and configuration.\n\t *\n\t * **WARNING**: This operation is destructive and should only be used\n\t * in development environments or during testing.\n\t *\n\t * @private\n\t * @returns Promise resolving to HTTP response indicating success\n\t * @example Response body: `{\"success\": true}`\n\t */\n\tprivate async handleFlush(): Promise<Response> {\n\t\tawait this.state.storage.deleteAll();\n\t\treturn new Response(JSON.stringify({ success: true }), {\n\t\t\theaders: { 'Content-Type': 'application/json' }\n\t\t});\n\t}\n\n\t/**\n\t * Resolves the effective sharding strategy for a given operation type\n\t *\n\t * @private\n\t * @param configStrategy - The strategy from state configuration\n\t * @param requestStrategy - Optional strategy override from request\n\t * @param operationType - The type of operation (read/write)\n\t * @returns The effective sharding strategy to use\n\t */\n\tprivate resolveStrategy(\n\t\tconfigStrategy: ShardingStrategy | MixedShardingStrategy,\n\t\trequestStrategy?: ShardingStrategy,\n\t\toperationType: OperationType = 'write'\n\t): ShardingStrategy {\n\t\t// Request strategy overrides everything\n\t\tif (requestStrategy) {\n\t\t\treturn requestStrategy;\n\t\t}\n\n\t\t// If config strategy is a string, use it for all operations\n\t\tif (typeof configStrategy === 'string') {\n\t\t\treturn configStrategy;\n\t\t}\n\n\t\t// If config strategy is a mixed strategy object, use the appropriate strategy for the operation type\n\t\treturn configStrategy[operationType];\n\t}\n\n\t/**\n\t * Implements the core shard selection logic for different allocation strategies.\n\t * Uses consistent algorithms to ensure predictable shard assignment.\n\t *\n\t * Strategy details:\n\t * - round-robin: Uses roundRobinIndex to cycle through shards\n\t * - random: Uses Math.random() for uniform distribution\n\t * - hash: Uses string hash function for consistent assignment\n\t *\n\t * @private\n\t * @param primaryKey - The primary key to allocate a shard for\n\t * @param state - Current coordinator state containing available shards\n\t * @param strategy - The allocation strategy to use\n\t * @param eligibleShards - Optional filtered list of shards to choose from\n\t * @returns The selected shard binding name\n\t * @throws {CollegeDBError} If no shards are available\n\t * @example\n\t * ```typescript\n\t * const shard = this.selectShard('user-123', state, 'hash');\n\t * // Returns: \"db-west\" (consistent for this key)\n\t * ```\n\t */\n\tprivate selectShard(primaryKey: string, state: ShardCoordinatorState, strategy: ShardingStrategy, eligibleShards?: string[]): string {\n\t\tconst shards = eligibleShards || state.knownShards;\n\n\t\tif (shards.length === 0) {\n\t\t\tthrow new CollegeDBError('No shards available', 'NO_SHARDS');\n\t\t}\n\n\t\tswitch (strategy) {\n\t\t\tcase 'round-robin':\n\t\t\t\treturn shards[state.roundRobinIndex] ?? shards[0]!;\n\t\t\tcase 'random':\n\t\t\t\treturn shards[Math.floor(Math.random() * shards.length)]!;\n\t\t\tcase 'hash': {\n\t\t\t\tlet hash = 0;\n\t\t\t\tfor (let i = 0; i < primaryKey.length; i++) {\n\t\t\t\t\tconst char = primaryKey.charCodeAt(i);\n\t\t\t\t\thash = (hash << 5) - hash + char;\n\t\t\t\t\thash = hash & hash; // Convert to 32-bit integer\n\t\t\t\t}\n\t\t\t\tconst index = Math.abs(hash) % shards.length;\n\t\t\t\treturn shards[index]!;\n\t\t\t}\n\t\t\tcase 'location': {\n\t\t\t\t// If location config missing, fallback to hash\n\t\t\t\tconst region = state.targetRegion;\n\t\t\t\tconst locations = state.shardLocations || {};\n\t\t\t\tconst located = shards.filter((s) => locations[s]);\n\t\t\t\tif (!region || located.length === 0) {\n\t\t\t\t\tlet h = 0;\n\t\t\t\t\tfor (let i = 0; i < primaryKey.length; i++) {\n\t\t\t\t\t\tconst c = primaryKey.charCodeAt(i);\n\t\t\t\t\t\th = (h << 5) - h + c;\n\t\t\t\t\t\th = h & h;\n\t\t\t\t\t}\n\t\t\t\t\tconst idx = Math.abs(h) % shards.length;\n\t\t\t\t\treturn shards[idx]!;\n\t\t\t\t}\n\n\t\t\t\t// Simple location scoring similar to router.ts\n\t\t\t\tconst coords: Record<D1Region, { lat: number; lon: number }> = {\n\t\t\t\t\t// Western North America - San Francisco, CA\n\t\t\t\t\twnam: { lat: 37.7749, lon: -122.4194 },\n\t\t\t\t\t// Eastern North America - Newark, NJ\n\t\t\t\t\tenam: { lat: 40.7357, lon: -74.1724 },\n\t\t\t\t\t// Western Europe - London, UK\n\t\t\t\t\tweur: { lat: 51.5074, lon: -0.1278 },\n\t\t\t\t\t// Eastern Europe - Warsaw, Poland\n\t\t\t\t\teeur: { lat: 52.2297, lon: 21.0122 },\n\t\t\t\t\t// Asia Pacific - Tokyo, Japan\n\t\t\t\t\tapac: { lat: 35.6762, lon: 139.6503 },\n\t\t\t\t\t// Oceania - Sydney, Australia\n\t\t\t\t\toc: { lat: -33.8688, lon: 151.2093 },\n\t\t\t\t\t// Middle East - Dubai, UAE\n\t\t\t\t\tme: { lat: 25.2048, lon: 55.2708 },\n\t\t\t\t\t// Africa - Johannesburg, South Africa\n\t\t\t\t\taf: { lat: -26.2041, lon: 28.0473 }\n\t\t\t\t};\n\n\t\t\t\tconst hasCoordKey = (obj: typeof coords, key: D1Region) => key in obj;\n\t\t\t\tconst getKey = (k: D1Region): keyof typeof coords => (hasCoordKey(coords, k) ? (k as keyof typeof coords) : 'wnam');\n\t\t\t\tconst dist = (from: D1Region, to: D1Region) => {\n\t\t\t\t\tconst a = coords[getKey(from)];\n\t\t\t\t\tconst b = coords[getKey(to)];\n\t\t\t\t\tconst lat = a.lat - b.lat;\n\t\t\t\t\tconst lon = a.lon - b.lon;\n\t\t\t\t\treturn Math.sqrt(lat * lat + lon * lon);\n\t\t\t\t};\n\n\t\t\t\tconst scores = located.map((shard) => {\n\t\t\t\t\tconst meta = locations[shard]!;\n\t\t\t\t\tconst distance = dist(region, meta.region);\n\t\t\t\t\tconst priority = meta.priority || 1;\n\t\t\t\t\treturn { shard, score: distance - priority * 0.1 };\n\t\t\t\t});\n\n\t\t\t\tscores.sort((a, b) => a.score - b.score);\n\t\t\t\tconst bestScore = scores[0]!.score;\n\t\t\t\tconst best = scores.filter((s) => Math.abs(s.score - bestScore) < 0.01);\n\t\t\t\tif (best.length === 1) return best[0]!.shard;\n\n\t\t\t\t// Tie-breaker by consistent hash\n\t\t\t\tlet h2 = 0;\n\t\t\t\tfor (let i = 0; i < primaryKey.length; i++) {\n\t\t\t\t\tconst c = primaryKey.charCodeAt(i);\n\t\t\t\t\th2 = (h2 << 5) - h2 + c;\n\t\t\t\t\th2 = h2 & h2;\n\t\t\t\t}\n\t\t\t\tconst idx2 = Math.abs(h2) % best.length;\n\t\t\t\treturn best[idx2]!.shard;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\treturn shards[0]!;\n\t\t}\n\t}\n\n\t/**\n\t * Atomically increments the key count for a specific shard and updates\n\t * the last modified timestamp. Used when new primary keys are assigned\n\t * to a shard.\n\t * @param shard - The shard binding name to increment\n\t * @returns Promise that resolves when the count is updated\n\t * @throws {Error} If the shard is not known to the coordinator\n\t * @example\n\t * ```typescript\n\t * await coordinator.incrementShardCount('db-east');\n\t * ```\n\t */\n\tasync incrementShardCount(shard: string): Promise<void> {\n\t\tconst state = await this.getState();\n\t\tif (state.shardStats[shard]) {\n\t\t\tstate.shardStats[shard].count++;\n\t\t\tstate.shardStats[shard].lastUpdated = Date.now();\n\t\t\tawait this.saveState(state);\n\t\t}\n\t}\n\n\t/**\n\t * Atomically decrements the key count for a specific shard and updates\n\t * the last modified timestamp. Used when primary keys are removed or\n\t * moved from a shard. Prevents negative counts.\n\t * @param shard - The shard binding name to decrement\n\t * @returns Promise that resolves when the count is updated\n\t * @throws {CollegeDBError} If the shard is not known to the coordinator\n\t * @example\n\t * ```typescript\n\t * await coordinator.decrementShardCount('db-west');\n\t * ```\n\t */\n\tasync decrementShardCount(shard: string): Promise<void> {\n\t\tconst state = await this.getState();\n\t\tif (state.shardStats[shard] && state.shardStats[shard].count > 0) {\n\t\t\tstate.shardStats[shard].count--;\n\t\t\tstate.shardStats[shard].lastUpdated = Date.now();\n\t\t\tawait this.saveState(state);\n\t\t}\n\t}\n}\n",
10
+ "/**\n * CollegeDB - Cloudflare D1 Sharding Router\n *\n * A TypeScript library for horizontal scaling of SQLite-style databases on Cloudflare\n * using D1 and KV. Routes queries to the correct D1 database instance using primary\n * key mappings stored in Cloudflare KV.\n *\n * @author Gregory Mitchell\n * @license MIT\n */\n\n// Export main API functions\nexport {\n\tall,\n\tallAllShards,\n\tallAllShardsGlobal,\n\tallByLookupKey,\n\tallShard,\n\tcollegedb,\n\tcount,\n\tcountAllShards,\n\tcountShard,\n\tcreateSchema,\n\texplain,\n\texplainAllShards,\n\texplainShard,\n\tfirst,\n\tfirstAllShards,\n\tfirstAllShardsGlobal,\n\tfirstByLookupKey,\n\tfirstShard,\n\tflush,\n\tgetClosestRegionFromIP,\n\tgetDatabaseSizeForKey,\n\tgetDatabaseSizeForShard,\n\tgetDatabaseSizesAllShards,\n\tgetShardStats,\n\tgetTotalDatabaseSize,\n\tindex,\n\tindexAllShards,\n\tindexShard,\n\tinitialize,\n\tinitializeAsync,\n\tinsert,\n\tinsertShard,\n\tlistKnownShards,\n\tprepare,\n\treassignShard,\n\tresetConfig,\n\trun,\n\trunAllShards,\n\trunShard\n} from './router';\n\nexport type {\n\tCreateIndexOptions,\n\tExplainOptions,\n\tGlobalAllShardsOptions,\n\tIndexColumnDefinition,\n\tInsertResult,\n\tShardSizeResult,\n\tShardTableCount\n} from './router';\n\n// Export utility classes\nexport { ShardCoordinator } from './durable';\nexport { CollegeDBError } from './errors';\nexport { KVShardMapper } from './kvmap';\n\n// Export provider adapters\nexport {\n\tcreateDrizzleSQLProvider,\n\tcreateHyperdriveMySQLProvider,\n\tcreateHyperdrivePostgresProvider,\n\tcreateMySQLProvider,\n\tcreateNuxtHubKVProvider,\n\tcreatePostgreSQLProvider,\n\tcreateRedisKVProvider,\n\tcreateSQLiteProvider,\n\tcreateValkeyKVProvider,\n\tisKVStorage,\n\tisSQLDatabase,\n\ttype DrizzleClientLike,\n\ttype DrizzleSqlChunkLike,\n\ttype DrizzleSqlTagLike,\n\ttype HyperdriveBindingLike,\n\ttype HyperdriveMySQLClientFactory,\n\ttype HyperdrivePostgresClientFactory,\n\ttype MySQLClientLike,\n\ttype NuxtHubKVLike,\n\ttype PostgresClientLike,\n\ttype RedisLikeClient,\n\ttype SQLiteClientLike\n} from './providers';\n\n// Export migration functions\nexport {\n\tautoDetectAndMigrate,\n\tcheckMigrationNeeded,\n\tclearMigrationCache,\n\tclearShardMigrationCache,\n\tcreateMappingsForExistingKeys,\n\tcreateSchemaAcrossShards,\n\tdiscoverExistingPrimaryKeys,\n\tdiscoverExistingRecordsWithColumns,\n\tdropSchema,\n\tintegrateExistingDatabase,\n\tlistTables,\n\tmigrateRecord,\n\tschemaExists,\n\tvalidateTableForSharding,\n\ttype IntegrationOptions,\n\ttype IntegrationResult,\n\ttype ValidationResult\n} from './migrations';\n\n// Export types\nexport type {\n\tCollegeDBConfig,\n\tD1Region,\n\tEnv,\n\tKVListResult,\n\tKVStorage,\n\tMixedShardingStrategy,\n\tOperationType,\n\tPreparedStatement,\n\tQueryResult,\n\tQueryResultMeta,\n\tSQLDatabase,\n\tShardCoordinatorState,\n\tShardLocation,\n\tShardMapping,\n\tShardStats,\n\tShardingStrategy\n} from './types';\n",
11
+ "/**\n * @fileoverview Provider adapters for non-Cloudflare backends.\n *\n * This module defines maintainable adapter factories that allow CollegeDB to run\n * on multiple storage backends while preserving Cloudflare compatibility.\n *\n * Supported KV backends:\n * - Cloudflare KV (native shape)\n * - Redis\n * - Valkey\n * - NuxtHub KV / Unstorage-compatible clients\n *\n * Supported SQL backends:\n * - Cloudflare D1 (native shape)\n * - PostgreSQL compatible clients\n * - MySQL / MariaDB compatible clients\n * - SQLite clients\n * - Drizzle ORM database instances\n * - Hyperdrive-backed PostgreSQL / MySQL clients\n *\n * @author CollegeDB Team\n * @since 1.1.0\n */\n\nimport { CollegeDBError } from './errors';\nimport type { KVListResult, KVStorage, PreparedStatement, QueryResult, QueryResultMeta, SQLDatabase } from './types';\n\nconst DEFAULT_REDIS_SCAN_COUNT = 500;\n\n/**\n * Minimal Redis/Valkey client contract used by the KV adapter.\n */\nexport interface RedisLikeClient {\n\tget(key: string): Promise<string | null>;\n\tset(key: string, value: string): unknown | Promise<unknown>;\n\tdel(key: string): unknown | Promise<unknown>;\n\tscan(cursor: string, ...args: any[]): RedisScanResult | Promise<RedisScanResult>;\n}\n\n/**\n * Redis/Valkey SCAN response in ioredis tuple form.\n */\nexport type RedisScanTupleResult = [string, string[]];\n\n/**\n * Redis/Valkey SCAN response in node-redis object form.\n */\nexport interface RedisScanObjectResult {\n\tcursor: string | number;\n\tkeys: string[];\n}\n\n/**\n * Accepted SCAN response formats.\n */\nexport type RedisScanResult = RedisScanTupleResult | RedisScanObjectResult;\n\n/**\n * PostgreSQL result shape used by adapters.\n */\nexport interface PostgresQueryResult<T = Record<string, unknown>> {\n\trows: T[];\n\trowCount?: number | null;\n\tcommand?: string;\n\t[key: string]: unknown;\n}\n\n/**\n * Minimal PostgreSQL client contract used by the SQL adapter.\n */\nexport interface PostgresClientLike {\n\tquery<T = Record<string, unknown>>(sql: string, bindings?: any[]): Promise<PostgresQueryResult<T>>;\n}\n\n/**\n * Optional lifecycle methods used by Hyperdrive helpers.\n */\nexport interface PostgresLifecycleClientLike extends PostgresClientLike {\n\tconnect?: () => void | Promise<void>;\n\tend?: () => void | Promise<void>;\n\trelease?: () => void;\n}\n\n/**\n * MySQL/MariaDB OK packet shape.\n */\nexport interface MySQLOkPacket {\n\taffectedRows?: number;\n\tinsertId?: number;\n\twarningStatus?: number;\n\t[key: string]: unknown;\n}\n\n/**\n * Minimal MySQL/MariaDB client contract used by adapters.\n */\nexport interface MySQLClientLike {\n\texecute?: (sql: string, bindings?: any[]) => any | Promise<any>;\n\tquery?: (sql: string, bindings?: any[]) => any | Promise<any>;\n}\n\n/**\n * Optional lifecycle methods used by Hyperdrive helpers.\n */\nexport interface MySQLLifecycleClientLike extends MySQLClientLike {\n\tend?: () => void | Promise<void>;\n\tclose?: () => void | Promise<void>;\n\tdestroy?: () => void;\n}\n\n/**\n * Statement contract for SQLite adapters.\n */\nexport interface SQLiteStatementLike {\n\trun?: (...bindings: any[]) => unknown | Promise<unknown>;\n\tall?: (...bindings: any[]) => unknown[] | Promise<unknown[]>;\n\tget?: (...bindings: any[]) => unknown | Promise<unknown>;\n}\n\n/**\n * Minimal SQLite client contract used by adapters.\n */\nexport interface SQLiteClientLike {\n\tprepare?: (sql: string) => SQLiteStatementLike;\n\texecute?: (sql: string, bindings?: any[]) => any | Promise<any>;\n}\n\n/**\n * Hyperdrive binding shape used by helper factories.\n */\nexport interface HyperdriveBindingLike {\n\tconnectionString: string;\n\tlocalConnectionString?: string;\n}\n\n/**\n * Factory for creating PostgreSQL clients from a Hyperdrive connection string.\n */\nexport type HyperdrivePostgresClientFactory = (connectionString: string) => PostgresLifecycleClientLike;\n\n/**\n * Factory for creating MySQL clients from a Hyperdrive connection string.\n */\nexport type HyperdriveMySQLClientFactory = (connectionString: string) => MySQLLifecycleClientLike;\n\n/**\n * Minimal SQL chunk contract produced by Drizzle's `sql` helper.\n */\nexport interface DrizzleSqlChunkLike {\n\tappend(chunk: DrizzleSqlChunkLike): void;\n}\n\n/**\n * Minimal Drizzle `sql` tag contract used to build parameterized raw statements.\n */\nexport interface DrizzleSqlTagLike {\n\t(strings: TemplateStringsArray, ...params: any[]): DrizzleSqlChunkLike;\n\traw(sql: string): DrizzleSqlChunkLike;\n\tempty?: () => DrizzleSqlChunkLike;\n}\n\n/**\n * Minimal Drizzle database contract used by the SQL adapter.\n */\nexport interface DrizzleClientLike {\n\texecute?: (query: any) => any | Promise<any>;\n\trun?: (query: any) => any | Promise<any>;\n\tall?: (query: any) => any | Promise<any>;\n\tget?: (query: any) => any | Promise<any>;\n}\n\n/**\n * NuxtHub/Unstorage-like KV contract used by the adapter.\n */\nexport interface NuxtHubKVLike {\n\tget?<T = any>(key: string): T | null | undefined | Promise<T | null | undefined>;\n\tset?(key: string, value: any, options?: { ttl?: number }): any | Promise<any>;\n\tdel?(key: string): any | Promise<any>;\n\tkeys?(prefix?: string): string[] | readonly string[] | Promise<string[] | readonly string[]>;\n\tgetItem?<T = any>(key: string): T | null | undefined | Promise<T | null | undefined>;\n\tsetItem?(key: string, value: any): any | Promise<any>;\n\tremoveItem?(key: string): any | Promise<any>;\n\tgetKeys?(prefix?: string): string[] | readonly string[] | Promise<string[] | readonly string[]>;\n}\n\n/**\n * Creates a Redis-backed KV provider adapter.\n *\n * The adapter supports both node-redis and ioredis scan formats.\n *\n * @param client - Redis/Valkey client\n * @param options - Adapter tuning options\n * @returns KVStorage-compatible adapter\n */\nexport function createRedisKVProvider(client: RedisLikeClient, options: { scanCount?: number } = {}): KVStorage {\n\tconst scanCount = options.scanCount ?? DEFAULT_REDIS_SCAN_COUNT;\n\n\treturn {\n\t\tasync get<T = unknown>(key: string, type: 'text' | 'json' = 'text'): Promise<T | string | null> {\n\t\t\tconst raw = await client.get(key);\n\t\t\tif (raw === null) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif (type !== 'json') {\n\t\t\t\treturn raw;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(raw) as T;\n\t\t\t} catch (error) {\n\t\t\t\tthrow new CollegeDBError(\n\t\t\t\t\t`Failed to parse JSON from Redis for key ${key}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t'KV_JSON_PARSE_FAILED'\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\n\t\tasync put(key: string, value: string): Promise<void> {\n\t\t\tawait client.set(key, value);\n\t\t},\n\n\t\tasync delete(key: string): Promise<void> {\n\t\t\tawait client.del(key);\n\t\t},\n\n\t\tasync list(options?: { prefix?: string; cursor?: string; limit?: number }): Promise<KVListResult> {\n\t\t\tconst prefix = options?.prefix ?? '';\n\t\t\tconst pattern = `${prefix}*`;\n\t\t\tlet cursor = options?.cursor ?? '0';\n\t\t\tconst limit = options?.limit;\n\t\t\tconst keys: string[] = [];\n\n\t\t\tdo {\n\t\t\t\tconst scanResult = await executeRedisScan(client, cursor, pattern, scanCount);\n\t\t\t\tcursor = scanResult.cursor;\n\n\t\t\t\tfor (const key of scanResult.keys) {\n\t\t\t\t\tif (!prefix || key.startsWith(prefix)) {\n\t\t\t\t\t\tkeys.push(key);\n\t\t\t\t\t}\n\t\t\t\t\tif (limit && keys.length >= limit) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (limit && keys.length >= limit) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} while (cursor !== '0');\n\n\t\t\treturn {\n\t\t\t\tkeys: keys.map((name) => ({ name })),\n\t\t\t\tcursor,\n\t\t\t\tlist_complete: cursor === '0'\n\t\t\t};\n\t\t}\n\t};\n}\n\n/**\n * Creates a Valkey-backed KV provider adapter.\n *\n * Valkey and Redis have compatible command surfaces for this adapter.\n *\n * @param client - Valkey client\n * @param options - Adapter tuning options\n * @returns KVStorage-compatible adapter\n */\nexport function createValkeyKVProvider(client: RedisLikeClient, options: { scanCount?: number } = {}): KVStorage {\n\treturn createRedisKVProvider(client, options);\n}\n\n/**\n * Creates a PostgreSQL adapter implementing CollegeDB's SQL contract.\n *\n * Supports `pg` Client, Pool, and compatible implementations.\n * SQL using `?` placeholders is automatically rewritten to `$1..$n`.\n *\n * For Drizzle-backed PostgreSQL clients, pass the Drizzle DB instance as\n * `client` and the Drizzle `sql` helper as the second argument.\n *\n * @param client - PostgreSQL client/pool\n * @param sqlTag - Optional Drizzle `sql` helper for Drizzle interop\n * @returns SQLDatabase-compatible adapter\n */\nexport function createPostgreSQLProvider(client: PostgresClientLike): SQLDatabase;\nexport function createPostgreSQLProvider(client: DrizzleClientLike, sqlTag: DrizzleSqlTagLike): SQLDatabase;\nexport function createPostgreSQLProvider(client: PostgresClientLike | DrizzleClientLike, sqlTag?: DrizzleSqlTagLike): SQLDatabase {\n\tif (sqlTag) {\n\t\treturn createDrizzleSQLProvider(client as DrizzleClientLike, sqlTag);\n\t}\n\n\treturn {\n\t\tprepare(sql: string): PreparedStatement {\n\t\t\treturn new PostgresPreparedStatement(client as PostgresClientLike, sql);\n\t\t}\n\t};\n}\n\n/**\n * Creates a MySQL/MariaDB adapter implementing CollegeDB's SQL contract.\n *\n * Supports mysql2/promise clients, pools, and compatible wrappers.\n *\n * For Drizzle-backed MySQL/MariaDB clients, pass the Drizzle DB instance as\n * `client` and the Drizzle `sql` helper as the second argument.\n *\n * @param client - MySQL/MariaDB client or pool\n * @param sqlTag - Optional Drizzle `sql` helper for Drizzle interop\n * @returns SQLDatabase-compatible adapter\n */\nexport function createMySQLProvider(client: MySQLClientLike): SQLDatabase;\nexport function createMySQLProvider(client: DrizzleClientLike, sqlTag: DrizzleSqlTagLike): SQLDatabase;\nexport function createMySQLProvider(client: MySQLClientLike | DrizzleClientLike, sqlTag?: DrizzleSqlTagLike): SQLDatabase {\n\tif (sqlTag) {\n\t\treturn createDrizzleSQLProvider(client as DrizzleClientLike, sqlTag);\n\t}\n\n\treturn {\n\t\tprepare(sql: string): PreparedStatement {\n\t\t\treturn new MySQLPreparedStatement(client as MySQLClientLike, sql);\n\t\t}\n\t};\n}\n\n/**\n * Creates a SQLite adapter implementing CollegeDB's SQL contract.\n *\n * Supports both execute-style clients and prepare/run/get/all statement clients.\n *\n * For Drizzle-backed SQLite/D1 clients, pass the Drizzle DB instance as\n * `client` and the Drizzle `sql` helper as the second argument.\n *\n * @param client - SQLite client\n * @param sqlTag - Optional Drizzle `sql` helper for Drizzle interop\n * @returns SQLDatabase-compatible adapter\n */\nexport function createSQLiteProvider(client: SQLiteClientLike): SQLDatabase;\nexport function createSQLiteProvider(client: DrizzleClientLike, sqlTag: DrizzleSqlTagLike): SQLDatabase;\nexport function createSQLiteProvider(client: SQLiteClientLike | DrizzleClientLike, sqlTag?: DrizzleSqlTagLike): SQLDatabase {\n\tif (sqlTag) {\n\t\treturn createDrizzleSQLProvider(client as DrizzleClientLike, sqlTag);\n\t}\n\n\treturn {\n\t\tprepare(sql: string): PreparedStatement {\n\t\t\treturn new SQLitePreparedStatement(client as SQLiteClientLike, sql);\n\t\t}\n\t};\n}\n\n/**\n * Creates a Drizzle-backed SQL adapter implementing CollegeDB's SQL contract.\n *\n * This adapter enables using Drizzle database instances (including NuxtHub's\n * `db` from `@nuxthub/db` or `hub:db`) as shard providers while CollegeDB keeps\n * query routing and key->shard mapping responsibilities.\n *\n * @param client - Drizzle database instance\n * @param sqlTag - Drizzle `sql` helper from `drizzle-orm`\n * @returns SQLDatabase-compatible adapter\n */\nexport function createDrizzleSQLProvider(client: DrizzleClientLike, sqlTag: DrizzleSqlTagLike): SQLDatabase {\n\treturn {\n\t\tprepare(sql: string): PreparedStatement {\n\t\t\treturn new DrizzlePreparedStatement(client, sqlTag, sql);\n\t\t}\n\t};\n}\n\n/**\n * Creates a NuxtHub KV adapter implementing CollegeDB's KV contract.\n *\n * Supports both `@nuxthub/kv` (`get/set/del/keys`) and unstorage-like\n * implementations (`getItem/setItem/removeItem/getKeys`).\n *\n * @param client - NuxtHub KV/Unstorage-like client\n * @returns KVStorage-compatible adapter\n */\nexport function createNuxtHubKVProvider(client: NuxtHubKVLike): KVStorage {\n\treturn {\n\t\tasync get<T = unknown>(key: string, type: 'text' | 'json' = 'text'): Promise<T | string | null> {\n\t\t\tconst raw = await getNuxtHubKVValue(client, key);\n\t\t\tif (raw === null || raw === undefined) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif (type === 'json') {\n\t\t\t\tif (typeof raw === 'string') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn JSON.parse(raw) as T;\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthrow new CollegeDBError(\n\t\t\t\t\t\t\t`Failed to parse JSON from NuxtHub KV for key ${key}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t\t\t'KV_JSON_PARSE_FAILED'\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn raw as T;\n\t\t\t}\n\n\t\t\treturn typeof raw === 'string' ? raw : JSON.stringify(raw);\n\t\t},\n\n\t\tasync put(key: string, value: string): Promise<void> {\n\t\t\tawait setNuxtHubKVValue(client, key, value);\n\t\t},\n\n\t\tasync delete(key: string): Promise<void> {\n\t\t\tawait deleteNuxtHubKVValue(client, key);\n\t\t},\n\n\t\tasync list(options?: { prefix?: string; cursor?: string; limit?: number }): Promise<KVListResult> {\n\t\t\tconst prefix = options?.prefix ?? '';\n\t\t\tconst allKeys = await listNuxtHubKVKeys(client, prefix);\n\t\t\tconst limitedKeys = typeof options?.limit === 'number' ? allKeys.slice(0, options.limit) : allKeys;\n\n\t\t\treturn {\n\t\t\t\tkeys: limitedKeys.map((name) => ({ name })),\n\t\t\t\tlist_complete: true\n\t\t\t};\n\t\t}\n\t};\n}\n\n/**\n * Creates a PostgreSQL adapter wired to a Hyperdrive binding.\n *\n * The returned provider creates a transient client for each statement execution.\n * Hyperdrive handles connection pooling at the edge, so this pattern remains fast\n * and scalable in Workers.\n *\n * @param hyperdrive - Hyperdrive binding\n * @param clientFactory - Client factory (e.g. `connectionString => new Client({ connectionString })`)\n * @returns SQLDatabase-compatible adapter\n */\nexport function createHyperdrivePostgresProvider(\n\thyperdrive: HyperdriveBindingLike,\n\tclientFactory: HyperdrivePostgresClientFactory\n): SQLDatabase {\n\tconst delegatedClient: PostgresClientLike = {\n\t\tquery: async <T = Record<string, unknown>>(sql: string, bindings: any[] = []) => {\n\t\t\tconst client = clientFactory(hyperdrive.connectionString);\n\t\t\tif (typeof client.connect === 'function') {\n\t\t\t\tawait client.connect();\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\treturn await client.query<T>(sql, bindings);\n\t\t\t} finally {\n\t\t\t\tif (typeof client.release === 'function') {\n\t\t\t\t\tclient.release();\n\t\t\t\t} else if (typeof client.end === 'function') {\n\t\t\t\t\tawait client.end();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\treturn createPostgreSQLProvider(delegatedClient);\n}\n\n/**\n * Creates a MySQL/MariaDB adapter wired to a Hyperdrive binding.\n *\n * The returned provider creates a transient client for each statement execution.\n * Hyperdrive handles connection pooling under the hood.\n *\n * @param hyperdrive - Hyperdrive binding\n * @param clientFactory - Client factory (e.g. `connectionString => mysql.createConnection(connectionString)`)\n * @returns SQLDatabase-compatible adapter\n */\nexport function createHyperdriveMySQLProvider(hyperdrive: HyperdriveBindingLike, clientFactory: HyperdriveMySQLClientFactory): SQLDatabase {\n\tconst delegatedClient: MySQLClientLike = {\n\t\texecute: async (sql: string, bindings: any[] = []) => {\n\t\t\tconst client = clientFactory(hyperdrive.connectionString);\n\t\t\ttry {\n\t\t\t\tif (typeof client.execute === 'function') {\n\t\t\t\t\treturn await client.execute(sql, bindings);\n\t\t\t\t}\n\t\t\t\tif (typeof client.query === 'function') {\n\t\t\t\t\treturn await client.query(sql, bindings);\n\t\t\t\t}\n\n\t\t\t\tthrow new CollegeDBError('Hyperdrive MySQL client is missing execute/query methods', 'MYSQL_CLIENT_INVALID');\n\t\t\t} finally {\n\t\t\t\tif (typeof client.end === 'function') {\n\t\t\t\t\tawait client.end();\n\t\t\t\t} else if (typeof client.close === 'function') {\n\t\t\t\t\tawait client.close();\n\t\t\t\t} else if (typeof client.destroy === 'function') {\n\t\t\t\t\tclient.destroy();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\treturn createMySQLProvider(delegatedClient);\n}\n\n/**\n * Returns `true` when a value looks like an SQL database provider.\n */\nexport function isSQLDatabase(value: unknown): value is SQLDatabase {\n\tif (!value || typeof value !== 'object') {\n\t\treturn false;\n\t}\n\n\treturn typeof (value as SQLDatabase).prepare === 'function';\n}\n\n/**\n * Returns `true` when a value looks like a KV storage provider.\n */\nexport function isKVStorage(value: unknown): value is KVStorage {\n\tif (!value || typeof value !== 'object') {\n\t\treturn false;\n\t}\n\n\tconst kv = value as KVStorage;\n\treturn typeof kv.get === 'function' && typeof kv.put === 'function' && typeof kv.delete === 'function' && typeof kv.list === 'function';\n}\n\nclass PostgresPreparedStatement implements PreparedStatement {\n\tprivate readonly client: PostgresClientLike;\n\tprivate readonly sql: string;\n\tprivate readonly bindings: any[];\n\n\tconstructor(client: PostgresClientLike, sql: string, bindings: any[] = []) {\n\t\tthis.client = client;\n\t\tthis.sql = sql;\n\t\tthis.bindings = bindings;\n\t}\n\n\tbind(...bindings: any[]): PreparedStatement {\n\t\treturn new PostgresPreparedStatement(this.client, this.sql, bindings);\n\t}\n\n\tasync run<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\t\tconst sql = rewriteQuestionPlaceholders(this.sql);\n\t\tconst result = await this.client.query<T>(sql, this.bindings);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: result.rows ?? [],\n\t\t\tmeta: createMeta(startedAt, {\n\t\t\t\tchanges: typeof result.rowCount === 'number' ? result.rowCount : undefined,\n\t\t\t\tcommand: result.command\n\t\t\t})\n\t\t};\n\t}\n\n\tasync all<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\t\tconst sql = rewriteQuestionPlaceholders(this.sql);\n\t\tconst result = await this.client.query<T>(sql, this.bindings);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: result.rows ?? [],\n\t\t\tmeta: createMeta(startedAt, {\n\t\t\t\tchanges: typeof result.rowCount === 'number' ? result.rowCount : undefined,\n\t\t\t\tcommand: result.command\n\t\t\t})\n\t\t};\n\t}\n\n\tasync first<T = Record<string, unknown>>(): Promise<T | null> {\n\t\tconst sql = rewriteQuestionPlaceholders(this.sql);\n\t\tconst result = await this.client.query<T>(sql, this.bindings);\n\t\treturn result.rows?.[0] ?? null;\n\t}\n}\n\nclass MySQLPreparedStatement implements PreparedStatement {\n\tprivate readonly client: MySQLClientLike;\n\tprivate readonly sql: string;\n\tprivate readonly bindings: any[];\n\n\tconstructor(client: MySQLClientLike, sql: string, bindings: any[] = []) {\n\t\tthis.client = client;\n\t\tthis.sql = sql;\n\t\tthis.bindings = bindings;\n\t}\n\n\tbind(...bindings: any[]): PreparedStatement {\n\t\treturn new MySQLPreparedStatement(this.client, this.sql, bindings);\n\t}\n\n\tasync run<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\t\tconst rows = await executeMySQL(this.client, this.sql, this.bindings);\n\n\t\tif (Array.isArray(rows)) {\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tresults: rows as T[],\n\t\t\t\tmeta: createMeta(startedAt)\n\t\t\t};\n\t\t}\n\n\t\tconst packet = rows as MySQLOkPacket;\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: [],\n\t\t\tmeta: createMeta(startedAt, {\n\t\t\t\tchanges: packet.affectedRows,\n\t\t\t\tlast_row_id: packet.insertId,\n\t\t\t\twarningStatus: packet.warningStatus\n\t\t\t})\n\t\t};\n\t}\n\n\tasync all<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\t\tconst rows = await executeMySQL(this.client, this.sql, this.bindings);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: Array.isArray(rows) ? (rows as T[]) : [],\n\t\t\tmeta: createMeta(startedAt, {\n\t\t\t\tchanges: !Array.isArray(rows) ? (rows as MySQLOkPacket).affectedRows : undefined\n\t\t\t})\n\t\t};\n\t}\n\n\tasync first<T = Record<string, unknown>>(): Promise<T | null> {\n\t\tconst rows = await executeMySQL(this.client, this.sql, this.bindings);\n\t\tif (!Array.isArray(rows) || rows.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn rows[0] as T;\n\t}\n}\n\nclass SQLitePreparedStatement implements PreparedStatement {\n\tprivate readonly client: SQLiteClientLike;\n\tprivate readonly sql: string;\n\tprivate readonly bindings: any[];\n\n\tconstructor(client: SQLiteClientLike, sql: string, bindings: any[] = []) {\n\t\tthis.client = client;\n\t\tthis.sql = sql;\n\t\tthis.bindings = bindings;\n\t}\n\n\tbind(...bindings: any[]): PreparedStatement {\n\t\treturn new SQLitePreparedStatement(this.client, this.sql, bindings);\n\t}\n\n\tasync run<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\n\t\tif (typeof this.client.execute === 'function') {\n\t\t\tconst result = await this.client.execute(this.sql, this.bindings);\n\t\t\tconst rows = extractRowsFromSQLiteExecute<T>(result);\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tresults: rows,\n\t\t\t\tmeta: createMeta(startedAt)\n\t\t\t};\n\t\t}\n\n\t\tconst statement = this.client.prepare?.(this.sql);\n\t\tif (!statement || typeof statement.run !== 'function') {\n\t\t\tthrow new CollegeDBError('SQLite client must expose execute() or prepare().run()', 'SQLITE_CLIENT_INVALID');\n\t\t}\n\n\t\tconst runResult = await statement.run(...this.bindings);\n\t\tconst runMeta = (runResult ?? {}) as Record<string, unknown>;\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: [],\n\t\t\tmeta: createMeta(startedAt, {\n\t\t\t\tchanges: toMaybeNumber(runMeta.changes),\n\t\t\t\tlast_row_id: (runMeta.lastInsertRowid ?? runMeta.lastID) as number | string | undefined\n\t\t\t})\n\t\t};\n\t}\n\n\tasync all<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\n\t\tif (typeof this.client.execute === 'function') {\n\t\t\tconst result = await this.client.execute(this.sql, this.bindings);\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tresults: extractRowsFromSQLiteExecute<T>(result),\n\t\t\t\tmeta: createMeta(startedAt)\n\t\t\t};\n\t\t}\n\n\t\tconst statement = this.client.prepare?.(this.sql);\n\t\tif (!statement || typeof statement.all !== 'function') {\n\t\t\tthrow new CollegeDBError('SQLite client must expose execute() or prepare().all()', 'SQLITE_CLIENT_INVALID');\n\t\t}\n\n\t\tconst rows = await statement.all(...this.bindings);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: (Array.isArray(rows) ? rows : []) as T[],\n\t\t\tmeta: createMeta(startedAt)\n\t\t};\n\t}\n\n\tasync first<T = Record<string, unknown>>(): Promise<T | null> {\n\t\tif (typeof this.client.execute === 'function') {\n\t\t\tconst result = await this.client.execute(this.sql, this.bindings);\n\t\t\tconst rows = extractRowsFromSQLiteExecute<T>(result);\n\t\t\treturn rows[0] ?? null;\n\t\t}\n\n\t\tconst statement = this.client.prepare?.(this.sql);\n\t\tif (!statement) {\n\t\t\tthrow new CollegeDBError('SQLite client must expose execute() or prepare().get()', 'SQLITE_CLIENT_INVALID');\n\t\t}\n\n\t\tif (typeof statement.get === 'function') {\n\t\t\tconst row = await statement.get(...this.bindings);\n\t\t\treturn row === undefined || row === null ? null : (row as T);\n\t\t}\n\n\t\tif (typeof statement.all === 'function') {\n\t\t\tconst rows = await statement.all(...this.bindings);\n\t\t\tif (!Array.isArray(rows) || rows.length === 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst firstRow = rows[0];\n\t\t\treturn firstRow === undefined || firstRow === null ? null : (firstRow as T);\n\t\t}\n\n\t\tthrow new CollegeDBError('SQLite prepare() result must expose get() or all()', 'SQLITE_CLIENT_INVALID');\n\t}\n}\n\nclass DrizzlePreparedStatement implements PreparedStatement {\n\tprivate readonly client: DrizzleClientLike;\n\tprivate readonly sqlTag: DrizzleSqlTagLike;\n\tprivate readonly sqlText: string;\n\tprivate readonly bindings: any[];\n\n\tconstructor(client: DrizzleClientLike, sqlTag: DrizzleSqlTagLike, sqlText: string, bindings: any[] = []) {\n\t\tthis.client = client;\n\t\tthis.sqlTag = sqlTag;\n\t\tthis.sqlText = sqlText;\n\t\tthis.bindings = bindings;\n\t}\n\n\tbind(...bindings: any[]): PreparedStatement {\n\t\treturn new DrizzlePreparedStatement(this.client, this.sqlTag, this.sqlText, bindings);\n\t}\n\n\tasync run<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\t\tconst query = buildDrizzleQuery(this.sqlTag, this.sqlText, this.bindings);\n\t\tconst result = await executeDrizzleRun(this.client, query);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: extractRowsFromDrizzleExecute<T>(result),\n\t\t\tmeta: createMeta(startedAt, extractMetaFromDrizzleExecute(result))\n\t\t};\n\t}\n\n\tasync all<T = Record<string, unknown>>(): Promise<QueryResult<T>> {\n\t\tconst startedAt = Date.now();\n\t\tconst query = buildDrizzleQuery(this.sqlTag, this.sqlText, this.bindings);\n\t\tconst result = await executeDrizzleAll(this.client, query);\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tresults: extractRowsFromDrizzleExecute<T>(result),\n\t\t\tmeta: createMeta(startedAt, extractMetaFromDrizzleExecute(result))\n\t\t};\n\t}\n\n\tasync first<T = Record<string, unknown>>(): Promise<T | null> {\n\t\tconst query = buildDrizzleQuery(this.sqlTag, this.sqlText, this.bindings);\n\t\tconst result = await executeDrizzleFirst(this.client, query);\n\t\tconst rows = extractRowsFromDrizzleExecute<T>(result);\n\t\tif (rows.length > 0) {\n\t\t\treturn rows[0] ?? null;\n\t\t}\n\n\t\tif (result && typeof result === 'object' && 'row' in result) {\n\t\t\tconst row = (result as Record<string, unknown>).row;\n\t\t\treturn row === undefined || row === null ? null : (row as T);\n\t\t}\n\n\t\tif (\n\t\t\tresult &&\n\t\t\ttypeof result === 'object' &&\n\t\t\t!Array.isArray(result) &&\n\t\t\t!('rows' in result) &&\n\t\t\t!('results' in result) &&\n\t\t\t!('data' in result)\n\t\t) {\n\t\t\treturn result as T;\n\t\t}\n\n\t\treturn null;\n\t}\n}\n\nasync function executeRedisScan(\n\tclient: RedisLikeClient,\n\tcursor: string,\n\tpattern: string,\n\tscanCount: number\n): Promise<{ cursor: string; keys: string[] }> {\n\ttry {\n\t\tconst objectResult = await client.scan(cursor, { MATCH: pattern, COUNT: scanCount });\n\t\treturn normalizeRedisScanResult(objectResult);\n\t} catch {\n\t\tconst tupleResult = await client.scan(cursor, 'MATCH', pattern, 'COUNT', String(scanCount));\n\t\treturn normalizeRedisScanResult(tupleResult);\n\t}\n}\n\nfunction normalizeRedisScanResult(result: RedisScanResult): { cursor: string; keys: string[] } {\n\tif (Array.isArray(result)) {\n\t\treturn {\n\t\t\tcursor: String(result[0] ?? '0'),\n\t\t\tkeys: Array.isArray(result[1]) ? result[1] : []\n\t\t};\n\t}\n\n\treturn {\n\t\tcursor: String(result.cursor ?? '0'),\n\t\tkeys: Array.isArray(result.keys) ? result.keys : []\n\t};\n}\n\nasync function executeMySQL(client: MySQLClientLike, sql: string, bindings: any[]): Promise<unknown> {\n\tif (typeof client.execute === 'function') {\n\t\tconst result = await client.execute(sql, bindings);\n\t\tif (Array.isArray(result)) {\n\t\t\treturn result[0];\n\t\t}\n\t\treturn result;\n\t}\n\n\tif (typeof client.query === 'function') {\n\t\tconst result = await client.query(sql, bindings);\n\t\tif (Array.isArray(result)) {\n\t\t\treturn result[0];\n\t\t}\n\t\treturn result;\n\t}\n\n\tthrow new CollegeDBError('MySQL client must expose execute() or query()', 'MYSQL_CLIENT_INVALID');\n}\n\nasync function executeDrizzleRun(client: DrizzleClientLike, query: DrizzleSqlChunkLike): Promise<unknown> {\n\tif (typeof client.run === 'function') {\n\t\treturn await client.run(query);\n\t}\n\n\tif (typeof client.execute === 'function') {\n\t\treturn await client.execute(query);\n\t}\n\n\tif (typeof client.all === 'function') {\n\t\treturn await client.all(query);\n\t}\n\n\tthrow new CollegeDBError('Drizzle client must expose run(), execute(), or all()', 'DRIZZLE_CLIENT_INVALID');\n}\n\nasync function executeDrizzleAll(client: DrizzleClientLike, query: DrizzleSqlChunkLike): Promise<unknown> {\n\tif (typeof client.all === 'function') {\n\t\treturn await client.all(query);\n\t}\n\n\tif (typeof client.execute === 'function') {\n\t\treturn await client.execute(query);\n\t}\n\n\tif (typeof client.run === 'function') {\n\t\treturn await client.run(query);\n\t}\n\n\tthrow new CollegeDBError('Drizzle client must expose all(), execute(), or run()', 'DRIZZLE_CLIENT_INVALID');\n}\n\nasync function executeDrizzleFirst(client: DrizzleClientLike, query: DrizzleSqlChunkLike): Promise<unknown> {\n\tif (typeof client.get === 'function') {\n\t\treturn await client.get(query);\n\t}\n\n\treturn await executeDrizzleAll(client, query);\n}\n\nfunction buildDrizzleQuery(sqlTag: DrizzleSqlTagLike, sqlText: string, bindings: any[]): DrizzleSqlChunkLike {\n\tconst segments = splitQuestionPlaceholders(sqlText);\n\tconst placeholderCount = segments.length - 1;\n\n\tif (placeholderCount !== bindings.length) {\n\t\tthrow new CollegeDBError(\n\t\t\t`Drizzle binding mismatch: expected ${placeholderCount} bindings, received ${bindings.length}`,\n\t\t\t'DRIZZLE_BINDINGS_MISMATCH'\n\t\t);\n\t}\n\n\tif (placeholderCount === 0) {\n\t\treturn sqlTag.raw(sqlText);\n\t}\n\n\tconst statement = typeof sqlTag.empty === 'function' ? sqlTag.empty() : sqlTag.raw('');\n\n\tfor (let i = 0; i < segments.length; i++) {\n\t\tconst segment = segments[i];\n\t\tif (segment) {\n\t\t\tstatement.append(sqlTag.raw(segment));\n\t\t}\n\n\t\tif (i < placeholderCount) {\n\t\t\tstatement.append(sqlTag`${bindings[i]}`);\n\t\t}\n\t}\n\n\treturn statement;\n}\n\nfunction splitQuestionPlaceholders(sql: string): string[] {\n\tconst segments: string[] = [];\n\tlet segmentStart = 0;\n\n\tlet inSingleQuote = false;\n\tlet inDoubleQuote = false;\n\tlet inLineComment = false;\n\tlet inBlockComment = false;\n\n\tfor (let i = 0; i < sql.length; i++) {\n\t\tconst char = sql[i]!;\n\t\tconst next = i + 1 < sql.length ? sql[i + 1] : '';\n\n\t\tif (inLineComment) {\n\t\t\tif (char === '\\n') {\n\t\t\t\tinLineComment = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (inBlockComment) {\n\t\t\tif (char === '*' && next === '/') {\n\t\t\t\ti++;\n\t\t\t\tinBlockComment = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!inSingleQuote && !inDoubleQuote) {\n\t\t\tif (char === '-' && next === '-') {\n\t\t\t\ti++;\n\t\t\t\tinLineComment = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (char === '/' && next === '*') {\n\t\t\t\ti++;\n\t\t\t\tinBlockComment = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (char === \"'\" && !inDoubleQuote) {\n\t\t\tif (inSingleQuote && next === \"'\") {\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tinSingleQuote = !inSingleQuote;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === '\"' && !inSingleQuote) {\n\t\t\tif (inDoubleQuote && next === '\"') {\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tinDoubleQuote = !inDoubleQuote;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === '?' && !inSingleQuote && !inDoubleQuote) {\n\t\t\tsegments.push(sql.slice(segmentStart, i));\n\t\t\tsegmentStart = i + 1;\n\t\t}\n\t}\n\n\tsegments.push(sql.slice(segmentStart));\n\treturn segments;\n}\n\nfunction extractRowsFromDrizzleExecute<T>(result: unknown): T[] {\n\tconst extractRowsFromObject = (value: unknown): T[] | undefined => {\n\t\tif (!value || typeof value !== 'object' || Array.isArray(value)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst objectValue = value as Record<string, unknown>;\n\t\tif (Array.isArray(objectValue.rows)) {\n\t\t\treturn objectValue.rows as T[];\n\t\t}\n\n\t\tif (Array.isArray(objectValue.results)) {\n\t\t\treturn objectValue.results as T[];\n\t\t}\n\n\t\tif (Array.isArray(objectValue.data)) {\n\t\t\treturn objectValue.data as T[];\n\t\t}\n\n\t\treturn undefined;\n\t};\n\n\tconst looksLikeRowObject = (value: unknown): value is Record<string, unknown> => {\n\t\tif (!value || typeof value !== 'object' || Array.isArray(value)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn Object.keys(value).length > 0;\n\t};\n\n\tif (Array.isArray(result)) {\n\t\tif (result.length === 2) {\n\t\t\tconst firstObjectRows = extractRowsFromObject(result[0]);\n\t\t\tif (firstObjectRows) {\n\t\t\t\treturn firstObjectRows;\n\t\t\t}\n\n\t\t\tconst secondObjectRows = extractRowsFromObject(result[1]);\n\t\t\tif (secondObjectRows) {\n\t\t\t\treturn secondObjectRows;\n\t\t\t}\n\n\t\t\tif (!Array.isArray(result[0]) && !Array.isArray(result[1])) {\n\t\t\t\tif (looksLikeRowObject(result[0])) {\n\t\t\t\t\treturn [result[0] as T];\n\t\t\t\t}\n\n\t\t\t\tif (looksLikeRowObject(result[1])) {\n\t\t\t\t\treturn [result[1] as T];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Array.isArray(result[0])) {\n\t\t\t\treturn result[0] as T[];\n\t\t\t}\n\n\t\t\tif (Array.isArray(result[1])) {\n\t\t\t\treturn result[1] as T[];\n\t\t\t}\n\t\t}\n\n\t\treturn result as T[];\n\t}\n\n\tif (result && typeof result === 'object') {\n\t\tconst objectRows = extractRowsFromObject(result);\n\t\tif (objectRows) {\n\t\t\treturn objectRows;\n\t\t}\n\t}\n\n\treturn [];\n}\n\nfunction extractMetaFromDrizzleExecute(result: unknown): Record<string, unknown> {\n\tif (!result) {\n\t\treturn {};\n\t}\n\n\tlet objectResult: Record<string, unknown> | undefined;\n\n\tif (Array.isArray(result)) {\n\t\tif (result.length === 2) {\n\t\t\t// Try result[0] first (metadata-first format like [metadata, rows])\n\t\t\tif (result[0] && typeof result[0] === 'object' && !Array.isArray(result[0])) {\n\t\t\t\tobjectResult = result[0] as Record<string, unknown>;\n\t\t\t}\n\t\t\t// Try result[1] if result[0] is not metadata (metadata-second format like [rows, metadata])\n\t\t\telse if (result[1] && typeof result[1] === 'object' && !Array.isArray(result[1])) {\n\t\t\t\tobjectResult = result[1] as Record<string, unknown>;\n\t\t\t}\n\t\t}\n\t} else if (typeof result === 'object' && !Array.isArray(result)) {\n\t\tobjectResult = result as Record<string, unknown>;\n\t}\n\n\tif (!objectResult) {\n\t\treturn {};\n\t}\n\n\tconst meta: Record<string, unknown> = {};\n\n\tconst changes = toMaybeNumber(objectResult.rowCount) ?? toMaybeNumber(objectResult.changes) ?? toMaybeNumber(objectResult.affectedRows);\n\tif (changes !== undefined) {\n\t\tmeta.changes = changes;\n\t}\n\n\tconst lastRowId =\n\t\tobjectResult.lastInsertRowid ??\n\t\tobjectResult.lastInsertId ??\n\t\tobjectResult.lastID ??\n\t\tobjectResult.lastRowID ??\n\t\tobjectResult.insertId ??\n\t\tobjectResult.insertID;\n\tif (typeof lastRowId === 'number' || typeof lastRowId === 'string') {\n\t\tmeta.last_row_id = lastRowId;\n\t}\n\n\tif (objectResult.meta && typeof objectResult.meta === 'object') {\n\t\tObject.assign(meta, objectResult.meta as Record<string, unknown>);\n\t}\n\n\treturn meta;\n}\n\nasync function getNuxtHubKVValue<T = unknown>(client: NuxtHubKVLike, key: string): Promise<T | null | undefined> {\n\tif (typeof client.get === 'function') {\n\t\treturn await client.get<T>(key);\n\t}\n\n\tif (typeof client.getItem === 'function') {\n\t\treturn await client.getItem<T>(key);\n\t}\n\n\tthrow new CollegeDBError('NuxtHub KV client must expose get() or getItem()', 'NUXTHUB_KV_CLIENT_INVALID');\n}\n\nasync function setNuxtHubKVValue(client: NuxtHubKVLike, key: string, value: string): Promise<void> {\n\tif (typeof client.set === 'function') {\n\t\tawait client.set(key, value);\n\t\treturn;\n\t}\n\n\tif (typeof client.setItem === 'function') {\n\t\tawait client.setItem(key, value);\n\t\treturn;\n\t}\n\n\tthrow new CollegeDBError('NuxtHub KV client must expose set() or setItem()', 'NUXTHUB_KV_CLIENT_INVALID');\n}\n\nasync function deleteNuxtHubKVValue(client: NuxtHubKVLike, key: string): Promise<void> {\n\tif (typeof client.del === 'function') {\n\t\tawait client.del(key);\n\t\treturn;\n\t}\n\n\tif (typeof client.removeItem === 'function') {\n\t\tawait client.removeItem(key);\n\t\treturn;\n\t}\n\n\tthrow new CollegeDBError('NuxtHub KV client must expose del() or removeItem()', 'NUXTHUB_KV_CLIENT_INVALID');\n}\n\nasync function listNuxtHubKVKeys(client: NuxtHubKVLike, prefix: string): Promise<string[]> {\n\tlet keys: readonly string[];\n\n\tif (typeof client.keys === 'function') {\n\t\tkeys = await client.keys(prefix);\n\t} else if (typeof client.getKeys === 'function') {\n\t\tkeys = await client.getKeys(prefix);\n\t} else {\n\t\tthrow new CollegeDBError('NuxtHub KV client must expose keys() or getKeys()', 'NUXTHUB_KV_CLIENT_INVALID');\n\t}\n\n\tif (!Array.isArray(keys)) {\n\t\treturn [];\n\t}\n\n\tif (!prefix) {\n\t\treturn [...keys];\n\t}\n\n\treturn keys.filter((key) => key.startsWith(prefix));\n}\n\nfunction extractRowsFromSQLiteExecute<T>(result: unknown): T[] {\n\tif (Array.isArray(result)) {\n\t\treturn result as T[];\n\t}\n\n\tif (result && typeof result === 'object') {\n\t\tconst objectResult = result as Record<string, unknown>;\n\n\t\tif (Array.isArray(objectResult.rows)) {\n\t\t\treturn objectResult.rows as T[];\n\t\t}\n\t\tif (Array.isArray(objectResult.results)) {\n\t\t\treturn objectResult.results as T[];\n\t\t}\n\t}\n\n\treturn [];\n}\n\nfunction createMeta(startedAt: number, extra: Record<string, unknown> = {}): QueryResultMeta {\n\treturn {\n\t\tduration: Date.now() - startedAt,\n\t\t...extra\n\t};\n}\n\nfunction toMaybeNumber(value: unknown): number | undefined {\n\tif (typeof value === 'number' && Number.isFinite(value)) {\n\t\treturn value;\n\t}\n\treturn undefined;\n}\n\nconst postgresPlaceholderCache = new Map<string, string>();\n\nfunction rewriteQuestionPlaceholders(sql: string): string {\n\tconst cached = postgresPlaceholderCache.get(sql);\n\tif (cached) {\n\t\treturn cached;\n\t}\n\n\tlet output = '';\n\tlet placeholderIndex = 0;\n\tlet inSingleQuote = false;\n\tlet inDoubleQuote = false;\n\tlet inLineComment = false;\n\tlet inBlockComment = false;\n\n\tfor (let i = 0; i < sql.length; i++) {\n\t\tconst char = sql[i]!;\n\t\tconst next = i + 1 < sql.length ? sql[i + 1] : '';\n\n\t\tif (inLineComment) {\n\t\t\toutput += char;\n\t\t\tif (char === '\\n') {\n\t\t\t\tinLineComment = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (inBlockComment) {\n\t\t\toutput += char;\n\t\t\tif (char === '*' && next === '/') {\n\t\t\t\toutput += '/';\n\t\t\t\ti++;\n\t\t\t\tinBlockComment = false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!inSingleQuote && !inDoubleQuote) {\n\t\t\tif (char === '-' && next === '-') {\n\t\t\t\toutput += '--';\n\t\t\t\ti++;\n\t\t\t\tinLineComment = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (char === '/' && next === '*') {\n\t\t\t\toutput += '/*';\n\t\t\t\ti++;\n\t\t\t\tinBlockComment = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (char === \"'\" && !inDoubleQuote) {\n\t\t\tinSingleQuote = !inSingleQuote;\n\t\t\toutput += char;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === '\"' && !inSingleQuote) {\n\t\t\tinDoubleQuote = !inDoubleQuote;\n\t\t\toutput += char;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (char === '?' && !inSingleQuote && !inDoubleQuote) {\n\t\t\tplaceholderIndex++;\n\t\t\toutput += `$${placeholderIndex}`;\n\t\t\tcontinue;\n\t\t}\n\n\t\toutput += char;\n\t}\n\n\tpostgresPlaceholderCache.set(sql, output);\n\tif (postgresPlaceholderCache.size > 5000) {\n\t\tconst firstKey = postgresPlaceholderCache.keys().next().value;\n\t\tif (firstKey) {\n\t\t\tpostgresPlaceholderCache.delete(firstKey);\n\t\t}\n\t}\n\n\treturn output;\n}\n"
12
12
  ],
13
- "mappings": "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",
14
- "debugId": "DEC582821021CEEA64756E2164756E21",
13
+ "mappings": "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",
14
+ "debugId": "46EBE6102EC18AED64756E2164756E21",
15
15
  "names": []
16
16
  }