@earth-app/collegedb 1.0.1

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.
@@ -0,0 +1,509 @@
1
+ /**
2
+ * @fileoverview Main routing and query distribution logic for CollegeDB
3
+ *
4
+ * This module provides the core functionality for routing database queries to the
5
+ * appropriate D1 shard based on primary key mappings. It handles shard selection,
6
+ * database routing, and provides a unified API for CRUD operations across multiple
7
+ * distributed D1 databases.
8
+ *
9
+ * Key responsibilities:
10
+ * - Initialize and manage the global CollegeDB configuration
11
+ * - Route queries to appropriate shards based on primary key mappings
12
+ * - Implement shard allocation strategies (round-robin, random, hash-based)
13
+ * - Provide unified CRUD operations across distributed shards
14
+ * - Coordinate with Durable Objects for centralized shard management
15
+ * - Handle shard rebalancing and data migration
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { initialize, insert, first, run } from 'collegedb';
20
+ *
21
+ * // Initialize the system
22
+ * initialize({
23
+ * kv: env.KV,
24
+ * coordinator: env.ShardCoordinator,
25
+ * shards: {
26
+ * 'db-east': env.DB_EAST,
27
+ * 'db-west': env.DB_WEST
28
+ * },
29
+ * strategy: 'hash'
30
+ * });
31
+ *
32
+ * // Insert a record (automatically routed to appropriate shard)
33
+ * await run('user-123', 'INSERT INTO users (id, name) VALUES (?, ?)', ['user-123', 'John']);
34
+ *
35
+ * // Query the record (routed to same shard)
36
+ * const result = await first('user-123', 'SELECT * FROM users WHERE id = ?', ['user-123']);
37
+ * ```
38
+ *
39
+ * @author CollegeDB Team
40
+ * @since 1.0.0
41
+ */
42
+ import type { D1Database, D1PreparedStatement, D1Result } from '@cloudflare/workers-types';
43
+ import type { CollegeDBConfig, ShardStats } from './types.js';
44
+ /**
45
+ * Sets up the global configuration for the CollegeDB system. This must be called
46
+ * before any other operations can be performed. The configuration includes KV
47
+ * storage, available D1 shards, optional coordinator, and allocation strategy.
48
+ *
49
+ * This will also automatically detect and migrate existing databases without requiring
50
+ * additional setup. If shards contain existing data with primary keys, CollegeDB
51
+ * will automatically create the necessary mappings for seamless operation.
52
+ *
53
+ * @param config - Configuration object containing all necessary bindings and settings
54
+ * @throws {Error} If configuration is invalid or required bindings are missing
55
+ * @example
56
+ * ```typescript
57
+ * // Basic setup with multiple shards - auto-migration happens automatically
58
+ * initialize({
59
+ * kv: env.KV,
60
+ * shards: {
61
+ * 'db-primary': env.DB_PRIMARY, // Existing DB with data
62
+ * 'db-secondary': env.DB_SECONDARY // Another existing DB
63
+ * },
64
+ * strategy: 'round-robin'
65
+ * });
66
+ * // Existing data is now automatically accessible via CollegeDB!
67
+ *
68
+ * // Advanced setup with coordinator
69
+ * initialize({
70
+ * kv: env.KV,
71
+ * coordinator: env.ShardCoordinator,
72
+ * shards: {
73
+ * 'db-east': env.DB_EAST,
74
+ * 'db-west': env.DB_WEST,
75
+ * 'db-central': env.DB_CENTRAL
76
+ * },
77
+ * strategy: 'hash'
78
+ * });
79
+ * ```
80
+ */
81
+ export declare function initialize(config: CollegeDBConfig): void;
82
+ /**
83
+ * Sets up the global configuration for the CollegeDB system asynchronously.
84
+ * This must be called before any other operations can be performed. The
85
+ * configuration includes KVstorage, available D1 shards, optional coordinator,
86
+ * and allocation strategy.
87
+ *
88
+ * This will also automatically detect and migrate existing databases without requiring
89
+ * additional setup. If shards contain existing data with primary keys, CollegeDB
90
+ * will automatically create the necessary mappings for seamless operation.
91
+ *
92
+ * Compared to `initialize`, this method waits for the background check to finish.
93
+ *
94
+ * @param config - Configuration object containing all necessary bindings and settings
95
+ * @throws {Error} If configuration is invalid or required bindings are missing
96
+ * @example
97
+ * ```typescript
98
+ * // Basic setup with multiple shards - auto-migration happens automatically
99
+ * initializeAsync({
100
+ * kv: env.KV,
101
+ * shards: {
102
+ * 'db-primary': env.DB_PRIMARY, // Existing DB with data
103
+ * 'db-secondary': env.DB_SECONDARY // Another existing DB
104
+ * },
105
+ * strategy: 'round-robin'
106
+ * });
107
+ * // Existing data is now automatically accessible via CollegeDB!
108
+ *
109
+ * // Advanced setup with coordinator
110
+ * initializeAsync({
111
+ * kv: env.KV,
112
+ * coordinator: env.ShardCoordinator,
113
+ * shards: {
114
+ * 'db-east': env.DB_EAST,
115
+ * 'db-west': env.DB_WEST,
116
+ * 'db-central': env.DB_CENTRAL
117
+ * },
118
+ * strategy: 'hash'
119
+ * });
120
+ * ```
121
+ */
122
+ export declare function initializeAsync(config: CollegeDBConfig): Promise<void>;
123
+ /**
124
+ * Initializes the configuration and then performs a callback once the configuration
125
+ * has finished initializing.
126
+ *
127
+ * @param config - CollegeDB Configuration
128
+ * @param callback - The callback to perform after the initialization
129
+ * @returns The result of the callback
130
+ * @example
131
+ * ```
132
+ * import { collegedb, first } from 'collegedb'
133
+ *
134
+ * const result = collegedb({
135
+ * kv: env.KV,
136
+ * shards: {
137
+ * 'db-primary': env.DB_PRIMARY, // Existing DB with data
138
+ * 'db-secondary': env.DB_SECONDARY // Another existing DB
139
+ * },
140
+ * strategy: 'hash'
141
+ * }, async () => {
142
+ * return await first('user-123', 'SELECT * FROM users WHERE id = ?', ['user-123']);
143
+ * });
144
+ * ```
145
+ */
146
+ export declare function collegedb<T>(config: CollegeDBConfig, callback: () => T): Promise<T>;
147
+ /**
148
+ * Creates the database schema in the specified D1 database
149
+ *
150
+ * @param d1 - The D1 database instance to create schema in
151
+ * @param schema - The SQL schema definition to execute
152
+ * @returns Promise that resolves when schema creation is complete
153
+ * @throws {Error} If schema creation fails
154
+ * @example
155
+ * ```typescript
156
+ * const userSchema = `
157
+ * CREATE TABLE users (
158
+ * id TEXT PRIMARY KEY,
159
+ * name TEXT NOT NULL,
160
+ * email TEXT UNIQUE
161
+ * );
162
+ * `;
163
+ * await createSchema(env.DB_NEW_SHARD, userSchema);
164
+ * ```
165
+ */
166
+ export declare function createSchema(d1: D1Database, schema: string): Promise<void>;
167
+ /**
168
+ * Prepares a SQL statement for execution.
169
+ *
170
+ * @param key - The primary key to route the query
171
+ * @param sql - The SQL statement to prepare
172
+ * @returns Promise that resolves to a prepared statement
173
+ * @throws {Error} If preparation fails
174
+ */
175
+ export declare function prepare(key: string, sql: string): Promise<D1PreparedStatement>;
176
+ /**
177
+ * Executes a statement on the appropriate shard based on the primary key.
178
+ * The primary key is used to determine which shard should store the record,
179
+ * ensuring consistent routing for future queries.
180
+ *
181
+ * @template T - Type of the result records
182
+ * @param key - Primary key to route the query (should match the record's primary key)
183
+ * @param sql - SQL statement with parameter placeholders
184
+ * @param bindings - Parameter values to bind to the SQL statement
185
+ * @returns Promise that resolves when the statement is complete
186
+ * @throws {Error} If statement fails or routing fails
187
+ * @example
188
+ * ```typescript
189
+ * // Insert a new user
190
+ * await run('user-123',
191
+ * 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)',
192
+ * ['user-123', 'John Doe', 'john@example.com']
193
+ * );
194
+ *
195
+ * // Insert a post linked to a user
196
+ * await run('post-456',
197
+ * 'INSERT INTO posts (id, user_id, title, content) VALUES (?, ?, ?, ?)',
198
+ * ['post-456', 'user-123', 'Hello World', 'My first post!']
199
+ * );
200
+ * ```
201
+ *
202
+ * @example
203
+ * ```typescript
204
+ * // Update user information
205
+ * await run('user-123',
206
+ * 'UPDATE users SET name = ?, email = ? WHERE id = ?',
207
+ * ['John Smith', 'johnsmith@example.com', 'user-123']
208
+ * );
209
+ *
210
+ * // Update post content
211
+ * await run('post-456',
212
+ * 'UPDATE posts SET title = ?, content = ?, updated_at = strftime("%s", "now") WHERE id = ?',
213
+ * ['Updated Title', 'Updated content here', 'post-456']
214
+ * );
215
+ * ```
216
+ *
217
+ * @example
218
+ * ```typescript
219
+ * // Delete a specific user
220
+ * await run('user-123',
221
+ * 'DELETE FROM users WHERE id = ?',
222
+ * ['user-123']
223
+ * );
224
+ *
225
+ * // Delete user's posts (cascade delete)
226
+ * await run('user-123',
227
+ * 'DELETE FROM posts WHERE user_id = ?',
228
+ * ['user-123']
229
+ * );
230
+ *
231
+ * // Delete with conditions
232
+ * await run('user-123',
233
+ * 'DELETE FROM posts WHERE user_id = ? AND created_at < ?',
234
+ * ['user-123', Date.now() - 86400000] // Posts older than 1 day
235
+ * );
236
+ * ```
237
+ */
238
+ export declare function run<T = Record<string, unknown>>(key: string, sql: string, bindings?: any[]): Promise<D1Result<T>>;
239
+ /**
240
+ * Retrieves all records matching the query for a given primary key.
241
+ *
242
+ * This function is useful for fetching multiple records based on a primary key.
243
+ * It automatically routes the query to the correct shard based on the provided
244
+ * primary key, ensuring consistent data access.
245
+ * @param key - Primary key to route the query
246
+ * @param sql - The SQL statement to execute
247
+ * @param bindings - Parameter values to bind to the SQL statement
248
+ * @returns Promise that resolves to the result of the update operation
249
+ * @throws {Error} If update fails or routing fails
250
+ *
251
+ * @example
252
+ * ```typescript
253
+ * type Post = {
254
+ * id: string;
255
+ * user_id: string;
256
+ * title: string;
257
+ * content: string;
258
+ * };
259
+ *
260
+ *
261
+ * // Get user's posts
262
+ * const postsResult = await all<Post>('user-123',
263
+ * 'SELECT * FROM posts WHERE user_id = ? ORDER BY created_at DESC',
264
+ * ['user-123']
265
+ * );
266
+ *
267
+ * console.log(`User has ${postsResult.meta.count} posts`);
268
+ * ```
269
+ */
270
+ export declare function all<T = Record<string, unknown>>(key: string, sql: string, bindings?: any[]): Promise<D1Result<T>>;
271
+ /**
272
+ * Retrieves the first record matching the query for a given primary key.
273
+ *
274
+ * This function is useful for fetching a single record based on a primary key.
275
+ * It automatically routes the query to the correct shard based on the provided
276
+ * primary key, ensuring consistent data access.
277
+ *
278
+ * @template T - Type of the result record
279
+ * @param key - Primary key to route the query
280
+ * @param sql - SQL statement with parameter placeholders
281
+ * @param bindings - Parameter values to bind to the SQL statement
282
+ * @returns Promise that resolves to the first matching record, or null if not found
283
+ * @throws {Error} If query fails or routing fails
284
+ *
285
+ * @example
286
+ * ```typescript
287
+ * type User = {
288
+ * id: string;
289
+ * name: string;
290
+ * email: string;
291
+ * };
292
+ * // Get a specific user
293
+ * const userResult = await first<User>('user-123',
294
+ * 'SELECT * FROM users WHERE id = ?',
295
+ * ['user-123']
296
+ * );
297
+ *
298
+ * if (userResult) {
299
+ * console.log(`Found user: ${userResult.name}`);
300
+ * }
301
+ */
302
+ export declare function first<T = Record<string, unknown>>(key: string, sql: string, bindings?: any[]): Promise<T | null>;
303
+ /**
304
+ * Reassigns a primary key to a different shard
305
+ *
306
+ * Moves a primary key and its associated data from one shard to another. This
307
+ * operation is useful for load balancing, shard maintenance, or geographic
308
+ * redistribution of data.
309
+ *
310
+ * The reassignment process:
311
+ * 1. Validates the target shard exists in configuration
312
+ * 2. Checks that a mapping exists for the primary key
313
+ * 3. If target shard differs from current, migrates the data
314
+ * 4. Updates the KV mapping to point to the new shard
315
+ *
316
+ * **Note**: This operation involves data migration and should be used
317
+ * carefully in production environments. Consider the impact on ongoing queries.
318
+ *
319
+ * @param primaryKey - Primary key to reassign to a different shard
320
+ * @param newBinding - New shard binding name where the data should be moved
321
+ * @param tableName - Name of the table containing the record to migrate
322
+ * @returns Promise that resolves when reassignment and migration are complete
323
+ * @throws {Error} If target shard not found, mapping doesn't exist, or migration fails
324
+ * @example
325
+ * ```typescript
326
+ * // Move a user from east to west coast for better latency
327
+ * try {
328
+ * await reassignShard('user-california-123', 'db-west', 'users');
329
+ * console.log('User successfully moved to west coast shard');
330
+ * } catch (error) {
331
+ * console.error('Reassignment failed:', error.message);
332
+ * }
333
+ *
334
+ * // Load balancing: move high-activity user to dedicated shard
335
+ * await reassignShard('user-enterprise-456', 'db-dedicated', 'users');
336
+ * ```
337
+ */
338
+ export declare function reassignShard(primaryKey: string, newBinding: string, tableName: string): Promise<void>;
339
+ /**
340
+ * Lists all known shards
341
+ *
342
+ * Returns an array of all shard binding names known to the system. First
343
+ * attempts to get the list from the Durable Object coordinator for the most
344
+ * up-to-date information, then falls back to the configured shards if the
345
+ * coordinator is unavailable.
346
+ *
347
+ * @returns Promise resolving to array of shard binding names
348
+ * @example
349
+ * ```typescript
350
+ * const shards = await listKnownShards();
351
+ * console.log('Available shards:', shards);
352
+ * // Output: ['db-east', 'db-west', 'db-central']
353
+ *
354
+ * // Check if a specific shard is available
355
+ * if (shards.includes('db-asia')) {
356
+ * console.log('Asia region shard is available');
357
+ * }
358
+ * ```
359
+ */
360
+ export declare function listKnownShards(): Promise<string[]>;
361
+ /**
362
+ * Gets statistics for all shards
363
+ *
364
+ * Returns usage statistics for all known shards, including key counts and
365
+ * last updated timestamps. First attempts to get real-time statistics from
366
+ * the Durable Object coordinator, then falls back to KV-based counting.
367
+ *
368
+ * This information is useful for:
369
+ * - Load balancing decisions
370
+ * - Monitoring shard utilization
371
+ * - Capacity planning
372
+ * - Performance analysis
373
+ *
374
+ * @returns Promise resolving to array of shard statistics
375
+ * @example
376
+ * ```typescript
377
+ * const stats = await getShardStats();
378
+ * stats.forEach(shard => {
379
+ * console.log(`${shard.binding}: ${shard.count} keys`);
380
+ * if (shard.lastUpdated) {
381
+ * console.log(` Last updated: ${new Date(shard.lastUpdated)}`);
382
+ * }
383
+ * });
384
+ *
385
+ * // Find most loaded shard
386
+ * const mostLoaded = stats.reduce((prev, current) =>
387
+ * (prev.count > current.count) ? prev : current
388
+ * );
389
+ * console.log(`Most loaded shard: ${mostLoaded.binding} (${mostLoaded.count} keys)`);
390
+ * ```
391
+ */
392
+ export declare function getShardStats(): Promise<ShardStats[]>;
393
+ /**
394
+ * Bypasses the normal routing logic to execute a query directly on a specified
395
+ * shard. This is useful for administrative operations, cross-shard queries,
396
+ * or when you need to query data that doesn't follow the primary key routing pattern.
397
+ *
398
+ * **Use with caution**: This function bypasses routing safeguards and should
399
+ * be used only when you specifically need to target a particular shard.
400
+ *
401
+ * @param shardBinding - The shard binding name to execute the query on
402
+ * @param sql - SQL statement to execute
403
+ * @param bindings - Parameter values to bind to the SQL statement
404
+ * @returns Promise resolving to the result of the query execution
405
+ * @throws {Error} If shard not found or query fails
406
+ * @example
407
+ * ```typescript
408
+ * // Administrative query: insert a new user directly into a specific shard
409
+ * const result = await runShard('db-east',
410
+ * 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)',
411
+ * ['user-789', 'Alice', 'alice@example.com']
412
+ * );
413
+ * console.log(`Inserted user with ID: ${result.lastInsertId}`);
414
+ * ```
415
+ */
416
+ export declare function runShard<T = Record<string, unknown>>(shardBinding: string, sql: string, bindings?: any[]): Promise<D1Result<T>>;
417
+ /**
418
+ * Bypasses the normal routing logic to execute a query directly on a specified
419
+ * shard. This is useful for administrative operations, cross-shard queries,
420
+ * or when you need to query data that doesn't follow the primary key routing pattern.
421
+ *
422
+ * **Use with caution**: This function bypasses routing safeguards and should
423
+ * be used only when you specifically need to target a particular shard.
424
+ *
425
+ * @param shardBinding - The shard binding name to execute the query on
426
+ * @param sql - SQL statement to execute
427
+ * @param bindings - Parameter values to bind to the SQL statement
428
+ * @returns Promise resolving to structured query results
429
+ * @throws {Error} If shard not found or query fails
430
+ * @example
431
+ * ```typescript
432
+ * // Administrative query: count all users across a specific shard
433
+ * const eastCoastStats = await allShard('db-east',
434
+ * 'SELECT COUNT(*) as user_count FROM users'
435
+ * );
436
+ * console.log(`East coast users: ${eastCoastStats.results[0].user_count}`);
437
+ *
438
+ * // Cross-shard analytics: get recent posts from a specific region
439
+ * const recentPosts = await allShard('db-west',
440
+ * 'SELECT id, title, created_at FROM posts WHERE created_at > ? ORDER BY created_at DESC LIMIT ?',
441
+ * [Date.now() - 86400000, 10] // Last 24 hours, limit 10
442
+ * );
443
+ *
444
+ * // Schema inspection on specific shard
445
+ * const tables = await allShard('db-central',
446
+ * "SELECT name FROM sqlite_master WHERE type='table'"
447
+ * );
448
+ * ```
449
+ */
450
+ export declare function allShard<T = Record<string, unknown>>(shardBinding: string, sql: string, bindings?: any[]): Promise<D1Result<T>>;
451
+ /**
452
+ * Bypasses the normal routing logic to execute a query directly on a specified
453
+ * shard. This is useful for administrative operations, cross-shard queries,
454
+ * or when you need to query data that doesn't follow the primary key routing pattern.
455
+ *
456
+ * **Use with caution**: This function bypasses routing safeguards and should
457
+ * be used only when you specifically need to target a particular shard.
458
+ *
459
+ * @param shardBinding - The shard binding name to execute the query on
460
+ * @param sql - SQL statement to execute
461
+ * @param bindings - Parameter values to bind to the SQL statement
462
+ * @returns Promise resolving to the first matching record, or null if not found
463
+ * @throws {Error} If shard not found or query fails
464
+ * @example
465
+ * ```typescript
466
+ * // Administrative query: get a specific user from a shard
467
+ * const user = await firstShard('db-east',
468
+ * 'SELECT * FROM users WHERE id = ?',
469
+ * ['user-123']);
470
+ * if (user) {
471
+ * console.log(`Found user: ${user.name}`);
472
+ * } else {
473
+ * console.log('User not found in east shard');
474
+ * }
475
+ * ```
476
+ */
477
+ export declare function firstShard<T = Record<string, unknown>>(shardBinding: string, sql: string, bindings?: any[]): Promise<T | null>;
478
+ /**
479
+ * Flushes all shard mappings (development only)
480
+ *
481
+ * Completely clears all primary key to shard mappings from both KV storage
482
+ * and the Durable Object coordinator. This operation resets the entire
483
+ * routing system to a clean state.
484
+ *
485
+ * **DANGER**: This operation is destructive and irreversible. After flushing,
486
+ * all existing primary keys will be treated as new and may be assigned to
487
+ * different shards than before, causing data routing issues.
488
+ *
489
+ * **Use only for**:
490
+ * - Development and testing environments
491
+ * - Complete system resets
492
+ * - Emergency recovery scenarios
493
+ *
494
+ * @returns Promise that resolves when all mappings are cleared
495
+ * @example
496
+ * ```typescript
497
+ * // Only use in development!
498
+ * if (process.env.NODE_ENV === 'development') {
499
+ * await flush();
500
+ * console.log('All shard mappings cleared for testing');
501
+ *
502
+ * // Now all keys will be reassigned on next access
503
+ * await run('user-123', 'INSERT INTO users (id, name) VALUES (?, ?)',
504
+ * ['user-123', 'Test User']);
505
+ * }
506
+ * ```
507
+ */
508
+ export declare function flush(): Promise<void>;
509
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAE3F,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAa9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,QAQjD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,eAAe,iBAS5D;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,CAAC,cAG5E;AAkOD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhF;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAIpF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,wBAAsB,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,GAAG,EAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAS3H;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAsB,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,GAAG,EAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAS3H;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAsB,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,GAAG,EAAO,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAI1H;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6B5G;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAoBzD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CA0B3D;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,GAAG,EAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAkBzI;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,GAAG,EAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAczI;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,UAAU,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,GAAG,EAAO,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAcxI;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAiB3C"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * @fileoverview TypeScript type definitions for CollegeDB
3
+ *
4
+ * This module contains all the TypeScript interfaces and types used throughout
5
+ * the CollegeDB library. These types provide compile-time safety and enable
6
+ * better developer experience with IDE autocompletion and error checking.
7
+ *
8
+ * The types are organized into several categories:
9
+ * - Environment and configuration types
10
+ * - Query result and metadata types
11
+ * - Shard management and statistics types
12
+ * - Strategy and coordination types
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import type { CollegeDBConfig, QueryResult, ShardStats } from './types.js';
17
+ *
18
+ * const config: CollegeDBConfig = {
19
+ * kv: env.KV,
20
+ * shards: { 'db-east': env.DB_EAST },
21
+ * strategy: 'hash'
22
+ * };
23
+ * ```
24
+ *
25
+ * @author Gregory Mitchell
26
+ * @since 1.0.0
27
+ */
28
+ import type { D1Database, DurableObjectNamespace, KVNamespace } from '@cloudflare/workers-types';
29
+ /**
30
+ * Sharding strategy options for CollegeDB
31
+ * - `round-robin`: Distributes keys evenly across available shards.
32
+ * - `random`: Selects a random shard for each key.
33
+ * - `hash`: Uses a hash function to determine the shard based on the primary key.
34
+ */
35
+ export type ShardingStrategy = 'round-robin' | 'random' | 'hash';
36
+ /**
37
+ * Environment bindings for the Cloudflare Worker
38
+ */
39
+ export interface Env {
40
+ /** Cloudflare KV namespace for storing primary key to shard mappings */
41
+ KV: KVNamespace;
42
+ /** Durable Object binding for shard coordination */
43
+ ShardCoordinator: DurableObjectNamespace;
44
+ /** D1 database bindings - dynamic based on wrangler.toml */
45
+ [key: string]: any;
46
+ }
47
+ /**
48
+ * Configuration for the collegedb sharded database
49
+ */
50
+ export interface CollegeDBConfig {
51
+ /** KV namespace for storing mappings */
52
+ kv: KVNamespace;
53
+ /** Shard coordinator Durable Object */
54
+ coordinator?: DurableObjectNamespace;
55
+ /** Available D1 database bindings */
56
+ shards: Record<string, D1Database>;
57
+ /** Default shard allocation strategy */
58
+ strategy?: ShardingStrategy;
59
+ }
60
+ /**
61
+ * Shard statistics for monitoring and load balancing
62
+ */
63
+ export interface ShardStats {
64
+ /** D1 binding name */
65
+ binding: string;
66
+ /** Number of primary keys assigned to this shard */
67
+ count: number;
68
+ /** Last updated timestamp */
69
+ lastUpdated?: number;
70
+ }
71
+ /**
72
+ * Shard allocation strategy interface
73
+ */
74
+ export interface ShardStrategy {
75
+ /** Select a shard for a new primary key */
76
+ selectShard(primaryKey: string, availableShards: string[]): string;
77
+ }
78
+ /**
79
+ * Primary key to shard mapping stored in KV
80
+ */
81
+ export interface ShardMapping {
82
+ /** D1 binding name */
83
+ shard: string;
84
+ /** Timestamp when mapping was created */
85
+ createdAt: number;
86
+ /** Timestamp when mapping was last updated */
87
+ updatedAt: number;
88
+ }
89
+ /**
90
+ * Durable Object state for shard coordination
91
+ */
92
+ export interface ShardCoordinatorState {
93
+ /** List of known D1 bindings */
94
+ knownShards: string[];
95
+ /** Statistics for each shard */
96
+ shardStats: Record<string, ShardStats>;
97
+ /**
98
+ * Current allocation strategy
99
+ * `round-robin` - distributes keys evenly across shards
100
+ * `random` - selects a random shard for each key
101
+ * `hash` - uses a hash function to determine shard based on primary key (default)
102
+ */
103
+ strategy: ShardingStrategy;
104
+ /** Round-robin counter for allocation */
105
+ roundRobinIndex: number;
106
+ }
107
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAEjG;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,GAAG;IACnB,wEAAwE;IACxE,EAAE,EAAE,WAAW,CAAC;IAChB,oDAAoD;IACpD,gBAAgB,EAAE,sBAAsB,CAAC;IACzC,4DAA4D;IAC5D,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,wCAAwC;IACxC,EAAE,EAAE,WAAW,CAAC;IAChB,uCAAuC;IACvC,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACnC,wCAAwC;IACxC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,2CAA2C;IAC3C,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;CACnE;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,sBAAsB;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACrC,gCAAgC;IAChC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACvC;;;;;OAKG;IACH,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,yCAAyC;IACzC,eAAe,EAAE,MAAM,CAAC;CACxB"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@earth-app/collegedb",
3
+ "module": "dist/index.js",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "type": "module",
7
+ "version": "1.0.1",
8
+ "files": [
9
+ "dist/**/*",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "scripts": {
17
+ "build": "bun build src/index.ts --outdir=dist --target=node --format=esm --minify --sourcemap=linked && bunx tsc --project tsconfig.build.json",
18
+ "docs:build": "bunx typedoc src --out ./typedoc",
19
+ "prettier": "bunx prettier --write .",
20
+ "prettier:check": "bunx prettier --check .",
21
+ "test": "vitest run",
22
+ "test:watch": "vitest",
23
+ "test:coverage": "vitest run --coverage",
24
+ "prepare": "husky install"
25
+ },
26
+ "dependencies": {
27
+ "@cloudflare/workers-types": "^4.20250726.0"
28
+ },
29
+ "devDependencies": {
30
+ "@babel/cli": "^7.28.0",
31
+ "@babel/core": "^7.28.0",
32
+ "@babel/preset-env": "^7.28.0",
33
+ "@babel/preset-typescript": "^7.27.1",
34
+ "@types/bun": "latest",
35
+ "@vitest/coverage-v8": "^3.2.4",
36
+ "husky": "^9.1.7",
37
+ "jsdoc-babel": "^0.5.0",
38
+ "lint-staged": "^16.1.2",
39
+ "prettier": "^3.6.2",
40
+ "prettier-plugin-organize-imports": "^4.2.0",
41
+ "typedoc": "^0.28.8",
42
+ "vitest": "^3.2.4"
43
+ },
44
+ "peerDependencies": {
45
+ "typescript": "^5"
46
+ },
47
+ "lint-staged": {
48
+ "*.{js,ts,css,md}": "prettier --write"
49
+ }
50
+ }