@http-client-toolkit/store-sqlite 0.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,537 @@
1
+ import { CacheStore, DedupeStore, RateLimitStore, RateLimitConfig, AdaptiveRateLimitStore, AdaptiveConfigSchema, RequestPriority } from '@http-client-toolkit/core';
2
+ export { AdaptiveConfig, AdaptiveRateLimitStore, CacheStore, DedupeStore, RateLimitConfig, RateLimitStore, RequestPriority } from '@http-client-toolkit/core';
3
+ import Database from 'better-sqlite3';
4
+ import { z } from 'zod';
5
+ import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
6
+
7
+ interface SQLiteCacheStoreOptions {
8
+ /** File path or existing `better-sqlite3` connection. Defaults to `':memory:'`. */
9
+ database?: string | InstanceType<typeof Database>;
10
+ cleanupIntervalMs?: number;
11
+ maxEntrySizeBytes?: number;
12
+ }
13
+ declare class SQLiteCacheStore<T = unknown> implements CacheStore<T> {
14
+ private db;
15
+ private sqlite;
16
+ /** Indicates whether this store is responsible for managing (and therefore closing) the SQLite connection */
17
+ private readonly isConnectionManaged;
18
+ private cleanupInterval?;
19
+ private readonly cleanupIntervalMs;
20
+ /**
21
+ * Maximum allowed size (in bytes) for a single cache entry. If the serialized
22
+ * value exceeds this limit the entry will be **silently skipped** to avoid
23
+ * breaching SQLite's max length limits which could otherwise throw at write
24
+ * time. Defaults to `5 MiB`, which is well under SQLiteʼs compiled
25
+ * `SQLITE_MAX_LENGTH` (usually 1 GiB) yet large enough for typical Comic Vine
26
+ * responses.
27
+ */
28
+ private readonly maxEntrySizeBytes;
29
+ private isDestroyed;
30
+ constructor({
31
+ /** File path or existing `better-sqlite3` connection. Defaults to `':memory:'`. */
32
+ database,
33
+ /** Cleanup interval in milliseconds. Defaults to 1 minute. */
34
+ cleanupIntervalMs,
35
+ /** Maximum allowed size (in bytes) for a single cache entry. Defaults to 5 MiB. */
36
+ maxEntrySizeBytes, }?: SQLiteCacheStoreOptions);
37
+ get(hash: string): Promise<T | undefined>;
38
+ set(hash: string, value: T, ttlSeconds: number): Promise<void>;
39
+ delete(hash: string): Promise<void>;
40
+ clear(): Promise<void>;
41
+ /**
42
+ * Get cache statistics
43
+ */
44
+ getStats(): Promise<{
45
+ totalItems: number;
46
+ expiredItems: number;
47
+ databaseSizeKB: number;
48
+ }>;
49
+ /**
50
+ * Manually trigger cleanup of expired items
51
+ */
52
+ cleanup(): Promise<void>;
53
+ /**
54
+ * Close the database connection
55
+ */
56
+ close(): Promise<void>;
57
+ /**
58
+ * Alias for close() to match test expectations
59
+ */
60
+ destroy(): void;
61
+ private initializeDatabase;
62
+ private startCleanupInterval;
63
+ private cleanupExpiredItems;
64
+ }
65
+
66
+ interface SQLiteDedupeStoreOptions {
67
+ database?: string | InstanceType<typeof Database>;
68
+ jobTimeoutMs?: number;
69
+ timeoutMs?: number;
70
+ cleanupIntervalMs?: number;
71
+ pollIntervalMs?: number;
72
+ }
73
+ declare class SQLiteDedupeStore<T = unknown> implements DedupeStore<T> {
74
+ private db;
75
+ private sqlite;
76
+ /** Indicates whether this store manages (and should close) the SQLite connection */
77
+ private readonly isConnectionManaged;
78
+ private jobPromises;
79
+ private jobSettlers;
80
+ private readonly jobTimeoutMs;
81
+ private readonly pollIntervalMs;
82
+ private cleanupInterval?;
83
+ private readonly cleanupIntervalMs;
84
+ private isDestroyed;
85
+ constructor({
86
+ /** File path or existing `better-sqlite3` Database instance. Defaults to `':memory:'`. */
87
+ database,
88
+ /** Job timeout in milliseconds. Preferred over timeoutMs. */
89
+ jobTimeoutMs,
90
+ /** Legacy alias for jobTimeoutMs. */
91
+ timeoutMs,
92
+ /** Cleanup interval in milliseconds. Defaults to 1 minute. */
93
+ cleanupIntervalMs,
94
+ /** Poll interval for checking pending jobs in milliseconds. Defaults to 100ms. */
95
+ pollIntervalMs, }?: SQLiteDedupeStoreOptions);
96
+ private startCleanupInterval;
97
+ private cleanupExpiredJobs;
98
+ waitFor(hash: string): Promise<T | undefined>;
99
+ register(hash: string): Promise<string>;
100
+ registerOrJoin(hash: string): Promise<{
101
+ jobId: string;
102
+ isOwner: boolean;
103
+ }>;
104
+ complete(hash: string, value: T | undefined): Promise<void>;
105
+ fail(hash: string, error: Error): Promise<void>;
106
+ isInProgress(hash: string): Promise<boolean>;
107
+ getResult(hash: string): Promise<T | undefined>;
108
+ /**
109
+ * Get statistics about dedupe jobs
110
+ */
111
+ getStats(): Promise<{
112
+ totalJobs: number;
113
+ pendingJobs: number;
114
+ completedJobs: number;
115
+ failedJobs: number;
116
+ expiredJobs: number;
117
+ }>;
118
+ /**
119
+ * Clean up expired jobs
120
+ */
121
+ cleanup(): Promise<void>;
122
+ /**
123
+ * Clear all jobs
124
+ */
125
+ clear(): Promise<void>;
126
+ /**
127
+ * Close the database connection
128
+ */
129
+ close(): Promise<void>;
130
+ /**
131
+ * Alias for close() to match test expectations
132
+ */
133
+ destroy(): void;
134
+ private deserializeResult;
135
+ private initializeDatabase;
136
+ }
137
+
138
+ interface SQLiteRateLimitStoreOptions {
139
+ /** File path or existing `better-sqlite3` Database instance. Defaults to `':memory:'`. */
140
+ database?: string | InstanceType<typeof Database>;
141
+ /** Global/default rate-limit config applied when a resource-specific override is not provided. */
142
+ defaultConfig?: RateLimitConfig;
143
+ /** Optional per-resource overrides. */
144
+ resourceConfigs?: Map<string, RateLimitConfig>;
145
+ }
146
+ declare class SQLiteRateLimitStore implements RateLimitStore {
147
+ private db;
148
+ private sqlite;
149
+ /** Indicates whether this store manages (and should close) the SQLite connection */
150
+ private readonly isConnectionManaged;
151
+ private defaultConfig;
152
+ private resourceConfigs;
153
+ private isDestroyed;
154
+ constructor({
155
+ /** File path or existing `better-sqlite3` Database instance. Defaults to `':memory:'`. */
156
+ database,
157
+ /** Global/default rate-limit config applied when a resource-specific override is not provided. */
158
+ defaultConfig,
159
+ /** Optional per-resource overrides. */
160
+ resourceConfigs, }?: SQLiteRateLimitStoreOptions);
161
+ canProceed(resource: string): Promise<boolean>;
162
+ record(resource: string): Promise<void>;
163
+ getStatus(resource: string): Promise<{
164
+ remaining: number;
165
+ resetTime: Date;
166
+ limit: number;
167
+ }>;
168
+ reset(resource: string): Promise<void>;
169
+ getWaitTime(resource: string): Promise<number>;
170
+ /**
171
+ * Set rate limit configuration for a specific resource
172
+ */
173
+ setResourceConfig(resource: string, config: RateLimitConfig): void;
174
+ /**
175
+ * Get rate limit configuration for a resource
176
+ */
177
+ getResourceConfig(resource: string): RateLimitConfig;
178
+ /**
179
+ * Get statistics for all resources
180
+ */
181
+ getStats(): Promise<{
182
+ totalRequests: number;
183
+ uniqueResources: number;
184
+ rateLimitedResources: Array<string>;
185
+ }>;
186
+ /**
187
+ * Clean up all rate limit data
188
+ */
189
+ clear(): Promise<void>;
190
+ /**
191
+ * Clean up expired requests for all resources
192
+ */
193
+ cleanup(): Promise<void>;
194
+ /**
195
+ * Close the database connection
196
+ */
197
+ close(): Promise<void>;
198
+ /**
199
+ * Alias for close() to match test expectations
200
+ */
201
+ destroy(): void;
202
+ private cleanupExpiredRequests;
203
+ private initializeDatabase;
204
+ }
205
+
206
+ interface SqliteAdaptiveRateLimitStoreOptions {
207
+ /** File path or existing `better-sqlite3` Database instance. Defaults to `':memory:'`. */
208
+ database?: string | InstanceType<typeof Database>;
209
+ /** Global/default rate-limit config applied when a resource-specific override is not provided. */
210
+ defaultConfig?: RateLimitConfig;
211
+ /** Optional per-resource overrides. */
212
+ resourceConfigs?: Map<string, RateLimitConfig>;
213
+ /** Adaptive configuration for priority-based rate limiting */
214
+ adaptiveConfig?: Partial<z.input<typeof AdaptiveConfigSchema>>;
215
+ }
216
+ declare class SqliteAdaptiveRateLimitStore implements AdaptiveRateLimitStore {
217
+ private db;
218
+ private sqlite;
219
+ /** Indicates whether this store manages (and should close) the SQLite connection */
220
+ private readonly isConnectionManaged;
221
+ private defaultConfig;
222
+ private resourceConfigs;
223
+ private isDestroyed;
224
+ private capacityCalculator;
225
+ private activityMetrics;
226
+ private lastCapacityUpdate;
227
+ private cachedCapacity;
228
+ constructor({ database, defaultConfig, resourceConfigs, adaptiveConfig, }?: SqliteAdaptiveRateLimitStoreOptions);
229
+ canProceed(resource: string, priority?: RequestPriority): Promise<boolean>;
230
+ record(resource: string, priority?: RequestPriority): Promise<void>;
231
+ getStatus(resource: string): Promise<{
232
+ remaining: number;
233
+ resetTime: Date;
234
+ limit: number;
235
+ adaptive?: {
236
+ userReserved: number;
237
+ backgroundMax: number;
238
+ backgroundPaused: boolean;
239
+ recentUserActivity: number;
240
+ reason: string;
241
+ };
242
+ }>;
243
+ reset(resource: string): Promise<void>;
244
+ getWaitTime(resource: string, priority?: RequestPriority): Promise<number>;
245
+ /**
246
+ * Set rate limit configuration for a specific resource
247
+ */
248
+ setResourceConfig(resource: string, config: RateLimitConfig): void;
249
+ /**
250
+ * Get rate limit configuration for a resource
251
+ */
252
+ getResourceConfig(resource: string): RateLimitConfig;
253
+ /**
254
+ * Get statistics for all resources
255
+ */
256
+ getStats(): Promise<{
257
+ totalRequests: number;
258
+ uniqueResources: number;
259
+ rateLimitedResources: Array<string>;
260
+ }>;
261
+ /**
262
+ * Clean up all rate limit data
263
+ */
264
+ clear(): Promise<void>;
265
+ /**
266
+ * Clean up expired requests for all resources
267
+ */
268
+ cleanup(): Promise<void>;
269
+ /**
270
+ * Close the database connection
271
+ */
272
+ close(): Promise<void>;
273
+ /**
274
+ * Alias for close() to match test expectations
275
+ */
276
+ destroy(): void;
277
+ private calculateCurrentCapacity;
278
+ private getOrCreateActivityMetrics;
279
+ private ensureActivityMetrics;
280
+ private getCurrentUsage;
281
+ private cleanupOldRequests;
282
+ private getResourceLimit;
283
+ private getDefaultCapacity;
284
+ private cleanupExpiredRequests;
285
+ private initializeDatabase;
286
+ }
287
+
288
+ declare const cacheTable: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
289
+ name: "cache";
290
+ schema: undefined;
291
+ columns: {
292
+ hash: drizzle_orm_sqlite_core.SQLiteColumn<{
293
+ name: "hash";
294
+ tableName: "cache";
295
+ dataType: "string";
296
+ columnType: "SQLiteText";
297
+ data: string;
298
+ driverParam: string;
299
+ notNull: true;
300
+ hasDefault: false;
301
+ isPrimaryKey: true;
302
+ isAutoincrement: false;
303
+ hasRuntimeDefault: false;
304
+ enumValues: [string, ...string[]];
305
+ baseColumn: never;
306
+ generated: undefined;
307
+ }, object>;
308
+ value: drizzle_orm_sqlite_core.SQLiteColumn<{
309
+ name: "value";
310
+ tableName: "cache";
311
+ dataType: "json";
312
+ columnType: "SQLiteBlobJson";
313
+ data: unknown;
314
+ driverParam: Buffer<ArrayBufferLike>;
315
+ notNull: true;
316
+ hasDefault: false;
317
+ isPrimaryKey: false;
318
+ isAutoincrement: false;
319
+ hasRuntimeDefault: false;
320
+ enumValues: undefined;
321
+ baseColumn: never;
322
+ generated: undefined;
323
+ }, object>;
324
+ expiresAt: drizzle_orm_sqlite_core.SQLiteColumn<{
325
+ name: "expires_at";
326
+ tableName: "cache";
327
+ dataType: "number";
328
+ columnType: "SQLiteInteger";
329
+ data: number;
330
+ driverParam: number;
331
+ notNull: true;
332
+ hasDefault: false;
333
+ isPrimaryKey: false;
334
+ isAutoincrement: false;
335
+ hasRuntimeDefault: false;
336
+ enumValues: undefined;
337
+ baseColumn: never;
338
+ generated: undefined;
339
+ }, object>;
340
+ createdAt: drizzle_orm_sqlite_core.SQLiteColumn<{
341
+ name: "created_at";
342
+ tableName: "cache";
343
+ dataType: "number";
344
+ columnType: "SQLiteInteger";
345
+ data: number;
346
+ driverParam: number;
347
+ notNull: true;
348
+ hasDefault: false;
349
+ isPrimaryKey: false;
350
+ isAutoincrement: false;
351
+ hasRuntimeDefault: false;
352
+ enumValues: undefined;
353
+ baseColumn: never;
354
+ generated: undefined;
355
+ }, object>;
356
+ };
357
+ dialect: "sqlite";
358
+ }>;
359
+ declare const dedupeTable: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
360
+ name: "dedupe_jobs";
361
+ schema: undefined;
362
+ columns: {
363
+ hash: drizzle_orm_sqlite_core.SQLiteColumn<{
364
+ name: "hash";
365
+ tableName: "dedupe_jobs";
366
+ dataType: "string";
367
+ columnType: "SQLiteText";
368
+ data: string;
369
+ driverParam: string;
370
+ notNull: true;
371
+ hasDefault: false;
372
+ isPrimaryKey: true;
373
+ isAutoincrement: false;
374
+ hasRuntimeDefault: false;
375
+ enumValues: [string, ...string[]];
376
+ baseColumn: never;
377
+ generated: undefined;
378
+ }, object>;
379
+ jobId: drizzle_orm_sqlite_core.SQLiteColumn<{
380
+ name: "job_id";
381
+ tableName: "dedupe_jobs";
382
+ dataType: "string";
383
+ columnType: "SQLiteText";
384
+ data: string;
385
+ driverParam: string;
386
+ notNull: true;
387
+ hasDefault: false;
388
+ isPrimaryKey: false;
389
+ isAutoincrement: false;
390
+ hasRuntimeDefault: false;
391
+ enumValues: [string, ...string[]];
392
+ baseColumn: never;
393
+ generated: undefined;
394
+ }, object>;
395
+ status: drizzle_orm_sqlite_core.SQLiteColumn<{
396
+ name: "status";
397
+ tableName: "dedupe_jobs";
398
+ dataType: "string";
399
+ columnType: "SQLiteText";
400
+ data: string;
401
+ driverParam: string;
402
+ notNull: true;
403
+ hasDefault: false;
404
+ isPrimaryKey: false;
405
+ isAutoincrement: false;
406
+ hasRuntimeDefault: false;
407
+ enumValues: [string, ...string[]];
408
+ baseColumn: never;
409
+ generated: undefined;
410
+ }, object>;
411
+ result: drizzle_orm_sqlite_core.SQLiteColumn<{
412
+ name: "result";
413
+ tableName: "dedupe_jobs";
414
+ dataType: "json";
415
+ columnType: "SQLiteBlobJson";
416
+ data: unknown;
417
+ driverParam: Buffer<ArrayBufferLike>;
418
+ notNull: false;
419
+ hasDefault: false;
420
+ isPrimaryKey: false;
421
+ isAutoincrement: false;
422
+ hasRuntimeDefault: false;
423
+ enumValues: undefined;
424
+ baseColumn: never;
425
+ generated: undefined;
426
+ }, object>;
427
+ error: drizzle_orm_sqlite_core.SQLiteColumn<{
428
+ name: "error";
429
+ tableName: "dedupe_jobs";
430
+ dataType: "string";
431
+ columnType: "SQLiteText";
432
+ data: string;
433
+ driverParam: string;
434
+ notNull: false;
435
+ hasDefault: false;
436
+ isPrimaryKey: false;
437
+ isAutoincrement: false;
438
+ hasRuntimeDefault: false;
439
+ enumValues: [string, ...string[]];
440
+ baseColumn: never;
441
+ generated: undefined;
442
+ }, object>;
443
+ createdAt: drizzle_orm_sqlite_core.SQLiteColumn<{
444
+ name: "created_at";
445
+ tableName: "dedupe_jobs";
446
+ dataType: "number";
447
+ columnType: "SQLiteInteger";
448
+ data: number;
449
+ driverParam: number;
450
+ notNull: true;
451
+ hasDefault: false;
452
+ isPrimaryKey: false;
453
+ isAutoincrement: false;
454
+ hasRuntimeDefault: false;
455
+ enumValues: undefined;
456
+ baseColumn: never;
457
+ generated: undefined;
458
+ }, object>;
459
+ updatedAt: drizzle_orm_sqlite_core.SQLiteColumn<{
460
+ name: "updated_at";
461
+ tableName: "dedupe_jobs";
462
+ dataType: "number";
463
+ columnType: "SQLiteInteger";
464
+ data: number;
465
+ driverParam: number;
466
+ notNull: true;
467
+ hasDefault: false;
468
+ isPrimaryKey: false;
469
+ isAutoincrement: false;
470
+ hasRuntimeDefault: false;
471
+ enumValues: undefined;
472
+ baseColumn: never;
473
+ generated: undefined;
474
+ }, object>;
475
+ };
476
+ dialect: "sqlite";
477
+ }>;
478
+ declare const rateLimitTable: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
479
+ name: "rate_limits";
480
+ schema: undefined;
481
+ columns: {
482
+ resource: drizzle_orm_sqlite_core.SQLiteColumn<{
483
+ name: "resource";
484
+ tableName: "rate_limits";
485
+ dataType: "string";
486
+ columnType: "SQLiteText";
487
+ data: string;
488
+ driverParam: string;
489
+ notNull: true;
490
+ hasDefault: false;
491
+ isPrimaryKey: false;
492
+ isAutoincrement: false;
493
+ hasRuntimeDefault: false;
494
+ enumValues: [string, ...string[]];
495
+ baseColumn: never;
496
+ generated: undefined;
497
+ }, object>;
498
+ timestamp: drizzle_orm_sqlite_core.SQLiteColumn<{
499
+ name: "timestamp";
500
+ tableName: "rate_limits";
501
+ dataType: "number";
502
+ columnType: "SQLiteInteger";
503
+ data: number;
504
+ driverParam: number;
505
+ notNull: true;
506
+ hasDefault: false;
507
+ isPrimaryKey: false;
508
+ isAutoincrement: false;
509
+ hasRuntimeDefault: false;
510
+ enumValues: undefined;
511
+ baseColumn: never;
512
+ generated: undefined;
513
+ }, object>;
514
+ id: drizzle_orm_sqlite_core.SQLiteColumn<{
515
+ name: "id";
516
+ tableName: "rate_limits";
517
+ dataType: "number";
518
+ columnType: "SQLiteInteger";
519
+ data: number;
520
+ driverParam: number;
521
+ notNull: true;
522
+ hasDefault: true;
523
+ isPrimaryKey: true;
524
+ isAutoincrement: false;
525
+ hasRuntimeDefault: false;
526
+ enumValues: undefined;
527
+ baseColumn: never;
528
+ generated: undefined;
529
+ }, object>;
530
+ };
531
+ dialect: "sqlite";
532
+ }>;
533
+ type CacheRow = typeof cacheTable.$inferSelect;
534
+ type DedupeRow = typeof dedupeTable.$inferSelect;
535
+ type RateLimitRow = typeof rateLimitTable.$inferSelect;
536
+
537
+ export { type CacheRow, type DedupeRow, type RateLimitRow, SQLiteCacheStore, type SQLiteCacheStoreOptions, SQLiteDedupeStore, type SQLiteDedupeStoreOptions, SQLiteRateLimitStore, type SQLiteRateLimitStoreOptions, SqliteAdaptiveRateLimitStore, type SqliteAdaptiveRateLimitStoreOptions, cacheTable, dedupeTable, rateLimitTable };