commandkit 1.0.0-dev.20250702022547 → 1.0.0-dev.20250702125326
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/cli/app-process.d.ts +2 -2
- package/dist/cli/common.d.ts +2 -2
- package/dist/cli/information.js +1 -1
- package/dist/cli/production.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/kv/kv.d.ts +321 -0
- package/dist/kv/kv.js +428 -0
- package/dist/kv/kv.js.map +1 -0
- package/dist/{version-CHYJXFOa.js → version-DvvD35ov.js} +2 -2
- package/dist/{version-CHYJXFOa.js.map → version-DvvD35ov.js.map} +1 -1
- package/dist/version.js +1 -1
- package/kv.cjs +6 -0
- package/kv.d.ts +1 -0
- package/package.json +10 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as child_process3 from "child_process";
|
|
2
2
|
|
|
3
3
|
//#region src/cli/app-process.d.ts
|
|
4
4
|
|
|
@@ -6,7 +6,7 @@ import * as child_process0 from "child_process";
|
|
|
6
6
|
* @private
|
|
7
7
|
* @internal
|
|
8
8
|
*/
|
|
9
|
-
declare function createAppProcess(fileName: string, cwd: string, isDev: boolean):
|
|
9
|
+
declare function createAppProcess(fileName: string, cwd: string, isDev: boolean): child_process3.ChildProcess;
|
|
10
10
|
//#endregion
|
|
11
11
|
export { createAppProcess };
|
|
12
12
|
//# sourceMappingURL=app-process.d.ts.map
|
package/dist/cli/common.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ import "../CommandsRouter-CoOA7hkf.js";
|
|
|
29
29
|
import "../EventsRouter-BacqK6z3.js";
|
|
30
30
|
import "../index-CUPkUUOR.js";
|
|
31
31
|
import "../constants-BTttfrm3.js";
|
|
32
|
-
import * as
|
|
32
|
+
import * as typescript0 from "typescript";
|
|
33
33
|
|
|
34
34
|
//#region src/cli/common.d.ts
|
|
35
35
|
/**
|
|
@@ -57,7 +57,7 @@ declare function findPackageJSON(): any;
|
|
|
57
57
|
* @private
|
|
58
58
|
* @internal
|
|
59
59
|
*/
|
|
60
|
-
declare function loadTypeScript(e?: string): Promise<typeof
|
|
60
|
+
declare function loadTypeScript(e?: string): Promise<typeof typescript0>;
|
|
61
61
|
/**
|
|
62
62
|
* @private
|
|
63
63
|
* @internal
|
package/dist/cli/information.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require('../chunk-nOFOJqeH.js');
|
|
2
|
-
const require_version = require('../version-
|
|
2
|
+
const require_version = require('../version-DvvD35ov.js');
|
|
3
3
|
const node_fs = require_chunk.__toESM(require("node:fs"));
|
|
4
4
|
const node_path = require_chunk.__toESM(require("node:path"));
|
|
5
5
|
const node_child_process = require_chunk.__toESM(require("node:child_process"));
|
package/dist/cli/production.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as child_process1 from "child_process";
|
|
2
2
|
|
|
3
3
|
//#region src/cli/production.d.ts
|
|
4
4
|
|
|
@@ -6,7 +6,7 @@ import * as child_process3 from "child_process";
|
|
|
6
6
|
* @private
|
|
7
7
|
* @internal
|
|
8
8
|
*/
|
|
9
|
-
declare function bootstrapProductionServer(configPath?: string): Promise<
|
|
9
|
+
declare function bootstrapProductionServer(configPath?: string): Promise<child_process1.ChildProcess>;
|
|
10
10
|
/**
|
|
11
11
|
* @private
|
|
12
12
|
* @internal
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ require('./store-CyzliDXj.js');
|
|
|
36
36
|
const require_helpers = require('./helpers-DfV6HlgI.js');
|
|
37
37
|
require('./app-gCenKq8k.js');
|
|
38
38
|
require('./ILogger-BMIMljYD.js');
|
|
39
|
-
const require_version = require('./version-
|
|
39
|
+
const require_version = require('./version-DvvD35ov.js');
|
|
40
40
|
const require_feature_flags = require('./feature-flags-DJcINI5E.js');
|
|
41
41
|
const require_init = require('./init-DeoDd5cK.js');
|
|
42
42
|
|
package/dist/kv/kv.d.ts
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { DatabaseSync } from "node:sqlite";
|
|
2
|
+
|
|
3
|
+
//#region src/kv/kv.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Configuration options for the KV store
|
|
7
|
+
*/
|
|
8
|
+
interface KvOptions {
|
|
9
|
+
/** Enable Write-Ahead Logging for better performance and durability */
|
|
10
|
+
enableWAL?: boolean;
|
|
11
|
+
/** Namespace for the key-value store table */
|
|
12
|
+
namespace?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A key-value store implementation using SQLite
|
|
16
|
+
*
|
|
17
|
+
* This class provides a simple, persistent key-value storage solution
|
|
18
|
+
* with support for namespaces, automatic cleanup, iteration, and expiration.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const kv = new KV('data.db');
|
|
23
|
+
* kv.set('user:123', JSON.stringify({ name: 'John', age: 30 }));
|
|
24
|
+
* const user = JSON.parse(kv.get('user:123') || '{}');
|
|
25
|
+
*
|
|
26
|
+
* // Using namespaces
|
|
27
|
+
* const userKv = kv.namespace('users');
|
|
28
|
+
* userKv.set('123', JSON.stringify({ name: 'John' }));
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
declare class KV implements Disposable, AsyncDisposable {
|
|
32
|
+
private options;
|
|
33
|
+
private db;
|
|
34
|
+
private statements;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new KV store instance
|
|
37
|
+
*
|
|
38
|
+
* @param path - Database file path, buffer, URL, or existing DatabaseSync instance
|
|
39
|
+
* @param options - Configuration options for the KV store
|
|
40
|
+
*/
|
|
41
|
+
constructor(path: string | Buffer | URL | DatabaseSync, options?: KvOptions);
|
|
42
|
+
/**
|
|
43
|
+
* Gets the current timestamp in milliseconds
|
|
44
|
+
*/
|
|
45
|
+
private getCurrentTime;
|
|
46
|
+
/**
|
|
47
|
+
* Checks if the database connection is open
|
|
48
|
+
*
|
|
49
|
+
* @returns `true` if the database is open, `false` otherwise
|
|
50
|
+
*/
|
|
51
|
+
isOpen(): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Gets the underlying SQLite database instance
|
|
54
|
+
*
|
|
55
|
+
* @returns The DatabaseSync instance
|
|
56
|
+
*/
|
|
57
|
+
getDatabase(): DatabaseSync;
|
|
58
|
+
/**
|
|
59
|
+
* Closes the database connection
|
|
60
|
+
*/
|
|
61
|
+
close(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Disposable implementation - closes the database when disposed
|
|
64
|
+
*/
|
|
65
|
+
[Symbol.dispose](): void;
|
|
66
|
+
/**
|
|
67
|
+
* AsyncDisposable implementation - closes the database when disposed
|
|
68
|
+
*/
|
|
69
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Retrieves a value by key
|
|
72
|
+
*
|
|
73
|
+
* @param key - The key to retrieve
|
|
74
|
+
* @returns The value associated with the key, or `undefined` if not found or expired
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const value = kv.get('my-key');
|
|
79
|
+
* if (value) {
|
|
80
|
+
* console.log('Found:', value);
|
|
81
|
+
* }
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
get(key: string): string | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* Sets a key-value pair
|
|
87
|
+
*
|
|
88
|
+
* @param key - The key to set
|
|
89
|
+
* @param value - The value to associate with the key
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* kv.set('user:123', JSON.stringify({ name: 'John' }));
|
|
94
|
+
* kv.set('counter', '42');
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
set(key: string, value: string): void;
|
|
98
|
+
/**
|
|
99
|
+
* Sets a key-value pair with expiration
|
|
100
|
+
*
|
|
101
|
+
* @param key - The key to set
|
|
102
|
+
* @param value - The value to associate with the key
|
|
103
|
+
* @param ttl - Time to live in milliseconds
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* // Set with 1 hour expiration
|
|
108
|
+
* kv.setex('session:123', 'user_data', 60 * 60 * 1000);
|
|
109
|
+
*
|
|
110
|
+
* // Set with 5 minutes expiration
|
|
111
|
+
* kv.setex('temp:data', 'cached_value', 5 * 60 * 1000);
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
setex(key: string, value: string, ttl: number): void;
|
|
115
|
+
/**
|
|
116
|
+
* Sets expiration for an existing key
|
|
117
|
+
*
|
|
118
|
+
* @param key - The key to set expiration for
|
|
119
|
+
* @param ttl - Time to live in milliseconds
|
|
120
|
+
* @returns `true` if the key exists and expiration was set, `false` otherwise
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* kv.set('user:123', 'user_data');
|
|
125
|
+
*
|
|
126
|
+
* // Set 30 minute expiration
|
|
127
|
+
* if (kv.expire('user:123', 30 * 60 * 1000)) {
|
|
128
|
+
* console.log('Expiration set successfully');
|
|
129
|
+
* }
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
expire(key: string, ttl: number): boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Gets the time to live for a key
|
|
135
|
+
*
|
|
136
|
+
* @param key - The key to check
|
|
137
|
+
* @returns Time to live in milliseconds, or `-1` if the key doesn't exist, or `-2` if the key has no expiration
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```typescript
|
|
141
|
+
* const ttl = kv.ttl('user:123');
|
|
142
|
+
* if (ttl > 0) {
|
|
143
|
+
* console.log(`Key expires in ${ttl}ms`);
|
|
144
|
+
* } else if (ttl === -2) {
|
|
145
|
+
* console.log('Key has no expiration');
|
|
146
|
+
* } else {
|
|
147
|
+
* console.log('Key does not exist');
|
|
148
|
+
* }
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
ttl(key: string): number;
|
|
152
|
+
/**
|
|
153
|
+
* Deletes a key-value pair
|
|
154
|
+
*
|
|
155
|
+
* @param key - The key to delete
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```typescript
|
|
159
|
+
* kv.delete('user:123');
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
delete(key: string): void;
|
|
163
|
+
/**
|
|
164
|
+
* Checks if a key exists and is not expired
|
|
165
|
+
*
|
|
166
|
+
* @param key - The key to check
|
|
167
|
+
* @returns `true` if the key exists and is not expired, `false` otherwise
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```typescript
|
|
171
|
+
* if (kv.has('user:123')) {
|
|
172
|
+
* console.log('User exists and is not expired');
|
|
173
|
+
* }
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
has(key: string): boolean;
|
|
177
|
+
/**
|
|
178
|
+
* Gets all keys in the current namespace (excluding expired keys)
|
|
179
|
+
*
|
|
180
|
+
* @returns Array of all non-expired keys
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const keys = kv.keys();
|
|
185
|
+
* console.log('All keys:', keys);
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
keys(): string[];
|
|
189
|
+
/**
|
|
190
|
+
* Gets all values in the current namespace (excluding expired keys)
|
|
191
|
+
*
|
|
192
|
+
* @returns Array of all non-expired values
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* const values = kv.values();
|
|
197
|
+
* console.log('All values:', values);
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
values(): string[];
|
|
201
|
+
/**
|
|
202
|
+
* Gets the total number of key-value pairs in the current namespace (excluding expired keys)
|
|
203
|
+
*
|
|
204
|
+
* @returns The count of non-expired key-value pairs
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```typescript
|
|
208
|
+
* const count = kv.count();
|
|
209
|
+
* console.log(`Total entries: ${count}`);
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
count(): number;
|
|
213
|
+
/**
|
|
214
|
+
* Removes all key-value pairs from the current namespace
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* kv.clear(); // Removes all entries in current namespace
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
clear(): void;
|
|
222
|
+
/**
|
|
223
|
+
* Gets all key-value pairs as an object (excluding expired keys)
|
|
224
|
+
*
|
|
225
|
+
* @returns Object with all non-expired key-value pairs
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* ```typescript
|
|
229
|
+
* const all = kv.all();
|
|
230
|
+
* console.log('All entries:', all);
|
|
231
|
+
* // Output: { 'key1': 'value1', 'key2': 'value2' }
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
234
|
+
all(): Record<string, string>;
|
|
235
|
+
/**
|
|
236
|
+
* Gets all available namespaces (tables) in the database
|
|
237
|
+
*
|
|
238
|
+
* @returns Array of namespace names
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```typescript
|
|
242
|
+
* const namespaces = kv.namespaces();
|
|
243
|
+
* console.log('Available namespaces:', namespaces);
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
namespaces(): string[];
|
|
247
|
+
/**
|
|
248
|
+
* Gets the current namespace name
|
|
249
|
+
*
|
|
250
|
+
* @returns The current namespace string
|
|
251
|
+
*/
|
|
252
|
+
getCurrentNamespace(): string;
|
|
253
|
+
/**
|
|
254
|
+
* Creates a new KV instance with a different namespace
|
|
255
|
+
*
|
|
256
|
+
* @param namespace - The namespace to use for the new instance
|
|
257
|
+
* @returns A new KV instance with the specified namespace
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```typescript
|
|
261
|
+
* const userKv = kv.namespace('users');
|
|
262
|
+
* const configKv = kv.namespace('config');
|
|
263
|
+
*
|
|
264
|
+
* userKv.set('123', 'John Doe');
|
|
265
|
+
* configKv.set('theme', 'dark');
|
|
266
|
+
* ```
|
|
267
|
+
*/
|
|
268
|
+
namespace(namespace: string): KV;
|
|
269
|
+
/**
|
|
270
|
+
* Iterator implementation for iterating over all non-expired key-value pairs
|
|
271
|
+
*
|
|
272
|
+
* @returns Iterator yielding [key, value] tuples
|
|
273
|
+
*
|
|
274
|
+
* @example
|
|
275
|
+
* ```typescript
|
|
276
|
+
* for (const [key, value] of kv) {
|
|
277
|
+
* console.log(`${key}: ${value}`);
|
|
278
|
+
* }
|
|
279
|
+
*
|
|
280
|
+
* // Or using spread operator
|
|
281
|
+
* const entries = [...kv];
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
[Symbol.iterator](): Iterator<[string, string]>;
|
|
285
|
+
/**
|
|
286
|
+
* Executes a function within a transaction
|
|
287
|
+
*
|
|
288
|
+
* @param fn - Function to execute within the transaction (can be async)
|
|
289
|
+
* @returns The result of the function
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* ```typescript
|
|
293
|
+
* // Synchronous transaction
|
|
294
|
+
* kv.transaction(() => {
|
|
295
|
+
* kv.set('user:123', JSON.stringify({ name: 'John' }));
|
|
296
|
+
* kv.set('user:456', JSON.stringify({ name: 'Jane' }));
|
|
297
|
+
* // If any operation fails, all changes are rolled back
|
|
298
|
+
* });
|
|
299
|
+
*
|
|
300
|
+
* // Async transaction
|
|
301
|
+
* await kv.transaction(async () => {
|
|
302
|
+
* kv.set('user:123', JSON.stringify({ name: 'John' }));
|
|
303
|
+
* await someAsyncOperation();
|
|
304
|
+
* kv.set('user:456', JSON.stringify({ name: 'Jane' }));
|
|
305
|
+
* // If any operation fails, all changes are rolled back
|
|
306
|
+
* });
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
transaction<T>(fn: () => T | Promise<T>): Promise<T>;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Opens a new KV instance
|
|
313
|
+
*
|
|
314
|
+
* @param path - Database file path, buffer, URL, or existing DatabaseSync instance
|
|
315
|
+
* @param options - Configuration options for the KV store
|
|
316
|
+
* @returns A new KV instance
|
|
317
|
+
*/
|
|
318
|
+
declare function openKV(path?: string | Buffer | URL | DatabaseSync, options?: KvOptions): KV;
|
|
319
|
+
//#endregion
|
|
320
|
+
export { KV, KvOptions, openKV };
|
|
321
|
+
//# sourceMappingURL=kv.d.ts.map
|
package/dist/kv/kv.js
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
const require_chunk = require('../chunk-nOFOJqeH.js');
|
|
2
|
+
const node_sqlite = require_chunk.__toESM(require("node:sqlite"));
|
|
3
|
+
|
|
4
|
+
//#region src/kv/kv.ts
|
|
5
|
+
/**
|
|
6
|
+
* A key-value store implementation using SQLite
|
|
7
|
+
*
|
|
8
|
+
* This class provides a simple, persistent key-value storage solution
|
|
9
|
+
* with support for namespaces, automatic cleanup, iteration, and expiration.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const kv = new KV('data.db');
|
|
14
|
+
* kv.set('user:123', JSON.stringify({ name: 'John', age: 30 }));
|
|
15
|
+
* const user = JSON.parse(kv.get('user:123') || '{}');
|
|
16
|
+
*
|
|
17
|
+
* // Using namespaces
|
|
18
|
+
* const userKv = kv.namespace('users');
|
|
19
|
+
* userKv.set('123', JSON.stringify({ name: 'John' }));
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
var KV = class KV {
|
|
23
|
+
db;
|
|
24
|
+
statements = {};
|
|
25
|
+
/**
|
|
26
|
+
* Creates a new KV store instance
|
|
27
|
+
*
|
|
28
|
+
* @param path - Database file path, buffer, URL, or existing DatabaseSync instance
|
|
29
|
+
* @param options - Configuration options for the KV store
|
|
30
|
+
*/
|
|
31
|
+
constructor(path, options = {
|
|
32
|
+
enableWAL: true,
|
|
33
|
+
namespace: "commandkit_kv"
|
|
34
|
+
}) {
|
|
35
|
+
this.options = options;
|
|
36
|
+
this.db = path instanceof node_sqlite.DatabaseSync ? path : new node_sqlite.DatabaseSync(path, { open: true });
|
|
37
|
+
if (options.enableWAL) this.db.exec(`PRAGMA journal_mode = WAL;`);
|
|
38
|
+
this.db.prepare(`
|
|
39
|
+
CREATE TABLE IF NOT EXISTS ? (
|
|
40
|
+
key TEXT PRIMARY KEY,
|
|
41
|
+
value TEXT,
|
|
42
|
+
expires_at INTEGER
|
|
43
|
+
)
|
|
44
|
+
`).run(options.namespace ?? "commandkit_kv");
|
|
45
|
+
this.statements = {
|
|
46
|
+
get: this.db.prepare(`SELECT value, expires_at FROM ? WHERE key = ?`),
|
|
47
|
+
set: this.db.prepare(`INSERT OR REPLACE INTO ? (key, value, expires_at) VALUES (?, ?, ?)`),
|
|
48
|
+
setex: this.db.prepare(`INSERT OR REPLACE INTO ? (key, value, expires_at) VALUES (?, ?, ?)`),
|
|
49
|
+
delete: this.db.prepare(`DELETE FROM ? WHERE key = ?`),
|
|
50
|
+
has: this.db.prepare(`SELECT COUNT(*) FROM ? WHERE key = ? AND (expires_at IS NULL OR expires_at > ?)`),
|
|
51
|
+
keys: this.db.prepare(`SELECT key FROM ? WHERE expires_at IS NULL OR expires_at > ?`),
|
|
52
|
+
values: this.db.prepare(`SELECT value FROM ? WHERE expires_at IS NULL OR expires_at > ?`),
|
|
53
|
+
clear: this.db.prepare(`DELETE FROM ?`),
|
|
54
|
+
count: this.db.prepare(`SELECT COUNT(*) FROM ? WHERE expires_at IS NULL OR expires_at > ?`),
|
|
55
|
+
all: this.db.prepare(`SELECT key, value FROM ? WHERE expires_at IS NULL OR expires_at > ?`),
|
|
56
|
+
expire: this.db.prepare(`UPDATE ? SET expires_at = ? WHERE key = ?`),
|
|
57
|
+
ttl: this.db.prepare(`SELECT expires_at FROM ? WHERE key = ?`),
|
|
58
|
+
namespaces: this.db.prepare(`SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'`),
|
|
59
|
+
begin: this.db.prepare(`BEGIN TRANSACTION`),
|
|
60
|
+
commit: this.db.prepare(`COMMIT`),
|
|
61
|
+
rollback: this.db.prepare(`ROLLBACK`)
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Gets the current timestamp in milliseconds
|
|
66
|
+
*/
|
|
67
|
+
getCurrentTime() {
|
|
68
|
+
return Date.now();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Checks if the database connection is open
|
|
72
|
+
*
|
|
73
|
+
* @returns `true` if the database is open, `false` otherwise
|
|
74
|
+
*/
|
|
75
|
+
isOpen() {
|
|
76
|
+
return this.db.isOpen;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Gets the underlying SQLite database instance
|
|
80
|
+
*
|
|
81
|
+
* @returns The DatabaseSync instance
|
|
82
|
+
*/
|
|
83
|
+
getDatabase() {
|
|
84
|
+
return this.db;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Closes the database connection
|
|
88
|
+
*/
|
|
89
|
+
close() {
|
|
90
|
+
if (this.db.isOpen) this.db.close();
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Disposable implementation - closes the database when disposed
|
|
94
|
+
*/
|
|
95
|
+
[Symbol.dispose]() {
|
|
96
|
+
this.close();
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* AsyncDisposable implementation - closes the database when disposed
|
|
100
|
+
*/
|
|
101
|
+
async [Symbol.asyncDispose]() {
|
|
102
|
+
this.close();
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Retrieves a value by key
|
|
106
|
+
*
|
|
107
|
+
* @param key - The key to retrieve
|
|
108
|
+
* @returns The value associated with the key, or `undefined` if not found or expired
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* const value = kv.get('my-key');
|
|
113
|
+
* if (value) {
|
|
114
|
+
* console.log('Found:', value);
|
|
115
|
+
* }
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
get(key) {
|
|
119
|
+
const result = this.statements.get.get(this.getCurrentNamespace(), key);
|
|
120
|
+
if (!result) return void 0;
|
|
121
|
+
if (result.expires_at && Number(result.expires_at) <= this.getCurrentTime()) {
|
|
122
|
+
this.delete(key);
|
|
123
|
+
return void 0;
|
|
124
|
+
}
|
|
125
|
+
return result.value;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Sets a key-value pair
|
|
129
|
+
*
|
|
130
|
+
* @param key - The key to set
|
|
131
|
+
* @param value - The value to associate with the key
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```typescript
|
|
135
|
+
* kv.set('user:123', JSON.stringify({ name: 'John' }));
|
|
136
|
+
* kv.set('counter', '42');
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
set(key, value) {
|
|
140
|
+
this.statements.set.run(this.getCurrentNamespace(), key, value, null);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Sets a key-value pair with expiration
|
|
144
|
+
*
|
|
145
|
+
* @param key - The key to set
|
|
146
|
+
* @param value - The value to associate with the key
|
|
147
|
+
* @param ttl - Time to live in milliseconds
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```typescript
|
|
151
|
+
* // Set with 1 hour expiration
|
|
152
|
+
* kv.setex('session:123', 'user_data', 60 * 60 * 1000);
|
|
153
|
+
*
|
|
154
|
+
* // Set with 5 minutes expiration
|
|
155
|
+
* kv.setex('temp:data', 'cached_value', 5 * 60 * 1000);
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
setex(key, value, ttl) {
|
|
159
|
+
const expiresAt = this.getCurrentTime() + ttl;
|
|
160
|
+
this.statements.setex.run(this.getCurrentNamespace(), key, value, expiresAt);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Sets expiration for an existing key
|
|
164
|
+
*
|
|
165
|
+
* @param key - The key to set expiration for
|
|
166
|
+
* @param ttl - Time to live in milliseconds
|
|
167
|
+
* @returns `true` if the key exists and expiration was set, `false` otherwise
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```typescript
|
|
171
|
+
* kv.set('user:123', 'user_data');
|
|
172
|
+
*
|
|
173
|
+
* // Set 30 minute expiration
|
|
174
|
+
* if (kv.expire('user:123', 30 * 60 * 1000)) {
|
|
175
|
+
* console.log('Expiration set successfully');
|
|
176
|
+
* }
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
expire(key, ttl) {
|
|
180
|
+
if (!this.has(key)) return false;
|
|
181
|
+
const expiresAt = this.getCurrentTime() + ttl;
|
|
182
|
+
this.statements.expire.run(this.getCurrentNamespace(), expiresAt, key);
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Gets the time to live for a key
|
|
187
|
+
*
|
|
188
|
+
* @param key - The key to check
|
|
189
|
+
* @returns Time to live in milliseconds, or `-1` if the key doesn't exist, or `-2` if the key has no expiration
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```typescript
|
|
193
|
+
* const ttl = kv.ttl('user:123');
|
|
194
|
+
* if (ttl > 0) {
|
|
195
|
+
* console.log(`Key expires in ${ttl}ms`);
|
|
196
|
+
* } else if (ttl === -2) {
|
|
197
|
+
* console.log('Key has no expiration');
|
|
198
|
+
* } else {
|
|
199
|
+
* console.log('Key does not exist');
|
|
200
|
+
* }
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
ttl(key) {
|
|
204
|
+
const result = this.statements.ttl.get(this.getCurrentNamespace(), key);
|
|
205
|
+
if (!result) return -1;
|
|
206
|
+
if (!result.expires_at) return -2;
|
|
207
|
+
const remaining = Number(result.expires_at) - this.getCurrentTime();
|
|
208
|
+
return remaining > 0 ? remaining : -1;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Deletes a key-value pair
|
|
212
|
+
*
|
|
213
|
+
* @param key - The key to delete
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```typescript
|
|
217
|
+
* kv.delete('user:123');
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
delete(key) {
|
|
221
|
+
this.statements.delete.run(this.getCurrentNamespace(), key);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Checks if a key exists and is not expired
|
|
225
|
+
*
|
|
226
|
+
* @param key - The key to check
|
|
227
|
+
* @returns `true` if the key exists and is not expired, `false` otherwise
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```typescript
|
|
231
|
+
* if (kv.has('user:123')) {
|
|
232
|
+
* console.log('User exists and is not expired');
|
|
233
|
+
* }
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
has(key) {
|
|
237
|
+
const result = this.statements.has.get(this.getCurrentNamespace(), key, this.getCurrentTime());
|
|
238
|
+
return (result === null || result === void 0 ? void 0 : result.count) !== void 0 && result.count !== null && Number(result.count) > 0;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Gets all keys in the current namespace (excluding expired keys)
|
|
242
|
+
*
|
|
243
|
+
* @returns Array of all non-expired keys
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```typescript
|
|
247
|
+
* const keys = kv.keys();
|
|
248
|
+
* console.log('All keys:', keys);
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
keys() {
|
|
252
|
+
const result = this.statements.keys.all(this.getCurrentNamespace(), this.getCurrentTime());
|
|
253
|
+
return result.map((row) => row.key);
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Gets all values in the current namespace (excluding expired keys)
|
|
257
|
+
*
|
|
258
|
+
* @returns Array of all non-expired values
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```typescript
|
|
262
|
+
* const values = kv.values();
|
|
263
|
+
* console.log('All values:', values);
|
|
264
|
+
* ```
|
|
265
|
+
*/
|
|
266
|
+
values() {
|
|
267
|
+
const result = this.statements.values.all(this.getCurrentNamespace(), this.getCurrentTime());
|
|
268
|
+
return result.map((row) => row.value);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Gets the total number of key-value pairs in the current namespace (excluding expired keys)
|
|
272
|
+
*
|
|
273
|
+
* @returns The count of non-expired key-value pairs
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```typescript
|
|
277
|
+
* const count = kv.count();
|
|
278
|
+
* console.log(`Total entries: ${count}`);
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
count() {
|
|
282
|
+
const result = this.statements.count.get(this.getCurrentNamespace(), this.getCurrentTime());
|
|
283
|
+
return Number((result === null || result === void 0 ? void 0 : result.count) ?? 0);
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Removes all key-value pairs from the current namespace
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```typescript
|
|
290
|
+
* kv.clear(); // Removes all entries in current namespace
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
clear() {
|
|
294
|
+
this.statements.clear.run(this.getCurrentNamespace());
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Gets all key-value pairs as an object (excluding expired keys)
|
|
298
|
+
*
|
|
299
|
+
* @returns Object with all non-expired key-value pairs
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```typescript
|
|
303
|
+
* const all = kv.all();
|
|
304
|
+
* console.log('All entries:', all);
|
|
305
|
+
* // Output: { 'key1': 'value1', 'key2': 'value2' }
|
|
306
|
+
* ```
|
|
307
|
+
*/
|
|
308
|
+
all() {
|
|
309
|
+
const result = this.statements.all.all(this.getCurrentNamespace(), this.getCurrentTime());
|
|
310
|
+
return Object.fromEntries(result.map((row) => [row.key, row.value]));
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Gets all available namespaces (tables) in the database
|
|
314
|
+
*
|
|
315
|
+
* @returns Array of namespace names
|
|
316
|
+
*
|
|
317
|
+
* @example
|
|
318
|
+
* ```typescript
|
|
319
|
+
* const namespaces = kv.namespaces();
|
|
320
|
+
* console.log('Available namespaces:', namespaces);
|
|
321
|
+
* ```
|
|
322
|
+
*/
|
|
323
|
+
namespaces() {
|
|
324
|
+
const result = this.statements.namespaces.all();
|
|
325
|
+
return result.map((row) => row.name);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Gets the current namespace name
|
|
329
|
+
*
|
|
330
|
+
* @returns The current namespace string
|
|
331
|
+
*/
|
|
332
|
+
getCurrentNamespace() {
|
|
333
|
+
return this.options.namespace ?? "commandkit_kv";
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Creates a new KV instance with a different namespace
|
|
337
|
+
*
|
|
338
|
+
* @param namespace - The namespace to use for the new instance
|
|
339
|
+
* @returns A new KV instance with the specified namespace
|
|
340
|
+
*
|
|
341
|
+
* @example
|
|
342
|
+
* ```typescript
|
|
343
|
+
* const userKv = kv.namespace('users');
|
|
344
|
+
* const configKv = kv.namespace('config');
|
|
345
|
+
*
|
|
346
|
+
* userKv.set('123', 'John Doe');
|
|
347
|
+
* configKv.set('theme', 'dark');
|
|
348
|
+
* ```
|
|
349
|
+
*/
|
|
350
|
+
namespace(namespace) {
|
|
351
|
+
return new KV(this.db, {
|
|
352
|
+
enableWAL: this.options.enableWAL,
|
|
353
|
+
namespace
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Iterator implementation for iterating over all non-expired key-value pairs
|
|
358
|
+
*
|
|
359
|
+
* @returns Iterator yielding [key, value] tuples
|
|
360
|
+
*
|
|
361
|
+
* @example
|
|
362
|
+
* ```typescript
|
|
363
|
+
* for (const [key, value] of kv) {
|
|
364
|
+
* console.log(`${key}: ${value}`);
|
|
365
|
+
* }
|
|
366
|
+
*
|
|
367
|
+
* // Or using spread operator
|
|
368
|
+
* const entries = [...kv];
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
*[Symbol.iterator]() {
|
|
372
|
+
const result = this.statements.all.iterate(this.getCurrentNamespace(), this.getCurrentTime());
|
|
373
|
+
for (const row of result) yield [row.key, row.value];
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Executes a function within a transaction
|
|
377
|
+
*
|
|
378
|
+
* @param fn - Function to execute within the transaction (can be async)
|
|
379
|
+
* @returns The result of the function
|
|
380
|
+
*
|
|
381
|
+
* @example
|
|
382
|
+
* ```typescript
|
|
383
|
+
* // Synchronous transaction
|
|
384
|
+
* kv.transaction(() => {
|
|
385
|
+
* kv.set('user:123', JSON.stringify({ name: 'John' }));
|
|
386
|
+
* kv.set('user:456', JSON.stringify({ name: 'Jane' }));
|
|
387
|
+
* // If any operation fails, all changes are rolled back
|
|
388
|
+
* });
|
|
389
|
+
*
|
|
390
|
+
* // Async transaction
|
|
391
|
+
* await kv.transaction(async () => {
|
|
392
|
+
* kv.set('user:123', JSON.stringify({ name: 'John' }));
|
|
393
|
+
* await someAsyncOperation();
|
|
394
|
+
* kv.set('user:456', JSON.stringify({ name: 'Jane' }));
|
|
395
|
+
* // If any operation fails, all changes are rolled back
|
|
396
|
+
* });
|
|
397
|
+
* ```
|
|
398
|
+
*/
|
|
399
|
+
async transaction(fn) {
|
|
400
|
+
try {
|
|
401
|
+
this.statements.begin.run();
|
|
402
|
+
const result = await fn();
|
|
403
|
+
this.statements.commit.run();
|
|
404
|
+
return result;
|
|
405
|
+
} catch (error) {
|
|
406
|
+
this.statements.rollback.run();
|
|
407
|
+
throw error;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
/**
|
|
412
|
+
* Opens a new KV instance
|
|
413
|
+
*
|
|
414
|
+
* @param path - Database file path, buffer, URL, or existing DatabaseSync instance
|
|
415
|
+
* @param options - Configuration options for the KV store
|
|
416
|
+
* @returns A new KV instance
|
|
417
|
+
*/
|
|
418
|
+
function openKV(path = "commandkit_kv.db", options = {
|
|
419
|
+
enableWAL: true,
|
|
420
|
+
namespace: "commandkit_kv"
|
|
421
|
+
}) {
|
|
422
|
+
return new KV(path, options);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
//#endregion
|
|
426
|
+
exports.KV = KV;
|
|
427
|
+
exports.openKV = openKV;
|
|
428
|
+
//# sourceMappingURL=kv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kv.js","names":[],"sources":["../../src/kv/kv.ts"],"sourcesContent":["import { DatabaseSync, StatementSync } from 'node:sqlite';\n\n/**\n * Configuration options for the KV store\n */\nexport interface KvOptions {\n /** Enable Write-Ahead Logging for better performance and durability */\n enableWAL?: boolean;\n /** Namespace for the key-value store table */\n namespace?: string;\n}\n\n/**\n * A key-value store implementation using SQLite\n *\n * This class provides a simple, persistent key-value storage solution\n * with support for namespaces, automatic cleanup, iteration, and expiration.\n *\n * @example\n * ```typescript\n * const kv = new KV('data.db');\n * kv.set('user:123', JSON.stringify({ name: 'John', age: 30 }));\n * const user = JSON.parse(kv.get('user:123') || '{}');\n *\n * // Using namespaces\n * const userKv = kv.namespace('users');\n * userKv.set('123', JSON.stringify({ name: 'John' }));\n * ```\n */\nexport class KV implements Disposable, AsyncDisposable {\n private db: DatabaseSync;\n private statements: Record<string, StatementSync> = {};\n\n /**\n * Creates a new KV store instance\n *\n * @param path - Database file path, buffer, URL, or existing DatabaseSync instance\n * @param options - Configuration options for the KV store\n */\n public constructor(\n path: string | Buffer | URL | DatabaseSync,\n private options: KvOptions = {\n enableWAL: true,\n namespace: 'commandkit_kv',\n },\n ) {\n this.db =\n path instanceof DatabaseSync\n ? path\n : new DatabaseSync(path, { open: true });\n\n if (options.enableWAL) {\n this.db.exec(/* sql */ `PRAGMA journal_mode = WAL;`);\n }\n\n this.db\n .prepare(\n /* sql */ `\n CREATE TABLE IF NOT EXISTS ? (\n key TEXT PRIMARY KEY,\n value TEXT,\n expires_at INTEGER\n )\n `,\n )\n .run(options.namespace ?? 'commandkit_kv');\n\n this.statements = {\n get: this.db.prepare(\n /* sql */ `SELECT value, expires_at FROM ? WHERE key = ?`,\n ),\n set: this.db.prepare(\n /* sql */ `INSERT OR REPLACE INTO ? (key, value, expires_at) VALUES (?, ?, ?)`,\n ),\n setex: this.db.prepare(\n /* sql */ `INSERT OR REPLACE INTO ? (key, value, expires_at) VALUES (?, ?, ?)`,\n ),\n delete: this.db.prepare(/* sql */ `DELETE FROM ? WHERE key = ?`),\n has: this.db.prepare(\n /* sql */ `SELECT COUNT(*) FROM ? WHERE key = ? AND (expires_at IS NULL OR expires_at > ?)`,\n ),\n keys: this.db.prepare(\n /* sql */ `SELECT key FROM ? WHERE expires_at IS NULL OR expires_at > ?`,\n ),\n values: this.db.prepare(\n /* sql */ `SELECT value FROM ? WHERE expires_at IS NULL OR expires_at > ?`,\n ),\n clear: this.db.prepare(/* sql */ `DELETE FROM ?`),\n count: this.db.prepare(\n /* sql */ `SELECT COUNT(*) FROM ? WHERE expires_at IS NULL OR expires_at > ?`,\n ),\n all: this.db.prepare(\n /* sql */ `SELECT key, value FROM ? WHERE expires_at IS NULL OR expires_at > ?`,\n ),\n expire: this.db.prepare(\n /* sql */ `UPDATE ? SET expires_at = ? WHERE key = ?`,\n ),\n ttl: this.db.prepare(/* sql */ `SELECT expires_at FROM ? WHERE key = ?`),\n namespaces: this.db.prepare(\n /* sql */ `SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'`,\n ),\n begin: this.db.prepare(/* sql */ `BEGIN TRANSACTION`),\n commit: this.db.prepare(/* sql */ `COMMIT`),\n rollback: this.db.prepare(/* sql */ `ROLLBACK`),\n };\n }\n\n /**\n * Gets the current timestamp in milliseconds\n */\n private getCurrentTime(): number {\n return Date.now();\n }\n\n /**\n * Checks if the database connection is open\n *\n * @returns `true` if the database is open, `false` otherwise\n */\n public isOpen(): boolean {\n return this.db.isOpen;\n }\n\n /**\n * Gets the underlying SQLite database instance\n *\n * @returns The DatabaseSync instance\n */\n public getDatabase(): DatabaseSync {\n return this.db;\n }\n\n /**\n * Closes the database connection\n */\n public close(): void {\n if (this.db.isOpen) this.db.close();\n }\n\n /**\n * Disposable implementation - closes the database when disposed\n */\n public [Symbol.dispose]() {\n this.close();\n }\n\n /**\n * AsyncDisposable implementation - closes the database when disposed\n */\n public async [Symbol.asyncDispose]() {\n this.close();\n }\n\n /**\n * Retrieves a value by key\n *\n * @param key - The key to retrieve\n * @returns The value associated with the key, or `undefined` if not found or expired\n *\n * @example\n * ```typescript\n * const value = kv.get('my-key');\n * if (value) {\n * console.log('Found:', value);\n * }\n * ```\n */\n public get(key: string): string | undefined {\n const result = this.statements.get.get(this.getCurrentNamespace(), key);\n\n if (!result) return undefined;\n\n // Check if the key has expired\n if (\n result.expires_at &&\n Number(result.expires_at) <= this.getCurrentTime()\n ) {\n this.delete(key);\n return undefined;\n }\n\n return result.value as string;\n }\n\n /**\n * Sets a key-value pair\n *\n * @param key - The key to set\n * @param value - The value to associate with the key\n *\n * @example\n * ```typescript\n * kv.set('user:123', JSON.stringify({ name: 'John' }));\n * kv.set('counter', '42');\n * ```\n */\n public set(key: string, value: string): void {\n this.statements.set.run(this.getCurrentNamespace(), key, value, null);\n }\n\n /**\n * Sets a key-value pair with expiration\n *\n * @param key - The key to set\n * @param value - The value to associate with the key\n * @param ttl - Time to live in milliseconds\n *\n * @example\n * ```typescript\n * // Set with 1 hour expiration\n * kv.setex('session:123', 'user_data', 60 * 60 * 1000);\n *\n * // Set with 5 minutes expiration\n * kv.setex('temp:data', 'cached_value', 5 * 60 * 1000);\n * ```\n */\n public setex(key: string, value: string, ttl: number): void {\n const expiresAt = this.getCurrentTime() + ttl;\n this.statements.setex.run(\n this.getCurrentNamespace(),\n key,\n value,\n expiresAt,\n );\n }\n\n /**\n * Sets expiration for an existing key\n *\n * @param key - The key to set expiration for\n * @param ttl - Time to live in milliseconds\n * @returns `true` if the key exists and expiration was set, `false` otherwise\n *\n * @example\n * ```typescript\n * kv.set('user:123', 'user_data');\n *\n * // Set 30 minute expiration\n * if (kv.expire('user:123', 30 * 60 * 1000)) {\n * console.log('Expiration set successfully');\n * }\n * ```\n */\n public expire(key: string, ttl: number): boolean {\n if (!this.has(key)) return false;\n\n const expiresAt = this.getCurrentTime() + ttl;\n this.statements.expire.run(this.getCurrentNamespace(), expiresAt, key);\n return true;\n }\n\n /**\n * Gets the time to live for a key\n *\n * @param key - The key to check\n * @returns Time to live in milliseconds, or `-1` if the key doesn't exist, or `-2` if the key has no expiration\n *\n * @example\n * ```typescript\n * const ttl = kv.ttl('user:123');\n * if (ttl > 0) {\n * console.log(`Key expires in ${ttl}ms`);\n * } else if (ttl === -2) {\n * console.log('Key has no expiration');\n * } else {\n * console.log('Key does not exist');\n * }\n * ```\n */\n public ttl(key: string): number {\n const result = this.statements.ttl.get(this.getCurrentNamespace(), key);\n\n if (!result) return -1; // Key doesn't exist\n\n if (!result.expires_at) return -2; // No expiration\n\n const remaining = Number(result.expires_at) - this.getCurrentTime();\n return remaining > 0 ? remaining : -1; // Expired or doesn't exist\n }\n\n /**\n * Deletes a key-value pair\n *\n * @param key - The key to delete\n *\n * @example\n * ```typescript\n * kv.delete('user:123');\n * ```\n */\n public delete(key: string): void {\n this.statements.delete.run(this.getCurrentNamespace(), key);\n }\n\n /**\n * Checks if a key exists and is not expired\n *\n * @param key - The key to check\n * @returns `true` if the key exists and is not expired, `false` otherwise\n *\n * @example\n * ```typescript\n * if (kv.has('user:123')) {\n * console.log('User exists and is not expired');\n * }\n * ```\n */\n public has(key: string): boolean {\n const result = this.statements.has.get(\n this.getCurrentNamespace(),\n key,\n this.getCurrentTime(),\n );\n\n return (\n result?.count !== undefined &&\n result.count !== null &&\n Number(result.count) > 0\n );\n }\n\n /**\n * Gets all keys in the current namespace (excluding expired keys)\n *\n * @returns Array of all non-expired keys\n *\n * @example\n * ```typescript\n * const keys = kv.keys();\n * console.log('All keys:', keys);\n * ```\n */\n public keys(): string[] {\n const result = this.statements.keys.all(\n this.getCurrentNamespace(),\n this.getCurrentTime(),\n );\n\n return result.map((row) => row.key as string);\n }\n\n /**\n * Gets all values in the current namespace (excluding expired keys)\n *\n * @returns Array of all non-expired values\n *\n * @example\n * ```typescript\n * const values = kv.values();\n * console.log('All values:', values);\n * ```\n */\n public values(): string[] {\n const result = this.statements.values.all(\n this.getCurrentNamespace(),\n this.getCurrentTime(),\n );\n\n return result.map((row) => row.value as string);\n }\n\n /**\n * Gets the total number of key-value pairs in the current namespace (excluding expired keys)\n *\n * @returns The count of non-expired key-value pairs\n *\n * @example\n * ```typescript\n * const count = kv.count();\n * console.log(`Total entries: ${count}`);\n * ```\n */\n public count(): number {\n const result = this.statements.count.get(\n this.getCurrentNamespace(),\n this.getCurrentTime(),\n );\n\n return Number(result?.count ?? 0);\n }\n\n /**\n * Removes all key-value pairs from the current namespace\n *\n * @example\n * ```typescript\n * kv.clear(); // Removes all entries in current namespace\n * ```\n */\n public clear(): void {\n this.statements.clear.run(this.getCurrentNamespace());\n }\n\n /**\n * Gets all key-value pairs as an object (excluding expired keys)\n *\n * @returns Object with all non-expired key-value pairs\n *\n * @example\n * ```typescript\n * const all = kv.all();\n * console.log('All entries:', all);\n * // Output: { 'key1': 'value1', 'key2': 'value2' }\n * ```\n */\n public all(): Record<string, string> {\n const result = this.statements.all.all(\n this.getCurrentNamespace(),\n this.getCurrentTime(),\n );\n\n return Object.fromEntries(\n result.map((row) => [row.key as string, row.value as string]),\n );\n }\n\n /**\n * Gets all available namespaces (tables) in the database\n *\n * @returns Array of namespace names\n *\n * @example\n * ```typescript\n * const namespaces = kv.namespaces();\n * console.log('Available namespaces:', namespaces);\n * ```\n */\n public namespaces(): string[] {\n const result = this.statements.namespaces.all();\n\n return result.map((row) => row.name as string);\n }\n\n /**\n * Gets the current namespace name\n *\n * @returns The current namespace string\n */\n public getCurrentNamespace(): string {\n return this.options.namespace ?? 'commandkit_kv';\n }\n\n /**\n * Creates a new KV instance with a different namespace\n *\n * @param namespace - The namespace to use for the new instance\n * @returns A new KV instance with the specified namespace\n *\n * @example\n * ```typescript\n * const userKv = kv.namespace('users');\n * const configKv = kv.namespace('config');\n *\n * userKv.set('123', 'John Doe');\n * configKv.set('theme', 'dark');\n * ```\n */\n public namespace(namespace: string): KV {\n return new KV(this.db, {\n enableWAL: this.options.enableWAL,\n namespace,\n });\n }\n\n /**\n * Iterator implementation for iterating over all non-expired key-value pairs\n *\n * @returns Iterator yielding [key, value] tuples\n *\n * @example\n * ```typescript\n * for (const [key, value] of kv) {\n * console.log(`${key}: ${value}`);\n * }\n *\n * // Or using spread operator\n * const entries = [...kv];\n * ```\n */\n public *[Symbol.iterator](): Iterator<[string, string]> {\n const result = this.statements.all.iterate(\n this.getCurrentNamespace(),\n this.getCurrentTime(),\n );\n\n for (const row of result) {\n yield [row.key as string, row.value as string];\n }\n }\n\n /**\n * Executes a function within a transaction\n *\n * @param fn - Function to execute within the transaction (can be async)\n * @returns The result of the function\n *\n * @example\n * ```typescript\n * // Synchronous transaction\n * kv.transaction(() => {\n * kv.set('user:123', JSON.stringify({ name: 'John' }));\n * kv.set('user:456', JSON.stringify({ name: 'Jane' }));\n * // If any operation fails, all changes are rolled back\n * });\n *\n * // Async transaction\n * await kv.transaction(async () => {\n * kv.set('user:123', JSON.stringify({ name: 'John' }));\n * await someAsyncOperation();\n * kv.set('user:456', JSON.stringify({ name: 'Jane' }));\n * // If any operation fails, all changes are rolled back\n * });\n * ```\n */\n public async transaction<T>(fn: () => T | Promise<T>): Promise<T> {\n try {\n // Begin transaction\n this.statements.begin.run();\n\n // Execute the function\n const result = await fn();\n\n // Commit transaction\n this.statements.commit.run();\n\n return result;\n } catch (error) {\n // Rollback transaction on error\n this.statements.rollback.run();\n throw error;\n }\n }\n}\n\n/**\n * Opens a new KV instance\n *\n * @param path - Database file path, buffer, URL, or existing DatabaseSync instance\n * @param options - Configuration options for the KV store\n * @returns A new KV instance\n */\nexport function openKV(\n path: string | Buffer | URL | DatabaseSync = 'commandkit_kv.db',\n options: KvOptions = { enableWAL: true, namespace: 'commandkit_kv' },\n): KV {\n return new KV(path, options);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA6BA,IAAa,KAAb,MAAa,GAA0C;CACrD,AAAQ;CACR,AAAQ,aAA4C,CAAE;;;;;;;CAQtD,AAAO,YACP,MACQ,UAAqB;EAC3B,WAAW;EACX,WAAW;CACZ,GACD;EAJQ;AAKN,OAAK,KACL,gBAAgB,2BAChB,OACA,IAAI,yBAAa,MAAM,EAAE,MAAM,KAAM;AAErC,MAAI,QAAQ,UACV,MAAK,GAAG,MAAe,4BAA4B;AAGrD,OAAK,GACL,SACY;;;;;;MAOX,CACD,IAAI,QAAQ,aAAa,gBAAgB;AAEzC,OAAK,aAAa;GAChB,KAAK,KAAK,GAAG,SACD,+CACX;GACD,KAAK,KAAK,GAAG,SACD,oEACX;GACD,OAAO,KAAK,GAAG,SACH,oEACX;GACD,QAAQ,KAAK,GAAG,SAAkB,6BAA6B;GAC/D,KAAK,KAAK,GAAG,SACD,iFACX;GACD,MAAM,KAAK,GAAG,SACF,8DACX;GACD,QAAQ,KAAK,GAAG,SACJ,gEACX;GACD,OAAO,KAAK,GAAG,SAAkB,eAAe;GAChD,OAAO,KAAK,GAAG,SACH,mEACX;GACD,KAAK,KAAK,GAAG,SACD,qEACX;GACD,QAAQ,KAAK,GAAG,SACJ,2CACX;GACD,KAAK,KAAK,GAAG,SAAkB,wCAAwC;GACvE,YAAY,KAAK,GAAG,SACR,kFACX;GACD,OAAO,KAAK,GAAG,SAAkB,mBAAmB;GACpD,QAAQ,KAAK,GAAG,SAAkB,QAAQ;GAC1C,UAAU,KAAK,GAAG,SAAkB,UAAU;EAC/C;CACH;;;;CAKA,AAAQ,iBAAyB;AAC/B,SAAO,KAAK,KAAK;CACnB;;;;;;CAOA,AAAO,SAAkB;AACvB,SAAO,KAAK,GAAG;CACjB;;;;;;CAOA,AAAO,cAA4B;AACjC,SAAO,KAAK;CACd;;;;CAKA,AAAO,QAAc;AACnB,MAAI,KAAK,GAAG,OAAQ,MAAK,GAAG,OAAO;CACrC;;;;CAKA,CAAQ,OAAO,WAAW;AACxB,OAAK,OAAO;CACd;;;;CAKA,OAAc,OAAO,gBAAgB;AACnC,OAAK,OAAO;CACd;;;;;;;;;;;;;;;CAgBA,AAAO,IAAI,KAAiC;EAC1C,MAAM,SAAS,KAAK,WAAW,IAAI,IAAI,KAAK,qBAAqB,EAAE,IAAI;AAEvE,OAAK,OAAQ;AAGb,MACA,OAAO,cACP,OAAO,OAAO,WAAW,IAAI,KAAK,gBAAgB,EAClD;AACE,QAAK,OAAO,IAAI;AAChB;EACF;AAEA,SAAO,OAAO;CAChB;;;;;;;;;;;;;CAcA,AAAO,IAAI,KAAa,OAAqB;AAC3C,OAAK,WAAW,IAAI,IAAI,KAAK,qBAAqB,EAAE,KAAK,OAAO,KAAK;CACvE;;;;;;;;;;;;;;;;;CAkBA,AAAO,MAAM,KAAa,OAAe,KAAmB;EAC1D,MAAM,YAAY,KAAK,gBAAgB,GAAG;AAC1C,OAAK,WAAW,MAAM,IACpB,KAAK,qBAAqB,EAC1B,KACA,OACA,UACD;CACH;;;;;;;;;;;;;;;;;;CAmBA,AAAO,OAAO,KAAa,KAAsB;AAC/C,OAAK,KAAK,IAAI,IAAI,CAAE,QAAO;EAE3B,MAAM,YAAY,KAAK,gBAAgB,GAAG;AAC1C,OAAK,WAAW,OAAO,IAAI,KAAK,qBAAqB,EAAE,WAAW,IAAI;AACtE,SAAO;CACT;;;;;;;;;;;;;;;;;;;CAoBA,AAAO,IAAI,KAAqB;EAC9B,MAAM,SAAS,KAAK,WAAW,IAAI,IAAI,KAAK,qBAAqB,EAAE,IAAI;AAEvE,OAAK,OAAQ,QAAO;AAEpB,OAAK,OAAO,WAAY,QAAO;EAE/B,MAAM,YAAY,OAAO,OAAO,WAAW,GAAG,KAAK,gBAAgB;AACnE,SAAO,YAAY,IAAI,YAAY;CACrC;;;;;;;;;;;CAYA,AAAO,OAAO,KAAmB;AAC/B,OAAK,WAAW,OAAO,IAAI,KAAK,qBAAqB,EAAE,IAAI;CAC7D;;;;;;;;;;;;;;CAeA,AAAO,IAAI,KAAsB;EAC/B,MAAM,SAAS,KAAK,WAAW,IAAI,IACjC,KAAK,qBAAqB,EAC1B,KACA,KAAK,gBAAgB,CACtB;AAED,0DACE,OAAQ,qBACR,OAAO,UAAU,QACjB,OAAO,OAAO,MAAM,GAAG;CAE3B;;;;;;;;;;;;CAaA,AAAO,OAAiB;EACtB,MAAM,SAAS,KAAK,WAAW,KAAK,IAClC,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,CACtB;AAED,SAAO,OAAO,IAAI,CAAC,QAAQ,IAAI,IAAc;CAC/C;;;;;;;;;;;;CAaA,AAAO,SAAmB;EACxB,MAAM,SAAS,KAAK,WAAW,OAAO,IACpC,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,CACtB;AAED,SAAO,OAAO,IAAI,CAAC,QAAQ,IAAI,MAAgB;CACjD;;;;;;;;;;;;CAaA,AAAO,QAAgB;EACrB,MAAM,SAAS,KAAK,WAAW,MAAM,IACnC,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,CACtB;AAED,SAAO,wDAAO,OAAQ,UAAS,EAAE;CACnC;;;;;;;;;CAUA,AAAO,QAAc;AACnB,OAAK,WAAW,MAAM,IAAI,KAAK,qBAAqB,CAAC;CACvD;;;;;;;;;;;;;CAcA,AAAO,MAA8B;EACnC,MAAM,SAAS,KAAK,WAAW,IAAI,IACjC,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,CACtB;AAED,SAAO,OAAO,YACZ,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAe,IAAI,KAAgB,EAAC,CAC9D;CACH;;;;;;;;;;;;CAaA,AAAO,aAAuB;EAC5B,MAAM,SAAS,KAAK,WAAW,WAAW,KAAK;AAE/C,SAAO,OAAO,IAAI,CAAC,QAAQ,IAAI,KAAe;CAChD;;;;;;CAOA,AAAO,sBAA8B;AACnC,SAAO,KAAK,QAAQ,aAAa;CACnC;;;;;;;;;;;;;;;;CAiBA,AAAO,UAAU,WAAuB;AACtC,SAAO,IAAI,GAAG,KAAK,IAAI;GACrB,WAAW,KAAK,QAAQ;GACxB;EACD;CACH;;;;;;;;;;;;;;;;CAiBA,EAAS,OAAO,YAAwC;EACtD,MAAM,SAAS,KAAK,WAAW,IAAI,QACjC,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,CACtB;AAED,OAAK,MAAM,OAAO,OAChB,OAAM,CAAC,IAAI,KAAe,IAAI,KAAgB;CAElD;;;;;;;;;;;;;;;;;;;;;;;;;CA0BA,MAAa,YAAe,IAAsC;AAChE,MAAI;AAEF,QAAK,WAAW,MAAM,KAAK;GAG3B,MAAM,SAAS,MAAM,IAAI;AAGzB,QAAK,WAAW,OAAO,KAAK;AAE5B,UAAO;EACR,SAAQ,OAAO;AAEd,QAAK,WAAW,SAAS,KAAK;AAC9B,SAAM;EACR;CACF;AACF;;;;;;;;AASA,SAAgB,OAChB,OAA6C,oBAC7C,UAAqB;CAAE,WAAW;CAAM,WAAW;AAAiB,GAC/D;AACH,QAAO,IAAI,GAAG,MAAM;AACtB"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
/**
|
|
7
7
|
* The current version of CommandKit.
|
|
8
8
|
*/
|
|
9
|
-
const version = "1.0.0-dev.
|
|
9
|
+
const version = "1.0.0-dev.20250702125326";
|
|
10
10
|
|
|
11
11
|
//#endregion
|
|
12
12
|
Object.defineProperty(exports, 'version', {
|
|
@@ -15,4 +15,4 @@ Object.defineProperty(exports, 'version', {
|
|
|
15
15
|
return version;
|
|
16
16
|
}
|
|
17
17
|
});
|
|
18
|
-
//# sourceMappingURL=version-
|
|
18
|
+
//# sourceMappingURL=version-DvvD35ov.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-
|
|
1
|
+
{"version":3,"file":"version-DvvD35ov.js","names":[],"sources":["../src/version.ts"],"sourcesContent":["/**\n * @private\n */\nfunction $version(): string {\n 'use macro';\n return require('../package.json').version;\n}\n\n/**\n * The current version of CommandKit.\n */\nexport const version: string = $version();\n"],"mappings":";;;;;;;;AAWA,MAAa,UAA4B"}
|
package/dist/version.js
CHANGED
package/kv.cjs
ADDED
package/kv.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dist/kv/kv';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "commandkit",
|
|
3
3
|
"description": "Beginner friendly command & event handler for Discord.js",
|
|
4
|
-
"version": "1.0.0-dev.
|
|
4
|
+
"version": "1.0.0-dev.20250702125326",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -44,7 +44,9 @@
|
|
|
44
44
|
"./semaphore.cjs",
|
|
45
45
|
"./semaphore.d.ts",
|
|
46
46
|
"./mutex.cjs",
|
|
47
|
-
"./mutex.d.ts"
|
|
47
|
+
"./mutex.d.ts",
|
|
48
|
+
"./kv.cjs",
|
|
49
|
+
"./kv.d.ts"
|
|
48
50
|
],
|
|
49
51
|
"exports": {
|
|
50
52
|
".": {
|
|
@@ -136,6 +138,11 @@
|
|
|
136
138
|
"require": "./mutex.cjs",
|
|
137
139
|
"import": "./mutex.cjs",
|
|
138
140
|
"types": "./mutex.d.ts"
|
|
141
|
+
},
|
|
142
|
+
"./kv": {
|
|
143
|
+
"require": "./kv.cjs",
|
|
144
|
+
"import": "./kv.cjs",
|
|
145
|
+
"types": "./kv.d.ts"
|
|
139
146
|
}
|
|
140
147
|
},
|
|
141
148
|
"repository": {
|
|
@@ -171,7 +178,7 @@
|
|
|
171
178
|
"tsx": "^4.19.2",
|
|
172
179
|
"typescript": "^5.7.3",
|
|
173
180
|
"vitest": "^3.0.5",
|
|
174
|
-
"tsconfig": "0.0.0-dev.
|
|
181
|
+
"tsconfig": "0.0.0-dev.20250702125326"
|
|
175
182
|
},
|
|
176
183
|
"peerDependencies": {
|
|
177
184
|
"discord.js": "^14"
|