@earth-app/collegedb 1.0.1 → 1.0.2

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/durable.d.ts CHANGED
@@ -189,6 +189,16 @@ export declare class ShardCoordinator {
189
189
  * @example Response body: `{"success": true}`
190
190
  */
191
191
  private handleFlush;
192
+ /**
193
+ * Resolves the effective sharding strategy for a given operation type
194
+ *
195
+ * @private
196
+ * @param configStrategy - The strategy from state configuration
197
+ * @param requestStrategy - Optional strategy override from request
198
+ * @param operationType - The type of operation (read/write)
199
+ * @returns The effective sharding strategy to use
200
+ */
201
+ private resolveStrategy;
192
202
  /**
193
203
  * Implements the core shard selection logic for different allocation strategies.
194
204
  * Uses consistent algorithms to ensure predictable shard assignment.
@@ -203,7 +213,7 @@ export declare class ShardCoordinator {
203
213
  * @param state - Current coordinator state containing available shards
204
214
  * @param strategy - The allocation strategy to use
205
215
  * @returns The selected shard binding name
206
- * @throws {Error} If no shards are available
216
+ * @throws {CollegeDBError} If no shards are available
207
217
  * @example
208
218
  * ```typescript
209
219
  * const shard = this.selectShard('user-123', state, 'hash');
@@ -230,7 +240,7 @@ export declare class ShardCoordinator {
230
240
  * moved from a shard. Prevents negative counts.
231
241
  * @param shard - The shard binding name to decrement
232
242
  * @returns Promise that resolves when the count is updated
233
- * @throws {Error} If the shard is not known to the coordinator
243
+ * @throws {CollegeDBError} If the shard is not known to the coordinator
234
244
  * @example
235
245
  * ```typescript
236
246
  * await coordinator.decrementShardCount('db-west');
@@ -1 +1 @@
1
- {"version":3,"file":"durable.d.ts","sourceRoot":"","sources":["../src/durable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGpE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,gBAAgB;IAC5B;;;OAGG;IACH,OAAO,CAAC,KAAK,CAAqB;IAElC;;;OAGG;gBACS,KAAK,EAAE,kBAAkB;IAIrC;;;;;;;;;;OAUG;YACW,QAAQ;IAYtB;;;;;;;;;;OAUG;YACW,SAAS;IAIvB;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACG,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAgChD;;;;;;OAMG;YACW,gBAAgB;IAO9B;;;;;;;;;OASG;YACW,cAAc;IAmB5B;;;;;;;;;OASG;YACW,iBAAiB;IAoB/B;;;;;;OAMG;YACW,cAAc;IAQ5B;;;;;;;;OAQG;YACW,iBAAiB;IAe/B;;;;;;;;;;;;;;;OAeG;YACW,mBAAmB;IA2BjC;;;;;;;;;;OAUG;YACW,WAAW;IAOzB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,WAAW;IA8BnB;;;;;;;;;;;OAWG;IACG,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASvD;;;;;;;;;;;OAWG;IACG,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAQvD"}
1
+ {"version":3,"file":"durable.d.ts","sourceRoot":"","sources":["../src/durable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAIpE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,gBAAgB;IAC5B;;;OAGG;IACH,OAAO,CAAC,KAAK,CAAqB;IAElC;;;OAGG;gBACS,KAAK,EAAE,kBAAkB;IAIrC;;;;;;;;;;OAUG;YACW,QAAQ;IAYtB;;;;;;;;;;OAUG;YACW,SAAS;IAIvB;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACG,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAgChD;;;;;;OAMG;YACW,gBAAgB;IAO9B;;;;;;;;;OASG;YACW,cAAc;IA4B5B;;;;;;;;;OASG;YACW,iBAAiB;IA6B/B;;;;;;OAMG;YACW,cAAc;IAQ5B;;;;;;;;OAQG;YACW,iBAAiB;IA+B/B;;;;;;;;;;;;;;;OAeG;YACW,mBAAmB;IAuCjC;;;;;;;;;;OAUG;YACW,WAAW;IAOzB;;;;;;;;OAQG;IACH,OAAO,CAAC,eAAe;IAmBvB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,WAAW;IA0CnB;;;;;;;;;;;OAWG;IACG,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASvD;;;;;;;;;;;OAWG;IACG,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAQvD"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @fileoverview Custom error class for CollegeDB operations
3
+ *
4
+ * This module provides the CollegeDBError class that extends the native Error class
5
+ * to provide more specific error information for CollegeDB operations. This allows
6
+ * for better error handling and debugging throughout the application.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { CollegeDBError } from './errors.js';
11
+ *
12
+ * throw new CollegeDBError('Failed to allocate shard', 'SHARD_ALLOCATION_ERROR');
13
+ * ```
14
+ *
15
+ * @author CollegeDB Team
16
+ * @since 1.0.2
17
+ */
18
+ /**
19
+ * Custom error class for CollegeDB operations
20
+ *
21
+ * Extends the native Error class to provide more specific error information
22
+ * for CollegeDB operations. Includes an optional error code for better
23
+ * error categorization and handling.
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * try {
28
+ * await getShardForKey('invalid-key');
29
+ * } catch (error) {
30
+ * if (error instanceof CollegeDBError) {
31
+ * console.error(`CollegeDB Error (${error.code}): ${error.message}`);
32
+ * }
33
+ * }
34
+ * ```
35
+ */
36
+ export declare class CollegeDBError extends Error {
37
+ /**
38
+ * Optional error code for categorizing different types of errors
39
+ */
40
+ readonly code?: string;
41
+ /**
42
+ * Creates a new CollegeDBError instance
43
+ * @param message - Error message describing what went wrong
44
+ * @param code - Optional error code for categorization
45
+ * @example
46
+ * ```typescript
47
+ * throw new CollegeDBError('Shard not found', 'SHARD_NOT_FOUND');
48
+ * ```
49
+ */
50
+ constructor(message: string, code?: string);
51
+ }
52
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACxC;;OAEG;IACH,SAAgB,IAAI,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;;;;OAQG;gBACS,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAU1C"}
package/dist/index.d.ts CHANGED
@@ -8,9 +8,10 @@
8
8
  * @author Gregory Mitchell
9
9
  * @license MIT
10
10
  */
11
- export { all, allShard, createSchema, first, flush, getShardStats, initialize, listKnownShards, prepare, reassignShard, run } from './router.js';
11
+ export { all, allShard, collegedb, createSchema, first, firstShard, flush, getClosestRegionFromIP, getShardStats, initialize, initializeAsync, listKnownShards, prepare, reassignShard, resetConfig, run, runShard } from './router.js';
12
12
  export { ShardCoordinator } from './durable.js';
13
+ export { CollegeDBError } from './errors.js';
13
14
  export { KVShardMapper } from './kvmap.js';
14
- export { autoDetectAndMigrate, checkMigrationNeeded, clearMigrationCache, createMappingsForExistingKeys, createSchemaAcrossShards, discoverExistingPrimaryKeys, dropSchema, integrateExistingDatabase, listTables, migrateRecord, schemaExists, validateTableForSharding, type IntegrationOptions, type IntegrationResult, type ValidationResult } from './migrations.js';
15
- export type { CollegeDBConfig, Env, ShardCoordinatorState, ShardMapping, ShardStats, ShardingStrategy } from './types.js';
15
+ export { autoDetectAndMigrate, checkMigrationNeeded, clearMigrationCache, clearShardMigrationCache, createMappingsForExistingKeys, createSchemaAcrossShards, discoverExistingPrimaryKeys, dropSchema, integrateExistingDatabase, listTables, migrateRecord, schemaExists, validateTableForSharding, type IntegrationOptions, type IntegrationResult, type ValidationResult } from './migrations.js';
16
+ export type { CollegeDBConfig, D1Region, Env, MixedShardingStrategy, OperationType, ShardCoordinatorState, ShardLocation, ShardMapping, ShardStats, ShardingStrategy } from './types.js';
16
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EACN,GAAG,EACH,QAAQ,EACR,YAAY,EACZ,KAAK,EACL,KAAK,EACL,aAAa,EACb,UAAU,EACV,eAAe,EACf,OAAO,EACP,aAAa,EACb,GAAG,EACH,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3C,OAAO,EACN,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,6BAA6B,EAC7B,wBAAwB,EACxB,2BAA2B,EAC3B,UAAU,EACV,yBAAyB,EACzB,UAAU,EACV,aAAa,EACb,YAAY,EACZ,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EAAE,eAAe,EAAE,GAAG,EAAE,qBAAqB,EAAE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EACN,GAAG,EACH,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,KAAK,EACL,UAAU,EACV,KAAK,EACL,sBAAsB,EACtB,aAAa,EACb,UAAU,EACV,eAAe,EACf,eAAe,EACf,OAAO,EACP,aAAa,EACb,WAAW,EACX,GAAG,EACH,QAAQ,EACR,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3C,OAAO,EACN,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,6BAA6B,EAC7B,wBAAwB,EACxB,2BAA2B,EAC3B,UAAU,EACV,yBAAyB,EACzB,UAAU,EACV,aAAa,EACb,YAAY,EACZ,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EACX,eAAe,EACf,QAAQ,EACR,GAAG,EACH,qBAAqB,EACrB,aAAa,EACb,qBAAqB,EACrB,aAAa,EACb,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,19 +1,19 @@
1
- var s=Object.defineProperty;var b=(z,G)=>{for(var J in G)s(z,J,{get:G[J],enumerable:!0,configurable:!0,set:(H)=>G[J]=()=>H})};var r=(z,G)=>()=>(z&&(G=z(z=0)),G);var C={};b(C,{KVShardMapper:()=>D});class D{kv;constructor(z){this.kv=z}async getShardMapping(z){let G=`shard:${z}`;return await this.kv.get(G,"json")}async setShardMapping(z,G){let J=`shard:${z}`,H={shard:G,createdAt:Date.now(),updatedAt:Date.now()};await this.kv.put(J,JSON.stringify(H))}async updateShardMapping(z,G){let J=await this.getShardMapping(z);if(!J)throw new Error(`No existing mapping found for primary key: ${z}`);let H=`shard:${z}`,Q={...J,shard:G,updatedAt:Date.now()};await this.kv.put(H,JSON.stringify(Q))}async deleteShardMapping(z){let G=`shard:${z}`;await this.kv.delete(G)}async getKnownShards(){return await this.kv.get("known_shards","json")||[]}async setKnownShards(z){if(!z||z.length===0)return;await this.kv.put("known_shards",JSON.stringify(z))}async addKnownShard(z){if(!z)return;let G=await this.getKnownShards();if(!G.includes(z))G.push(z),await this.setKnownShards(G)}async getKeysForShard(z){let G=[],J=await this.kv.list({prefix:"shard:"});for(let H of J.keys)if((await this.getShardMapping(H.name.replace("shard:","")))?.shard===z)G.push(H.name.replace("shard:",""));return G}async getShardKeyCounts(){let z={},G=await this.kv.list({prefix:"shard:"});for(let J of G.keys){let H=await this.getShardMapping(J.name.replace("shard:",""));if(H)z[H.shard]=(z[H.shard]||0)+1}return z}async clearAllMappings(){let G=(await this.kv.list({prefix:"shard:"})).keys.map((J)=>this.kv.delete(J.name));await Promise.all(G)}}var B={};b(B,{validateTableForSharding:()=>q,schemaExists:()=>f,migrateRecord:()=>y,listTables:()=>P,integrateExistingDatabase:()=>h,dropSchema:()=>g,discoverExistingPrimaryKeys:()=>S,createSchemaAcrossShards:()=>c,createSchema:()=>N,createMappingsForExistingKeys:()=>p,clearMigrationCache:()=>m,checkMigrationNeeded:()=>o,autoDetectAndMigrate:()=>l});async function N(z,G){let J=G.split(";").map((H)=>H.trim()).filter((H)=>H.length>0&&!H.startsWith("--"));for(let H of J)try{await z.prepare(H).run()}catch(Q){throw console.error("Failed to execute schema statement:",H,Q),new Error(`Schema migration failed: ${Q}`)}}async function c(z,G){let J=Object.entries(z).map(([H,Q])=>{return N(Q,G).catch((W)=>{throw new Error(`Failed to create schema on shard ${H}: ${W.message}`)})});await Promise.all(J)}async function f(z,G){try{return await z.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='?'").bind(G).first()!==null}catch{return!1}}async function g(z,...G){for(let J of G)try{await z.prepare(`DROP TABLE IF EXISTS ${J}`).run()}catch(H){console.error(`Failed to drop table ${J}:`,H)}}async function P(z){try{return(await z.prepare("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name").all()).results.map((J)=>J.name)}catch{return[]}}async function y(z,G,J,H){let Q=await z.prepare(`SELECT * FROM ${H} WHERE id = ?`).bind(J).first();if(!Q)throw new Error(`Record with primary key ${J} not found in source database`);if(!await f(G,H))await N(G,H);let W=Object.keys(Q),Z=W.map(()=>"?").join(", "),X=W.map(($)=>Q[$]),Y=`INSERT OR REPLACE INTO ${H} (${W.join(", ")}) VALUES (${Z})`;await G.prepare(Y).bind(...X).run(),await z.prepare(`DELETE FROM ${H} WHERE id = ?`).bind(J).run()}async function S(z,G,J="id"){try{return(await z.prepare(`SELECT ${J} FROM ${G}`).all()).results.map((Q)=>String(Q[J]))}catch(H){throw new Error(`Failed to discover primary keys in table ${G}: ${H}`)}}async function p(z,G,J,H){let Q=G.length;for(let W=0;W<z.length;W++){let Z=z[W],X;switch(J){case"hash":let Y=0;for(let _=0;_<Z.length;_++){let L=Z.charCodeAt(_);Y=(Y<<5)-Y+L,Y=Y&Y}let $=Math.abs(Y)%Q;X=G[$];break;case"random":X=G[Math.floor(Math.random()*Q)];break;default:X=G[W%Q];break}await H.setShardMapping(Z,X)}}async function q(z,G,J){let H=[],Q=0;try{if(!await z.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?").bind(G).first())return H.push(`Table '${G}' does not exist`),{isValid:!1,tableName:G,primaryKeyColumn:J,recordCount:0,issues:H};if(!(await z.prepare(`PRAGMA table_info(${G})`).all()).results.some(($)=>$.name===J&&$.pk===1))H.push(`Primary key column '${J}' not found or not set as primary key`);if(Q=(await z.prepare(`SELECT COUNT(*) as count FROM ${G}`).first())?.count||0,Q===0)H.push(`Table '${G}' is empty`)}catch(W){H.push(`Database validation error: ${W}`)}return{isValid:H.length===0,tableName:G,primaryKeyColumn:J,recordCount:Q,issues:H}}async function h(z,G,J,H={}){let{tables:Q,primaryKeyColumn:W="id",strategy:Z="hash",addShardMappingsTable:X=!0,dryRun:Y=!1}=H,$=[],_=0,L=0,U=0;try{let x=(Q||await P(z)).filter((E)=>E!=="shard_mappings");for(let E of x)try{let I=await q(z,E,W);if(!I.isValid){$.push(`Table ${E}: ${I.issues.join(", ")}`);continue}let A=await S(z,E,W);if(A.length===0){$.push(`Table ${E} has no records to process`);continue}if(!Y)for(let F of A)await J.setShardMapping(F,G),U++;_++,L+=A.length}catch(I){$.push(`Failed to process table ${E}: ${I}`)}if(X&&!Y){if(!(await P(z)).includes("shard_mappings"))await z.prepare(`
1
+ var zJ=Object.defineProperty;var h=(J,Q)=>{for(var U in Q)zJ(J,U,{get:Q[U],enumerable:!0,configurable:!0,set:(Z)=>Q[U]=()=>Z})};var b=(J,Q)=>()=>(J&&(Q=J(J=0)),Q);var G;var D=b(()=>{G=class G extends Error{code;constructor(J,Q){super(J);if(this.name="CollegeDBError",this.code=Q,Error.captureStackTrace)Error.captureStackTrace(this,G)}}});var g={};h(g,{KVShardMapper:()=>A});class A{kv;constructor(J){this.kv=J}async getShardMapping(J){let Q=`${_}${J}`;return await this.kv.get(Q,"json")}async setShardMapping(J,Q){let U=`${_}${J}`,Z={shard:Q,createdAt:Date.now(),updatedAt:Date.now()};await this.kv.put(U,JSON.stringify(Z))}async updateShardMapping(J,Q){let U=await this.getShardMapping(J);if(!U)throw new G(`No existing mapping found for primary key: ${J}`,"MAPPING_NOT_FOUND");let Z=`${_}${J}`,$={...U,shard:Q,updatedAt:Date.now()};await this.kv.put(Z,JSON.stringify($))}async deleteShardMapping(J){let Q=`${_}${J}`;await this.kv.delete(Q)}async getKnownShards(){return await this.kv.get(l,"json")||[]}async setKnownShards(J){if(!J||J.length===0)return;await this.kv.put(l,JSON.stringify(J))}async addKnownShard(J){if(!J)return;let Q=await this.getKnownShards();if(!Q.includes(J))Q.push(J),await this.setKnownShards(Q)}async getKeysForShard(J){let Q=[],U=await this.kv.list({prefix:_});for(let Z of U.keys)if((await this.getShardMapping(Z.name.replace(_,"")))?.shard===J)Q.push(Z.name.replace(_,""));return Q}async getShardKeyCounts(){let J={},Q=await this.kv.list({prefix:_});for(let U of Q.keys){let Z=await this.getShardMapping(U.name.replace(_,""));if(Z)J[Z.shard]=(J[Z.shard]||0)+1}return J}async clearAllMappings(){let Q=(await this.kv.list({prefix:_})).keys.map((U)=>this.kv.delete(U.name));await Promise.all(Q)}}var _="shard:",l="known_shards";var v=b(()=>{D()});var k={};h(k,{validateTableForSharding:()=>N,schemaExists:()=>c,migrateRecord:()=>o,listTables:()=>P,integrateExistingDatabase:()=>t,dropSchema:()=>n,discoverExistingPrimaryKeys:()=>S,createSchemaAcrossShards:()=>d,createSchema:()=>p,createMappingsForExistingKeys:()=>i,clearShardMigrationCache:()=>e,clearMigrationCache:()=>a,checkMigrationNeeded:()=>r,autoDetectAndMigrate:()=>s});async function p(J,Q){let U=Q.split(";").map((Z)=>Z.trim()).filter((Z)=>Z.length>0&&!Z.startsWith("--"));for(let Z of U)try{await J.prepare(Z).run()}catch($){throw console.error("Failed to execute schema statement:",Z,$),new G(`Schema migration failed: ${$}`,"SCHEMA_MIGRATION_FAILED")}}async function d(J,Q){let U=Object.entries(J).map(([Z,$])=>{return p($,Q).catch((z)=>{throw new G(`Failed to create schema on shard ${Z}: ${z.message}`,"SCHEMA_CREATION_FAILED")})});await Promise.all(U)}async function c(J,Q){try{return await J.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='?'").bind(Q).first()!==null}catch{return!1}}async function n(J,...Q){for(let U of Q)try{await J.prepare(`DROP TABLE IF EXISTS ${U}`).run()}catch(Z){console.error(`Failed to drop table ${U}:`,Z)}}async function P(J){try{return(await J.prepare("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name").all()).results.map((U)=>U.name)}catch{return[]}}async function o(J,Q,U,Z){let $=await J.prepare(`SELECT * FROM ${Z} WHERE id = ?`).bind(U).first();if(!$)throw new G(`Record with primary key ${U} not found in source database`,"RECORD_NOT_FOUND");if(!await c(Q,Z))await p(Q,Z);let z=Object.keys($),Y=z.map(()=>"?").join(", "),V=z.map((O)=>$[O]),W=`INSERT OR REPLACE INTO ${Z} (${z.join(", ")}) VALUES (${Y})`;await Q.prepare(W).bind(...V).run(),await J.prepare(`DELETE FROM ${Z} WHERE id = ?`).bind(U).run()}async function S(J,Q,U="id"){try{return(await J.prepare(`SELECT ${U} FROM ${Q}`).all()).results.map(($)=>String($[U]))}catch(Z){throw new G(`Failed to discover primary keys in table ${Q}: ${Z}`,"DISCOVERY_FAILED")}}async function i(J,Q,U,Z){let $=Q.length;for(let z=0;z<J.length;z++){let Y=J[z],V;switch(U){case"hash":let W=0;for(let L=0;L<Y.length;L++){let X=Y.charCodeAt(L);W=(W<<5)-W+X,W=W&W}let O=Math.abs(W)%$;V=Q[O];break;case"random":V=Q[Math.floor(Math.random()*$)];break;default:V=Q[z%$];break}await Z.setShardMapping(Y,V)}}async function N(J,Q,U){let Z=[],$=0;try{if(!await J.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name=?").bind(Q).first())return Z.push(`Table '${Q}' does not exist`),{isValid:!1,tableName:Q,primaryKeyColumn:U,recordCount:0,issues:Z};if(!(await J.prepare(`PRAGMA table_info(${Q})`).all()).results.some((O)=>O.name===U&&O.pk===1))Z.push(`Primary key column '${U}' not found or not set as primary key`);if($=(await J.prepare(`SELECT COUNT(*) as count FROM ${Q}`).first())?.count||0,$===0)Z.push(`Table '${Q}' is empty`)}catch(z){Z.push(`Database validation error: ${z}`)}return{isValid:Z.length===0,tableName:Q,primaryKeyColumn:U,recordCount:$,issues:Z}}async function t(J,Q,U,Z={}){let{tables:$,primaryKeyColumn:z="id",strategy:Y="hash",addShardMappingsTable:V=!0,dryRun:W=!1}=Z,O=[],L=0,X=0,x=0;try{let T=($||await P(J)).filter((j)=>j!=="shard_mappings");for(let j of T)try{let w=await N(J,j,z);if(!w.isValid){O.push(`Table ${j}: ${w.issues.join(", ")}`);continue}let M=await S(J,j,z);if(M.length===0){O.push(`Table ${j} has no records to process`);continue}if(!W)for(let I of M)await U.setShardMapping(I,Q),x++;L++,X+=M.length}catch(w){O.push(`Failed to process table ${j}: ${w}`)}if(V&&!W){if(!(await P(J)).includes("shard_mappings"))await J.prepare(`
2
2
  CREATE TABLE IF NOT EXISTS shard_mappings (
3
3
  primary_key TEXT PRIMARY KEY,
4
4
  shard_name TEXT NOT NULL,
5
5
  created_at INTEGER NOT NULL,
6
6
  updated_at INTEGER NOT NULL
7
- );`.trim()).run()}if(!Y)await J.addKnownShard(G)}catch(O){$.push(`Integration failed: ${O}`)}return{success:$.length===0||$.length>0&&_>0,shardName:G,tablesProcessed:_,totalRecords:L,mappingsCreated:U,issues:$}}async function l(z,G,J,H={}){let{primaryKeyColumn:Q="id",tablesToCheck:W,skipCache:Z=!1,maxRecordsToCheck:X=1000}=H,Y=`${G}_migration_check`;if(!Z&&R.has(Y))return{migrationNeeded:!1,migrationPerformed:!1,recordsMigrated:0,tablesProcessed:0,issues:[]};let $=[],_=0,L=0,U=!1,O=!1;try{let{KVShardMapper:x}=await Promise.resolve().then(() => C),E=new x(J.kv),I=await P(z),A=W||I.filter((F)=>F!=="shard_mappings"&&!F.startsWith("sqlite_")&&F!=="sqlite_sequence");if(A.length===0)return R.set(Y,!0),{migrationNeeded:!1,migrationPerformed:!1,recordsMigrated:0,tablesProcessed:0,issues:[]};for(let F of A)try{let j=await q(z,F,Q);if(!j.isValid||j.recordCount===0)continue;let d=Math.min(X,j.recordCount),t=await z.prepare(`
8
- SELECT ${Q} FROM ${F}
9
- ORDER BY ${Q}
10
- LIMIT ?`.trim()).bind(d).all(),u=0,i=t.results.slice(0,10);for(let w of i){let M=String(w[Q]);if(!await E.getShardMapping(M))u++,U=!0}if(u>0){console.log(`Auto-migrating table ${F} in shard ${G} (${j.recordCount} records)`);let w=await S(z,F,Q),M=0;for(let k of w)if(!await E.getShardMapping(k))await E.setShardMapping(k,G),M++;_+=M,L++,O=!0,console.log(`Auto-migrated ${M} records from table ${F}`)}}catch(j){$.push(`Auto-migration failed for table ${F}: ${j}`)}if(O){if(await E.addKnownShard(G),!I.includes("shard_mappings"))await z.prepare(`CREATE TABLE IF NOT EXISTS shard_mappings (
7
+ );`.trim()).run()}if(!W)await U.addKnownShard(Q)}catch(F){O.push(`Integration failed: ${F}`)}return{success:O.length===0||O.length>0&&L>0,shardName:Q,tablesProcessed:L,totalRecords:X,mappingsCreated:x,issues:O}}async function s(J,Q,U,Z={}){let{primaryKeyColumn:$="id",tablesToCheck:z,skipCache:Y=!1,maxRecordsToCheck:V=1000}=Z,W=`${Q}_migration_check`;if(!Y&&E.has(W))return{migrationNeeded:!1,migrationPerformed:!1,recordsMigrated:0,tablesProcessed:0,issues:[]};let O=[],L=0,X=0,x=!1,F=!1;try{let{KVShardMapper:T}=await Promise.resolve().then(() => (v(),g)),j=new T(U.kv),w=await P(J),M=z||w.filter((I)=>I!=="shard_mappings"&&!I.startsWith("sqlite_")&&I!=="sqlite_sequence");if(M.length===0)return E.set(W,!0),{migrationNeeded:!1,migrationPerformed:!1,recordsMigrated:0,tablesProcessed:0,issues:[]};for(let I of M)try{let R=await N(J,I,$);if(!R.isValid||R.recordCount===0)continue;let UJ=Math.min(V,R.recordCount),ZJ=await J.prepare(`
8
+ SELECT ${$} FROM ${I}
9
+ ORDER BY ${$}
10
+ LIMIT ?`.trim()).bind(UJ).all(),m=0,$J=ZJ.results.slice(0,10);for(let f of $J){let q=String(f[$]);if(!await j.getShardMapping(q))m++,x=!0}if(m>0){console.log(`Auto-migrating table ${I} in shard ${Q} (${R.recordCount} records)`);let f=await S(J,I,$),q=0;for(let u of f)if(!await j.getShardMapping(u))await j.setShardMapping(u,Q),q++;L+=q,X++,F=!0,console.log(`Auto-migrated ${q} records from table ${I}`)}}catch(R){O.push(`Auto-migration failed for table ${I}: ${R}`)}if(F){if(await j.addKnownShard(Q),!w.includes("shard_mappings"))await J.prepare(`CREATE TABLE IF NOT EXISTS shard_mappings (
11
11
  primary_key TEXT PRIMARY KEY,
12
12
  shard_name TEXT NOT NULL,
13
13
  created_at INTEGER NOT NULL,
14
14
  updated_at INTEGER NOT NULL
15
15
  );
16
- `).run()}if(R.set(Y,!0),O)console.log(`Auto-migration completed for shard ${G}: ${_} records from ${L} tables`)}catch(x){$.push(`Auto-migration error: ${x}`)}return{migrationNeeded:U,migrationPerformed:O,recordsMigrated:_,tablesProcessed:L,issues:$}}async function o(z,G,J){let H=`${G}_migration_check`;if(R.has(H))return!1;try{let Q=await P(z);if(Q.includes("shard_mappings"))return R.set(H,!0),!1;let{KVShardMapper:Z}=await Promise.resolve().then(() => C),X=new Z(J.kv),Y=Q.filter(($)=>$!=="shard_mappings"&&!$.startsWith("sqlite_")&&$!=="sqlite_sequence");for(let $ of Y.slice(0,3))try{if(((await z.prepare(`SELECT COUNT(*) as count FROM ${$} LIMIT 1`).first())?.count||0)>0){let U=await z.prepare(`SELECT id FROM ${$} LIMIT 1`).first();if(U){let O=String(U.id);if(!await X.getShardMapping(O))return!0}}}catch{continue}return!1}catch{return!1}}function m(){R.clear()}var R;var T=r(()=>{R=new Map});var K=null;function e(z){if(K=z,z.shards&&Object.keys(z.shards).length>0)z1(z).catch((G)=>{console.warn("Background auto-migration failed:",G)})}async function z1(z){try{let{autoDetectAndMigrate:G}=await Promise.resolve().then(() => (T(),B)),J=Object.keys(z.shards);console.log(`\uD83D\uDD0D Checking ${J.length} shards for existing data...`);let H=J.map(async(Z)=>{let X=z.shards[Z];if(!X)return null;try{let Y=await G(X,Z,z,{maxRecordsToCheck:1000});return{shardName:Z,...Y}}catch(Y){return console.warn(`Auto-migration failed for shard ${Z}:`,Y),null}}),W=(await Promise.all(H)).filter((Z)=>Z?.migrationPerformed);if(W.length>0){let Z=W.reduce((X,Y)=>X+(Y?.recordsMigrated||0),0);console.log(`\uD83C\uDF89 Auto-migration completed! Migrated ${Z} records across ${W.length} shards`),W.forEach((X)=>{if(X)console.log(` ✅ ${X.shardName}: ${X.recordsMigrated} records from ${X.tablesProcessed} tables`)})}else console.log("✅ All shards ready - no migration needed")}catch(G){console.warn("Background auto-migration setup failed:",G)}}function V(){if(!K)throw new Error("CollegeDB not initialized. Call initialize() first.");return K}async function G1(z){let G=V(),J=new D(G.kv),H=await J.getShardMapping(z);if(H)return H.shard;let Q=Object.keys(G.shards);if(Q.length===0)throw new Error("No shards configured");for(let Z of Q){let X=G.shards[Z];if(!X)continue;try{let{autoDetectAndMigrate:Y}=await Promise.resolve().then(() => (T(),B));if((await Y(X,Z,G,{maxRecordsToCheck:100})).migrationPerformed){let _=await J.getShardMapping(z);if(_)return _.shard}}catch(Y){console.warn(`Auto-migration check failed for shard ${Z}:`,Y)}}let W;if(G.coordinator)try{let Z=G.coordinator.idFromName("default"),Y=await G.coordinator.get(Z).fetch("http://coordinator/allocate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({primaryKey:z,strategy:G.strategy||"round-robin"})});if(Y.ok)W=(await Y.json()).shard;else W=Q[Math.floor(Math.random()*Q.length)]}catch(Z){console.warn("Coordinator allocation failed, falling back to random:",Z),W=Q[Math.floor(Math.random()*Q.length)]}else switch(G.strategy||"round-robin"){case"hash":let X=0;for(let $=0;$<z.length;$++){let _=z.charCodeAt($);X=(X<<5)-X+_,X=X&X}let Y=Math.abs(X)%Q.length;W=Q[Y];break;case"random":W=Q[Math.floor(Math.random()*Q.length)];break;default:W=Q[0];break}return await J.setShardMapping(z,W),W}async function H1(z){let G=V(),J=await G1(z),H=G.shards[J];if(!H)throw new Error(`Shard ${J} not found in configuration`);return H}async function J1(z,G){let{createSchema:J}=await Promise.resolve().then(() => (T(),B));await J(z,G)}async function v(z,G){return(await H1(z)).prepare(G)}async function Q1(z,G,J=[]){let Q=await(await v(z,G)).bind(...J).run();if(!Q.success)throw new Error(`Query failed: ${Q.error||"Unknown error"}`);return Q}async function W1(z,G,J=[]){let Q=await(await v(z,G)).bind(...J).all();if(!Q.success)throw new Error(`Query failed: ${Q.error||"Unknown error"}`);return Q}async function X1(z,G,J=[]){return await(await v(z,G)).bind(...J).first()}async function Y1(z,G,J){let H=V();if(!H.shards[G])throw new Error(`Shard ${G} not found in configuration`);let Q=new D(H.kv),W=await Q.getShardMapping(z);if(!W)throw new Error(`No existing mapping found for primary key: ${z}`);if(W.shard!==G){let{migrateRecord:Z}=await Promise.resolve().then(() => (T(),B)),X=H.shards[W.shard],Y=H.shards[G];if(!X||!Y)throw new Error("Source or target shard not available");await Z(X,Y,z,J)}await Q.updateShardMapping(z,G)}async function Z1(){let z=V();if(z.coordinator)try{let G=z.coordinator.idFromName("default"),H=await z.coordinator.get(G).fetch("http://coordinator/shards");if(H.ok)return await H.json()}catch(G){console.warn("Failed to get shards from coordinator:",G)}return Object.keys(z.shards)}async function $1(){let z=V();if(z.coordinator)try{let H=z.coordinator.idFromName("default"),W=await z.coordinator.get(H).fetch("http://coordinator/stats");if(W.ok)return await W.json()}catch(H){console.warn("Failed to get stats from coordinator:",H)}let J=await new D(z.kv).getShardKeyCounts();return Object.entries(z.shards).map(([H,Q])=>({binding:H,count:J[H]||0}))}async function _1(z,G,J=[]){let Q=V().shards[z];if(!Q)throw new Error(`Shard ${z} not found`);return await Q.prepare(G).bind(...J).all()}async function E1(){let z=V();if(await new D(z.kv).clearAllMappings(),z.coordinator)try{let J=z.coordinator.idFromName("default");await z.coordinator.get(J).fetch("http://coordinator/flush",{method:"POST"})}catch(J){console.warn("Failed to flush coordinator:",J)}}class n{state;constructor(z){this.state=z}async getState(){return await this.state.storage.get("coordinator_state")||{knownShards:[],shardStats:{},strategy:"round-robin",roundRobinIndex:0}}async saveState(z){await this.state.storage.put("coordinator_state",z)}async fetch(z){let J=new URL(z.url).pathname,H=z.method;try{switch(`${H} ${J}`){case"GET /shards":return this.handleListShards();case"POST /shards":return this.handleAddShard(z);case"DELETE /shards":return this.handleRemoveShard(z);case"GET /stats":return this.handleGetStats();case"POST /stats":return this.handleUpdateStats(z);case"POST /allocate":return this.handleAllocateShard(z);case"POST /flush":return this.handleFlush();case"GET /health":return new Response("OK",{status:200});default:return new Response("Not Found",{status:404})}}catch(Q){return console.error("ShardCoordinator error:",Q),new Response("Internal Server Error",{status:500})}}async handleListShards(){let z=await this.getState();return new Response(JSON.stringify(z.knownShards),{headers:{"Content-Type":"application/json"}})}async handleAddShard(z){let{shard:G}=await z.json(),J=await this.getState();if(!J.knownShards.includes(G))J.knownShards.push(G),J.shardStats[G]={binding:G,count:0,lastUpdated:Date.now()},await this.saveState(J);return new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}async handleRemoveShard(z){let{shard:G}=await z.json(),J=await this.getState(),H=J.knownShards.indexOf(G);if(H>-1){if(J.knownShards.splice(H,1),delete J.shardStats[G],J.roundRobinIndex>=J.knownShards.length)J.roundRobinIndex=0;await this.saveState(J)}return new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}async handleGetStats(){let z=await this.getState(),G=Object.values(z.shardStats);return new Response(JSON.stringify(G),{headers:{"Content-Type":"application/json"}})}async handleUpdateStats(z){let{shard:G,count:J}=await z.json(),H=await this.getState();if(H.shardStats[G])H.shardStats[G].count=J,H.shardStats[G].lastUpdated=Date.now(),await this.saveState(H);return new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}async handleAllocateShard(z){let{primaryKey:G,strategy:J}=await z.json(),H=await this.getState();if(H.knownShards.length===0)return new Response(JSON.stringify({error:"No shards available"}),{status:400,headers:{"Content-Type":"application/json"}});let Q=this.selectShard(G,H,J||H.strategy);if((J||H.strategy)==="round-robin")H.roundRobinIndex=(H.roundRobinIndex+1)%H.knownShards.length,await this.saveState(H);return new Response(JSON.stringify({shard:Q}),{headers:{"Content-Type":"application/json"}})}async handleFlush(){return await this.state.storage.deleteAll(),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}selectShard(z,G,J){let H=G.knownShards;if(H.length===0)throw new Error("No shards available");switch(J){case"round-robin":return H[G.roundRobinIndex]??H[0];case"random":return H[Math.floor(Math.random()*H.length)];case"hash":let Q=0;for(let Z=0;Z<z.length;Z++){let X=z.charCodeAt(Z);Q=(Q<<5)-Q+X,Q=Q&Q}let W=Math.abs(Q)%H.length;return H[W];default:return H[0]}}async incrementShardCount(z){let G=await this.getState();if(G.shardStats[z])G.shardStats[z].count++,G.shardStats[z].lastUpdated=Date.now(),await this.saveState(G)}async decrementShardCount(z){let G=await this.getState();if(G.shardStats[z]&&G.shardStats[z].count>0)G.shardStats[z].count--,G.shardStats[z].lastUpdated=Date.now(),await this.saveState(G)}}T();export{q as validateTableForSharding,f as schemaExists,Q1 as run,Y1 as reassignShard,v as prepare,y as migrateRecord,P as listTables,Z1 as listKnownShards,h as integrateExistingDatabase,e as initialize,$1 as getShardStats,E1 as flush,X1 as first,g as dropSchema,S as discoverExistingPrimaryKeys,c as createSchemaAcrossShards,J1 as createSchema,p as createMappingsForExistingKeys,m as clearMigrationCache,o as checkMigrationNeeded,l as autoDetectAndMigrate,_1 as allShard,W1 as all,n as ShardCoordinator,D as KVShardMapper};
16
+ `).run()}if(E.set(W,!0),F)console.log(`Auto-migration completed for shard ${Q}: ${L} records from ${X} tables`)}catch(T){O.push(`Auto-migration error: ${T}`)}return{migrationNeeded:x,migrationPerformed:F,recordsMigrated:L,tablesProcessed:X,issues:O}}async function r(J,Q,U){let Z=`${Q}_migration_check`;if(E.has(Z))return!1;try{let $=await P(J);if($.includes("shard_mappings"))return E.set(Z,!0),!1;let{KVShardMapper:Y}=await Promise.resolve().then(() => (v(),g)),V=new Y(U.kv),W=$.filter((O)=>O!=="shard_mappings"&&!O.startsWith("sqlite_")&&O!=="sqlite_sequence");for(let O of W.slice(0,3))try{if(((await J.prepare(`SELECT COUNT(*) as count FROM ${O} LIMIT 1`).first())?.count||0)>0){let x=await J.prepare(`SELECT id FROM ${O} LIMIT 1`).first();if(x){let F=String(x.id);if(!await V.getShardMapping(F))return!0}}}catch{continue}return!1}catch{return!1}}function a(){E.clear()}function e(J){let Q=`${J}_migration_check`;E.delete(Q)}var E;var B=b(()=>{D();E=new Map});D();v();var C=null;function WJ(J){if(C=J,J.shards&&Object.keys(J.shards).length>0&&!J.disableAutoMigration)QJ(J).catch((Q)=>{console.warn("Background auto-migration failed:",Q)})}async function JJ(J){if(C=J,J.shards&&Object.keys(J.shards).length>0&&!J.disableAutoMigration)try{await QJ(J)}catch(Q){console.warn("Auto migration failed:",Q)}}async function YJ(J,Q){return await JJ(J),await Q()}async function QJ(J){try{let{autoDetectAndMigrate:Q}=await Promise.resolve().then(() => (B(),k)),U=Object.keys(J.shards);console.log(`\uD83D\uDD0D Checking ${U.length} shards for existing data...`);let Z=U.map(async(Y)=>{let V=J.shards[Y];if(!V)return null;try{let W=await Q(V,Y,J,{maxRecordsToCheck:1000});return{shardName:Y,...W}}catch(W){return console.warn(`Auto-migration failed for shard ${Y}:`,W),null}}),z=(await Promise.all(Z)).filter((Y)=>Y?.migrationPerformed);if(z.length>0){let Y=z.reduce((V,W)=>V+(W?.recordsMigrated||0),0);console.log(`\uD83C\uDF89 Auto-migration completed! Migrated ${Y} records across ${z.length} shards`),z.forEach((V)=>{if(V)console.log(` ✅ ${V.shardName}: ${V.recordsMigrated} records from ${V.tablesProcessed} tables`)})}else console.log("✅ All shards ready - no migration needed")}catch(Q){console.warn("Background auto-migration setup failed:",Q)}}function LJ(){C=null}function H(){if(!C)throw new G("CollegeDB not initialized. Call initialize() first.","NOT_INITIALIZED");return C}function VJ(J){let Q=J.trim().toUpperCase();if(Q.startsWith("SELECT")||Q.startsWith("VALUES")||Q.startsWith("TABLE")||Q.startsWith("PRAGMA")||Q.startsWith("EXPLAIN")||Q.startsWith("WITH")||Q.startsWith("SHOW"))return"read";return"write"}function OJ(J,Q){let U=J.strategy||"hash";if(typeof U==="string")return U;return U[Q]}function GJ(J,Q){if(J===Q)return 0;let U={wnam:{lat:37.7749,lon:-122.4194},enam:{lat:40.7128,lon:-74.006},weur:{lat:51.5074,lon:-0.1278},eeur:{lat:52.52,lon:13.405},apac:{lat:35.6762,lon:139.6503},oc:{lat:-33.8688,lon:151.2093},me:{lat:25.2048,lon:55.2708},af:{lat:-26.2041,lon:28.0473}},Z=U[J],$=U[Q],z=Z.lat-$.lat,Y=Z.lon-$.lon;return Math.sqrt(z*z+Y*Y)}function XJ(J){let Q=J.cf;if(!Q||!Q.country)return"wnam";let{country:U,continent:Z}=Q;if(["US","CA","MX"].includes(U)){let $=Q.region||Q.regionCode||"",z=Q.timezone||"";if($.includes("CA")||$.includes("WA")||$.includes("OR")||$.includes("NV")||$.includes("AZ")||$.includes("UT")||z.includes("Pacific")||z.includes("America/Los_Angeles"))return"wnam";return"enam"}if(["GL","PM","BM"].includes(U))return"enam";if(["GB","IE","FR","ES","PT","NL","BE","LU","CH","AT","IT"].includes(U))return"weur";if(["DE","PL","CZ","SK","HU","SI","HR","BA","RS","ME","MK","AL","BG","RO","MD","UA","BY","LT","LV","EE","FI","SE","NO","DK","IS"].includes(U))return"eeur";if(U==="RU")return"eeur";if(["JP","KR","CN","HK","TW","MO","MN","KP"].includes(U))return"apac";if(["TH","VN","SG","MY","ID","PH","BN","KH","LA","MM","TL","IN","PK","BD","LK","NP","BT","MV","AF"].includes(U))return"apac";if(["AU","NZ","PG","FJ","NC","VU","SB","WS","TO","KI","NR","PW","FM","MH","TV"].includes(U))return"oc";if(["AE","SA","QA","KW","BH","OM","YE","IQ","IR","SY","LB","JO","IL","PS","TR","CY"].includes(U))return"me";if(Z==="AF"||["EG","LY","TN","DZ","MA","SD","SS","ET","ER","DJ","SO"].includes(U))return"af";if(["KZ","UZ","TM","TJ","KG"].includes(U))return"eeur";if(Z==="SA"||["BR","AR","CL","PE","CO","VE","EC","BO","PY","UY","GY","SR","GF"].includes(U))return"enam";if(["GT","BZ","SV","HN","NI","CR","PA","CU","JM","HT","DO","PR","TT","BB","GD","VC","LC","DM","AG","KN"].includes(U))return"enam";return"wnam"}function xJ(J,Q,U,Z){let $=Q.filter((L)=>U[L]);if($.length===0){let L=0;for(let x=0;x<Z.length;x++){let F=Z.charCodeAt(x);L=(L<<5)-L+F,L=L&L}let X=Math.abs(L)%Q.length;return Q[X]}let z=$.map((L)=>{let X=U[L],x=GJ(J,X.region),F=X.priority||1,T=x-F*0.1;return{shard:L,score:T,distance:x,priority:F}});z.sort((L,X)=>L.score-X.score);let Y=z[0].score,V=z.filter((L)=>Math.abs(L.score-Y)<0.01);if(V.length===1)return V[0].shard;let W=0;for(let L=0;L<Z.length;L++){let X=Z.charCodeAt(L);W=(W<<5)-W+X,W=W&W}let O=Math.abs(W)%V.length;return V[O].shard}async function FJ(J,Q="write"){let U=H(),Z=new A(U.kv),$=await Z.getShardMapping(J);if($)return $.shard;let z=Object.keys(U.shards);if(z.length===0)throw new G("No shards configured","NO_SHARDS");for(let W of z){let O=U.shards[W];if(!O)continue;try{let{autoDetectAndMigrate:L}=await Promise.resolve().then(() => (B(),k));if((await L(O,W,U,{maxRecordsToCheck:100})).migrationPerformed){let x=await Z.getShardMapping(J);if(x)return x.shard}}catch(L){console.warn(`Auto-migration check failed for shard ${W}:`,L)}}let Y,V=OJ(U,Q);if(U.coordinator)try{let W=U.coordinator.idFromName("default"),L=await U.coordinator.get(W).fetch("http://coordinator/allocate",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({primaryKey:J,strategy:V,operationType:Q,targetRegion:U.targetRegion,shardLocations:U.shardLocations})});if(L.ok)Y=(await L.json()).shard;else Y=z[Math.floor(Math.random()*z.length)]}catch(W){console.warn("Coordinator allocation failed, falling back to local strategy:",W),Y=z[Math.floor(Math.random()*z.length)]}else switch(V){case"hash":let W=0;for(let L=0;L<J.length;L++){let X=J.charCodeAt(L);W=(W<<5)-W+X,W=W&W}let O=Math.abs(W)%z.length;Y=z[O]||z[0];break;case"location":if(!U.targetRegion){console.warn("Location strategy requires targetRegion in config, falling back to hash");let L=0;for(let x=0;x<J.length;x++){let F=J.charCodeAt(x);L=(L<<5)-L+F,L=L&L}let X=Math.abs(L)%z.length;Y=z[X]||z[0]}else Y=xJ(U.targetRegion,z,U.shardLocations||{},J);break;case"random":Y=z[Math.floor(Math.random()*z.length)]||z[0];break;default:Y=z[0];break}return await Z.setShardMapping(J,Y),Y}async function jJ(J,Q="write"){let U=H(),Z=await FJ(J,Q),$=U.shards[Z];if(!$)throw new G(`Shard ${Z} not found in configuration`,"SHARD_NOT_FOUND");return $}async function IJ(J,Q){let{createSchema:U}=await Promise.resolve().then(() => (B(),k));await U(J,Q)}async function K(J,Q){let U=VJ(Q);return(await jJ(J,U)).prepare(Q)}async function _J(J,Q,U=[]){let $=await(await K(J,Q)).bind(...U).run();if(!$.success)throw new G(`Query failed: ${$.error||"Unknown error"}`,"QUERY_FAILED");return $}async function HJ(J,Q,U=[]){let $=await(await K(J,Q)).bind(...U).all();if(!$.success)throw new G(`Query failed: ${$.error||"Unknown error"}`,"QUERY_FAILED");return $}async function TJ(J,Q,U=[]){return await(await K(J,Q)).bind(...U).first()}async function AJ(J,Q,U){let Z=H();if(!Z.shards[Q])throw new G(`Shard ${Q} not found in configuration`,"SHARD_NOT_FOUND");let $=new A(Z.kv),z=await $.getShardMapping(J);if(!z)throw new G(`No existing mapping found for primary key: ${J}`,"MAPPING_NOT_FOUND");if(z.shard!==Q){let{migrateRecord:Y}=await Promise.resolve().then(() => (B(),k)),V=Z.shards[z.shard],W=Z.shards[Q];if(!V||!W)throw new G("Source or target shard not available","SHARD_UNAVAILABLE");await Y(V,W,J,U)}await $.updateShardMapping(J,Q)}async function wJ(){let J=H();if(J.coordinator)try{let Q=J.coordinator.idFromName("default"),Z=await J.coordinator.get(Q).fetch("http://coordinator/shards");if(Z.ok)return await Z.json()}catch(Q){console.warn("Failed to get shards from coordinator:",Q)}return Object.keys(J.shards)}async function EJ(){let J=H();if(J.coordinator)try{let Z=J.coordinator.idFromName("default"),z=await J.coordinator.get(Z).fetch("http://coordinator/stats");if(z.ok)return await z.json()}catch(Z){console.warn("Failed to get stats from coordinator:",Z)}let U=await new A(J.kv).getShardKeyCounts();return Object.entries(J.shards).map(([Z,$])=>({binding:Z,count:U[Z]||0}))}async function MJ(J,Q,U=[]){let $=H().shards[J];if(!$)throw new G(`Shard ${J} not found`,"SHARD_NOT_FOUND");let z=await $.prepare(Q).bind(...U).run();if(!z.success)throw new G(`Query failed: ${z.error||"Unknown error"}`,"QUERY_FAILED");return z}async function RJ(J,Q,U=[]){let $=H().shards[J];if(!$)throw new G(`Shard ${J} not found`,"SHARD_NOT_FOUND");return await $.prepare(Q).bind(...U).all()}async function DJ(J,Q,U=[]){let $=H().shards[J];if(!$)throw new G(`Shard ${J} not found`,"SHARD_NOT_FOUND");return await $.prepare(Q).bind(...U).first()}async function PJ(){let J=H();if(await new A(J.kv).clearAllMappings(),J.coordinator)try{let U=J.coordinator.idFromName("default");await J.coordinator.get(U).fetch("http://coordinator/flush",{method:"POST"})}catch(U){console.warn("Failed to flush coordinator:",U)}}D();class y{state;constructor(J){this.state=J}async getState(){return await this.state.storage.get("coordinator_state")||{knownShards:[],shardStats:{},strategy:"round-robin",roundRobinIndex:0}}async saveState(J){await this.state.storage.put("coordinator_state",J)}async fetch(J){let U=new URL(J.url).pathname,Z=J.method;try{switch(`${Z} ${U}`){case"GET /shards":return this.handleListShards();case"POST /shards":return this.handleAddShard(J);case"DELETE /shards":return this.handleRemoveShard(J);case"GET /stats":return this.handleGetStats();case"POST /stats":return this.handleUpdateStats(J);case"POST /allocate":return this.handleAllocateShard(J);case"POST /flush":return this.handleFlush();case"GET /health":return new Response("OK",{status:200});default:return new Response("Not Found",{status:404})}}catch($){return console.error("ShardCoordinator error:",$),new Response("Internal Server Error",{status:500})}}async handleListShards(){let J=await this.getState();return new Response(JSON.stringify(J.knownShards),{headers:{"Content-Type":"application/json"}})}async handleAddShard(J){let{shard:Q}=await J.json();if(!Q||typeof Q!=="string")return new Response(JSON.stringify({error:"Missing or invalid shard parameter"}),{status:400,headers:{"Content-Type":"application/json"}});let U=await this.getState();if(!U.knownShards.includes(Q))U.knownShards.push(Q),U.shardStats[Q]={binding:Q,count:0,lastUpdated:Date.now()},await this.saveState(U);return new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}async handleRemoveShard(J){let{shard:Q}=await J.json();if(!Q||typeof Q!=="string")return new Response(JSON.stringify({error:"Missing or invalid shard parameter"}),{status:400,headers:{"Content-Type":"application/json"}});let U=await this.getState(),Z=U.knownShards.indexOf(Q);if(Z>-1){if(U.knownShards.splice(Z,1),delete U.shardStats[Q],U.roundRobinIndex>=U.knownShards.length)U.roundRobinIndex=0;await this.saveState(U)}return new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}async handleGetStats(){let J=await this.getState(),Q=Object.values(J.shardStats);return new Response(JSON.stringify(Q),{headers:{"Content-Type":"application/json"}})}async handleUpdateStats(J){let{shard:Q,count:U}=await J.json();if(!Q||typeof Q!=="string")return new Response(JSON.stringify({error:"Missing or invalid shard parameter"}),{status:400,headers:{"Content-Type":"application/json"}});if(U===void 0||typeof U!=="number")return new Response(JSON.stringify({error:"Missing or invalid count parameter"}),{status:400,headers:{"Content-Type":"application/json"}});let Z=await this.getState();if(Z.shardStats[Q])Z.shardStats[Q].count=U,Z.shardStats[Q].lastUpdated=Date.now(),await this.saveState(Z);return new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}async handleAllocateShard(J){let{primaryKey:Q,strategy:U,operationType:Z}=await J.json();if(!Q||typeof Q!=="string")return new Response(JSON.stringify({error:"Missing or invalid primaryKey parameter"}),{status:400,headers:{"Content-Type":"application/json"}});let $=await this.getState();if($.knownShards.length===0)return new Response(JSON.stringify({error:"No shards available"}),{status:400,headers:{"Content-Type":"application/json"}});let z=this.resolveStrategy($.strategy,U,Z||"write"),Y=this.selectShard(Q,$,z);if(z==="round-robin")$.roundRobinIndex=($.roundRobinIndex+1)%$.knownShards.length,await this.saveState($);return new Response(JSON.stringify({shard:Y}),{headers:{"Content-Type":"application/json"}})}async handleFlush(){return await this.state.storage.deleteAll(),new Response(JSON.stringify({success:!0}),{headers:{"Content-Type":"application/json"}})}resolveStrategy(J,Q,U="write"){if(Q)return Q;if(typeof J==="string")return J;return J[U]}selectShard(J,Q,U){let Z=Q.knownShards;if(Z.length===0)throw new G("No shards available","NO_SHARDS");switch(U){case"round-robin":return Z[Q.roundRobinIndex]??Z[0];case"random":return Z[Math.floor(Math.random()*Z.length)];case"hash":let $=0;for(let W=0;W<J.length;W++){let O=J.charCodeAt(W);$=($<<5)-$+O,$=$&$}let z=Math.abs($)%Z.length;return Z[z];case"location":let Y=0;for(let W=0;W<J.length;W++){let O=J.charCodeAt(W);Y=(Y<<5)-Y+O,Y=Y&Y}let V=Math.abs(Y)%Z.length;return Z[V];default:return Z[0]}}async incrementShardCount(J){let Q=await this.getState();if(Q.shardStats[J])Q.shardStats[J].count++,Q.shardStats[J].lastUpdated=Date.now(),await this.saveState(Q)}async decrementShardCount(J){let Q=await this.getState();if(Q.shardStats[J]&&Q.shardStats[J].count>0)Q.shardStats[J].count--,Q.shardStats[J].lastUpdated=Date.now(),await this.saveState(Q)}}if(typeof global!=="undefined"){class J{data=new Map;async get(Z){return this.data.get(Z)}async put(Z,$){this.data.set(Z,$)}async delete(Z){return this.data.delete(Z)}async deleteAll(){this.data.clear()}async list(Z){if(!Z?.prefix)return new Map(this.data);let $=new Map;for(let[z,Y]of this.data.entries())if(z.startsWith(Z.prefix))$.set(z,Y);return $}}class Q{storage;constructor(){this.storage=new J}}class U{coordinator;mockState;constructor(){this.mockState=new Q,this.coordinator=new y(this.mockState)}async testShardAllocation(){await this.coordinator.fetch(new Request("http://test/shards",{method:"POST",body:JSON.stringify({shard:"db-east"})})),await this.coordinator.fetch(new Request("http://test/shards",{method:"POST",body:JSON.stringify({shard:"db-west"})}));let $=await(await this.coordinator.fetch(new Request("http://test/allocate",{method:"POST",body:JSON.stringify({primaryKey:"user-1",strategy:"round-robin"})}))).json(),Y=await(await this.coordinator.fetch(new Request("http://test/allocate",{method:"POST",body:JSON.stringify({primaryKey:"user-2",strategy:"round-robin"})}))).json();console.assert($.shard!==Y.shard,"Round-robin should alternate shards");let W=await(await this.coordinator.fetch(new Request("http://test/allocate",{method:"POST",body:JSON.stringify({primaryKey:"consistent-key",strategy:"hash"})}))).json(),L=await(await this.coordinator.fetch(new Request("http://test/allocate",{method:"POST",body:JSON.stringify({primaryKey:"consistent-key",strategy:"hash"})}))).json();console.assert(W.shard===L.shard,"Hash allocation should be consistent"),console.log("✅ Shard allocation tests passed")}async testShardStats(){await this.coordinator.fetch(new Request("http://test/flush",{method:"POST"})),await this.coordinator.fetch(new Request("http://test/shards",{method:"POST",body:JSON.stringify({shard:"db-stats-test"})})),await this.coordinator.fetch(new Request("http://test/stats",{method:"POST",body:JSON.stringify({shard:"db-stats-test",count:42})}));let $=await(await this.coordinator.fetch(new Request("http://test/stats",{method:"GET"}))).json();console.assert($.length===1,"Should have one shard stat"),console.assert($[0]?.binding==="db-stats-test","Should have correct binding name"),console.assert($[0]?.count===42,"Should have correct count"),console.log("✅ Shard stats tests passed")}async testErrorHandling(){await this.coordinator.fetch(new Request("http://test/flush",{method:"POST"}));let Z=await this.coordinator.fetch(new Request("http://test/allocate",{method:"POST",body:JSON.stringify({primaryKey:"test-key"})}));console.assert(Z.status===400,"Should return 400 for no shards available");let $=await this.coordinator.fetch(new Request("http://test/invalid",{method:"GET"}));console.assert($.status===404,"Should return 404 for invalid endpoint"),console.log("✅ Error handling tests passed")}async testCountManagement(){await this.coordinator.fetch(new Request("http://test/shards",{method:"POST",body:JSON.stringify({shard:"db-count-test"})})),await this.coordinator.incrementShardCount("db-count-test"),await this.coordinator.incrementShardCount("db-count-test");let Z=await this.coordinator.fetch(new Request("http://test/stats",{method:"GET"})),$=await Z.json(),z=$.find((V)=>V.binding==="db-count-test");console.assert(z?.count===2,"Count should be 2 after two increments"),await this.coordinator.decrementShardCount("db-count-test"),Z=await this.coordinator.fetch(new Request("http://test/stats",{method:"GET"})),$=await Z.json();let Y=$.find((V)=>V.binding==="db-count-test");console.assert(Y?.count===1,"Count should be 1 after decrement"),console.log("✅ Count management tests passed")}async runAllTests(){console.log("\uD83E\uDDEA Running ShardCoordinator tests...");try{return await this.testShardAllocation(),await this.testShardStats(),await this.testErrorHandling(),await this.testCountManagement(),console.log("\uD83C\uDF89 All ShardCoordinator tests passed!"),!0}catch(Z){return console.error("❌ ShardCoordinator tests failed:",Z),!1}}}globalThis.testShardCoordinator=()=>new U}D();v();B();export{N as validateTableForSharding,c as schemaExists,MJ as runShard,_J as run,LJ as resetConfig,AJ as reassignShard,K as prepare,o as migrateRecord,P as listTables,wJ as listKnownShards,t as integrateExistingDatabase,JJ as initializeAsync,WJ as initialize,EJ as getShardStats,XJ as getClosestRegionFromIP,PJ as flush,DJ as firstShard,TJ as first,n as dropSchema,S as discoverExistingPrimaryKeys,d as createSchemaAcrossShards,IJ as createSchema,i as createMappingsForExistingKeys,YJ as collegedb,e as clearShardMigrationCache,a as clearMigrationCache,r as checkMigrationNeeded,s as autoDetectAndMigrate,RJ as allShard,HJ as all,y as ShardCoordinator,A as KVShardMapper,G as CollegeDBError};
17
17
 
18
- //# debugId=2553736B5DD34DE064756E2164756E21
18
+ //# debugId=757741E0B0241C8464756E2164756E21
19
19
  //# sourceMappingURL=index.js.map