node-sqlite-kv 0.3.1 → 1.0.0

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,11 @@
1
+ {
2
+ "arrowParens": "always",
3
+ "jsxSingleQuote": false,
4
+ "printWidth": 90,
5
+ "quoteProps": "as-needed",
6
+ "semi": false,
7
+ "singleQuote": false,
8
+ "tabWidth": 4,
9
+ "trailingComma": "es5",
10
+ "useTabs": false
11
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "prettier.configPath": ".prettierrc.json",
3
+ "prettier.prettierPath": "node_modules/prettier"
4
+ }
package/LICENSE CHANGED
@@ -1,7 +1,24 @@
1
- Copyright 2026 Andrew (e60m5ss / wlix)
1
+ This is free and unencumbered software released into the public domain.
2
2
 
3
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
4
7
 
5
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
6
15
 
7
- THE SOFTWARE IS PROVIDED AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <https://unlicense.org/>
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  <h1 align="center">node-sqlite-kv</h1>
2
2
 
3
- > Key-value store with node:sqlite (Node.js v22.5.0 or higher is required)
3
+ A simple key-value store with `node:sqlite`.
4
+
5
+ > ⚠️ Node.js v22 or higher is required.
4
6
 
5
7
  ## Installation
6
8
 
@@ -17,46 +19,56 @@ bun add node-sqlite-kv
17
19
  ## Example
18
20
 
19
21
  ```js
20
- import { KVSync } from "node-sqlite-kv";
22
+ import { JournalModes, KVSync } from "node-sqlite-kv"
21
23
 
24
+ // none of these options are required
22
25
  const kv = new KVSync({
23
- // use :memory: for in-memory storage
24
- // path is optional, defaults to :memory:
26
+ // sqlite journal mode; defaults to DELETE for
27
+ // in-memory stores, or WAL for persistent ones
28
+ journalMode: JournalModes.WAL,
29
+
30
+ // whether the database is open upon
31
+ // being instantiated; defaults to true
32
+ open: true,
33
+
34
+ // defaults to :memory: (in-memory storage)
25
35
  path: "./data.sqlite",
26
36
 
27
- // optional journal mode
28
- // default: DELETE
29
- journalMode: "WAL",
30
- });
37
+ // override the default table name of "kv"
38
+ // note: it's not recommended to use one file for
39
+ // multiple key value stores; this is only
40
+ // for the ability of changing the default name
41
+ tableName: "kv",
42
+ })
31
43
 
32
44
  // set values
33
- kv.set("number", 123);
34
- kv.set("string", "hello world");
35
- kv.set("boolean", true);
36
- kv.set("null", null);
37
- kv.set("array", [1, 2, 3]);
38
- kv.set("object", { settings: { theme: "dark" } });
39
- kv.set("date", new Date());
45
+ kv.set("number", 123)
46
+ kv.set("string", "hello world")
47
+ kv.set("boolean", true)
48
+ kv.set("null", null)
49
+ kv.set("array", [1, 2, 3])
50
+ kv.set("object", { settings: { theme: "dark" } })
51
+ kv.set("date", new Date())
40
52
 
41
53
  // get values
42
- kv.get("number"); // 123
43
- kv.get("string"); // "hello world"
44
- kv.get("boolean"); // true
45
- kv.get("null"); // null
46
- kv.get("array"); // [1, 2, 3]
47
- kv.get("object"); // { settings: { theme: "dark" } }
48
- kv.get("date"); // Date
54
+ kv.get("number") // 123
55
+ kv.get("string") // "hello world"
56
+ kv.get("boolean") // true
57
+ kv.get("null") // null
58
+ kv.get("array") // [1, 2, 3]
59
+ kv.get("object") // { settings: { theme: "dark" } }
60
+ kv.get("date") // Date
49
61
 
50
62
  // update values
51
- kv.set("number", 999);
52
- kv.get("number"); // 999
63
+ kv.set("number", 999)
64
+ kv.get("number") // 999
53
65
 
54
66
  // delete values
55
- kv.delete("array"); // [1, 2, 3]
56
- kv.get("array"); // null
67
+ kv.delete("array")
68
+ kv.get("array") // undefined
57
69
 
58
70
  // list all entries
59
- kv.all();
71
+ kv.all()
60
72
  // [
61
73
  // { key: "string", value: "hello world" },
62
74
  // { key: "number", value: 999 },
@@ -64,26 +76,59 @@ kv.all();
64
76
  // // ...
65
77
  // ];
66
78
 
79
+ // check if a key exists
80
+ kv.exists("string") // true
81
+ kv.exists("nonexistent") // false
82
+
83
+ // get total number of entries
84
+ kv.size() // 6
85
+
86
+ // get all keys
87
+ kv.keys() // ["string", "number", "boolean", "null", "object", "date"]
88
+
89
+ // get all values
90
+ kv.values() // ["hello world", 999, true, null, { settings: { theme: "dark" } }, Date]
91
+
67
92
  // transactions
68
- kv.set("user:1", { name: "Andrew", age: 19 });
69
- kv.set("user:2", { name: "Josh", age: 22 });
70
- kv.set("user:3", { name: "Gabe", age: 20 });
93
+ kv.set("user:1", { name: "Andrew", age: 19 })
94
+ kv.set("user:2", { name: "Josh", age: 22 })
95
+ kv.set("user:3", { name: "Gabe", age: 20 })
71
96
 
72
97
  // ...store what changed in transactions
73
98
  const { oldValues, newValues } = kv.transaction((tx) => {
74
- tx.set("user:1", { name: "Andrew", age: 20 });
75
- tx.set("user:4", { name: "Kris", age: 21 });
76
- tx.delete("user:2");
77
- });
99
+ tx.set("user:1", { name: "Andrew", age: 20 })
100
+ tx.set("user:4", { name: "Kris", age: 21 })
101
+ tx.delete("user:2")
102
+ })
78
103
 
79
104
  // delete all entries
80
- kv.clear();
105
+ kv.clear()
106
+
107
+ // close the database
108
+ kv.close()
109
+ ```
110
+
111
+ ### TS Generics Example
112
+
113
+ ```ts
114
+ import { KVSync } from "node-sqlite-kv"
115
+ const kv = new KVSync({ path: "./data.sqlite" })
116
+
117
+ interface User {
118
+ name: string
119
+ }
120
+
121
+ kv.set("user", { name: "Andrew" })
122
+ kv.get<User>("user") // User | null
123
+
124
+ kv.set("example", 123)
125
+ kv.get<number>("example") // number | null
81
126
  ```
82
127
 
83
128
  ## Contributing
84
129
 
85
- Pull requests are always welcomed. For more major changes, please open an issue to discuss what you wish to change.
130
+ [pnpm](https://pnpm.io) is used throughout this project for packages and scripts. Pull requests are always welcome. For more major changes, please open an issue to discuss what you wish to change.
86
131
 
87
132
  ## License
88
133
 
89
- [MIT](LICENSE)
134
+ [Unlicensed](LICENSE)
package/dist/index.cjs ADDED
@@ -0,0 +1,250 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) {
14
+ __defProp(to, key, {
15
+ get: ((k) => from[k]).bind(null, key),
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ }
19
+ }
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
24
+ value: mod,
25
+ enumerable: true
26
+ }) : target, mod));
27
+
28
+ //#endregion
29
+ let node_sqlite = require("node:sqlite");
30
+ let node_v8 = require("node:v8");
31
+ let node_fs = require("node:fs");
32
+ node_fs = __toESM(node_fs);
33
+ let node_path = require("node:path");
34
+ node_path = __toESM(node_path);
35
+
36
+ //#region src/classes/kv-error.ts
37
+ /** Class representing a KVError */
38
+ var KVError = class extends Error {
39
+ static name = "KVError";
40
+ scope;
41
+ constructor(scope, ...args) {
42
+ super(args.join(" "));
43
+ this.scope = scope;
44
+ Error.captureStackTrace?.(this, this.constructor);
45
+ }
46
+ get name() {
47
+ return `${this.constructor.name} (${this.scope})`;
48
+ }
49
+ };
50
+
51
+ //#endregion
52
+ //#region src/constants.ts
53
+ /** List of journal modes SQLite supports */
54
+ const JournalModes = {
55
+ Delete: "DELETE",
56
+ Memory: "MEMORY",
57
+ OFF: "OFF",
58
+ Persist: "PERSIST",
59
+ Truncate: "TRUNCATE",
60
+ WAL: "WAL"
61
+ };
62
+
63
+ //#endregion
64
+ //#region src/classes/kv-sync.ts
65
+ /** Class representing a synchronous key-value store */
66
+ var KVSync = class {
67
+ #db;
68
+ /**
69
+ * The name of the table with keys and values
70
+ * @default "kv"
71
+ */
72
+ tableName = "kv";
73
+ /**
74
+ * Instantiate a new key-value store
75
+ * @param props KVSync options
76
+ */
77
+ constructor(props) {
78
+ const dbPath = props?.path ?? ":memory:";
79
+ if (dbPath !== ":memory:") node_fs.default.mkdirSync(node_path.default.dirname(dbPath), { recursive: true });
80
+ this.tableName = props?.tableName ?? "kv";
81
+ this.#db = new node_sqlite.DatabaseSync(dbPath, { open: props?.open ?? true });
82
+ if (props?.open !== false) {
83
+ this.setJournalMode(props?.journalMode ?? (dbPath !== ":memory:" ? JournalModes.WAL : JournalModes.Delete));
84
+ this.#db.exec(`CREATE TABLE IF NOT EXISTS ${this.tableName} (key TEXT PRIMARY KEY NOT NULL, value BLOB NOT NULL) STRICT`);
85
+ }
86
+ }
87
+ /**
88
+ * Set a key in the database
89
+ * @param key Key name
90
+ * @param value Key value
91
+ * @returns Provided value
92
+ */
93
+ set(key, value) {
94
+ if (!this.#db.isOpen) throw new KVError("set", "Database is not open");
95
+ if (!key || typeof key !== "string") throw new KVError("set", "Key must be provided and be a non-empty string");
96
+ if (value === void 0) throw new KVError("set", "Provided value is undefined, did you mean to use delete()?");
97
+ this.#db.prepare(`INSERT OR REPLACE INTO ${this.tableName} (key, value) VALUES (?, ?)`).run(key, (0, node_v8.serialize)(value));
98
+ return value;
99
+ }
100
+ /**
101
+ * Get a value from the database
102
+ * @param key Key name
103
+ * @returns Value or undefined
104
+ */
105
+ get(key) {
106
+ if (!this.#db.isOpen) throw new KVError("get", "Database is not open");
107
+ if (!key || typeof key !== "string") throw new KVError("get", "Key must be provided and be a non-empty string.");
108
+ const row = this.#db.prepare(`SELECT value FROM ${this.tableName} WHERE key = ?`).get(key);
109
+ return row ? (0, node_v8.deserialize)(row.value) : void 0;
110
+ }
111
+ /**
112
+ * Delete a key from the database
113
+ * @param key Key name
114
+ * @returns KVSync instance
115
+ */
116
+ delete(key) {
117
+ if (!this.#db.isOpen) throw new KVError("delete", "Database is not open");
118
+ if (!key || typeof key !== "string") throw new KVError("delete", "Key must be provided and be a non-empty string.");
119
+ this.#db.prepare(`DELETE FROM ${this.tableName} WHERE key = ?`).run(key);
120
+ return this;
121
+ }
122
+ /**
123
+ * Get all data in the database
124
+ * @returns Array of objects containing keys and values
125
+ */
126
+ all(filter) {
127
+ if (!this.#db.isOpen) throw new KVError("all", "Database is not open");
128
+ const result = [];
129
+ const rows = this.#db.prepare(`SELECT key, value FROM ${this.tableName}`).iterate();
130
+ for (const row of rows) {
131
+ const key = row.key;
132
+ const value = (0, node_v8.deserialize)(row.value);
133
+ if (!filter || filter(key, value)) result.push({
134
+ key,
135
+ value
136
+ });
137
+ }
138
+ return result;
139
+ }
140
+ /**
141
+ * Remove all entries from the database
142
+ */
143
+ clear() {
144
+ if (!this.#db.isOpen) throw new KVError("clear", "Database is not open");
145
+ this.#db.exec(`DELETE FROM ${this.tableName}`);
146
+ return this;
147
+ }
148
+ /**
149
+ * Update the journal mode
150
+ * @param mode New journal mode
151
+ */
152
+ setJournalMode(mode) {
153
+ if (!this.#db.isOpen) throw new KVError("setJournalMode", "Database is not open");
154
+ if (!Object.values(JournalModes).includes(mode)) throw new KVError("setJournalMode", `Invalid journal mode specified - received: "${mode}", expected one of: ${Object.values(JournalModes).join(", ")}`);
155
+ this.#db.exec(`PRAGMA journal_mode = ${mode}`);
156
+ return this;
157
+ }
158
+ /**
159
+ * Perform a transaction
160
+ * @param callback Callback with KVSync instance
161
+ * @returns Object containing oldValues and newValues each containing arrays of keys and values
162
+ */
163
+ transaction(callback) {
164
+ if (!this.#db.isOpen) throw new KVError("transaction", "Database is not open");
165
+ if (!callback) throw new KVError("transaction", "A callback must be provided when using transaction().");
166
+ if (typeof callback !== "function") throw new KVError("transaction", `Transaction callback must be of type function. Received: ${typeof callback}`);
167
+ const oldMap = /* @__PURE__ */ new Map();
168
+ const newMap = /* @__PURE__ */ new Map();
169
+ const tx = Object.create(this);
170
+ tx.set = (key, value) => {
171
+ if (!oldMap.has(key)) {
172
+ const oldValue = this.get(key);
173
+ oldMap.set(key, oldValue);
174
+ }
175
+ newMap.set(key, value);
176
+ return value;
177
+ };
178
+ tx.delete = (key) => {
179
+ if (!oldMap.has(key)) {
180
+ const oldValue = this.get(key);
181
+ oldMap.set(key, oldValue);
182
+ }
183
+ newMap.set(key, void 0);
184
+ return tx;
185
+ };
186
+ try {
187
+ this.#db.exec("BEGIN TRANSACTION");
188
+ callback(tx);
189
+ for (const [key, value] of newMap.entries()) if (value === void 0) this.delete(key);
190
+ else this.set(key, value);
191
+ this.#db.exec("COMMIT");
192
+ } catch (error) {
193
+ this.#db.exec("ROLLBACK");
194
+ throw error;
195
+ }
196
+ return {
197
+ oldValues: Array.from(oldMap.entries()).map(([key, value]) => ({
198
+ key,
199
+ value
200
+ })),
201
+ newValues: Array.from(newMap.entries()).map(([key, value]) => ({
202
+ key,
203
+ value
204
+ }))
205
+ };
206
+ }
207
+ /**
208
+ * Check if a key exists
209
+ * @param key Key name
210
+ * @returns Boolean representing whether a key exists
211
+ */
212
+ exists(key) {
213
+ if (!this.#db.isOpen) throw new KVError("exists", "Database is not open");
214
+ if (!key || typeof key !== "string") throw new KVError("exists", "Key must be provided and be a non-empty string.");
215
+ return this.#db.prepare(`SELECT 1 FROM ${this.tableName} WHERE key = ?`).get(key) !== void 0;
216
+ }
217
+ /** Get total number of entries in the database */
218
+ size() {
219
+ if (!this.#db.isOpen) throw new KVError("size", "Database is not open");
220
+ return this.#db.prepare(`SELECT COUNT(*) as count FROM ${this.tableName}`).get().count;
221
+ }
222
+ /** Get all keys in the database */
223
+ keys() {
224
+ if (!this.#db.isOpen) throw new KVError("keys", "Database is not open");
225
+ return this.#db.prepare(`SELECT key FROM ${this.tableName}`).all().map((row) => row.key);
226
+ }
227
+ /** Get all values in the database */
228
+ values() {
229
+ if (!this.#db.isOpen) throw new KVError("values", "Database is not open");
230
+ return this.#db.prepare(`SELECT value FROM ${this.tableName}`).all().map((row) => (0, node_v8.deserialize)(row.value));
231
+ }
232
+ /** Open the database */
233
+ open() {
234
+ if (this.#db.isOpen) throw new KVError("open", "Database is already open");
235
+ this.#db.open();
236
+ this.#db.exec(`CREATE TABLE IF NOT EXISTS ${this.tableName} (key TEXT PRIMARY KEY NOT NULL, value BLOB NOT NULL) STRICT`);
237
+ return this;
238
+ }
239
+ /** Close the database */
240
+ close() {
241
+ if (!this.#db.isOpen) throw new KVError("close", "Database is not open");
242
+ this.#db.close();
243
+ return this;
244
+ }
245
+ };
246
+
247
+ //#endregion
248
+ exports.JournalModes = JournalModes;
249
+ exports.KVError = KVError;
250
+ exports.KVSync = KVSync;
@@ -0,0 +1,121 @@
1
+ //#region src/constants.d.ts
2
+ /** List of journal modes SQLite supports */
3
+ declare const JournalModes: {
4
+ readonly Delete: "DELETE";
5
+ readonly Memory: "MEMORY";
6
+ readonly OFF: "OFF";
7
+ readonly Persist: "PERSIST";
8
+ readonly Truncate: "TRUNCATE";
9
+ readonly WAL: "WAL";
10
+ };
11
+ //#endregion
12
+ //#region src/types.d.ts
13
+ /**
14
+ * SQLite journal mode
15
+ * @default DELETE (:memory: databases)
16
+ * @default WAL (persistent databases)
17
+ */
18
+ type JournalMode = (typeof JournalModes)[keyof typeof JournalModes];
19
+ /** KVSync configuration options */
20
+ interface KVSyncProps {
21
+ journalMode?: JournalMode;
22
+ open?: boolean;
23
+ path?: SQLitePath;
24
+ tableName?: string;
25
+ }
26
+ /** File path, or :memory: (for SQLite use) */
27
+ type SQLitePath = ":memory:" | (string & {});
28
+ //#endregion
29
+ //#region src/classes/kv-error.d.ts
30
+ /** Class representing a KVError */
31
+ declare class KVError extends Error {
32
+ static name: string;
33
+ readonly scope: string;
34
+ constructor(scope: string, ...args: unknown[]);
35
+ get name(): string;
36
+ }
37
+ //#endregion
38
+ //#region src/classes/kv-sync.d.ts
39
+ /** Class representing a synchronous key-value store */
40
+ declare class KVSync<T = any> {
41
+ #private;
42
+ /**
43
+ * The name of the table with keys and values
44
+ * @default "kv"
45
+ */
46
+ tableName: string;
47
+ /**
48
+ * Instantiate a new key-value store
49
+ * @param props KVSync options
50
+ */
51
+ constructor(props?: KVSyncProps);
52
+ /**
53
+ * Set a key in the database
54
+ * @param key Key name
55
+ * @param value Key value
56
+ * @returns Provided value
57
+ */
58
+ set<K = T>(key: string, value: K | undefined): K;
59
+ /**
60
+ * Get a value from the database
61
+ * @param key Key name
62
+ * @returns Value or undefined
63
+ */
64
+ get<K = T>(key: string): K | undefined;
65
+ /**
66
+ * Delete a key from the database
67
+ * @param key Key name
68
+ * @returns KVSync instance
69
+ */
70
+ delete(key: string): KVSync;
71
+ /**
72
+ * Get all data in the database
73
+ * @returns Array of objects containing keys and values
74
+ */
75
+ all<K = T>(filter?: (key: string, value: K) => boolean): {
76
+ key: string;
77
+ value: K;
78
+ }[];
79
+ /**
80
+ * Remove all entries from the database
81
+ */
82
+ clear(): KVSync;
83
+ /**
84
+ * Update the journal mode
85
+ * @param mode New journal mode
86
+ */
87
+ setJournalMode(mode: JournalMode): this;
88
+ /**
89
+ * Perform a transaction
90
+ * @param callback Callback with KVSync instance
91
+ * @returns Object containing oldValues and newValues each containing arrays of keys and values
92
+ */
93
+ transaction<R>(callback: (kv: KVSync<T>) => R): {
94
+ oldValues: {
95
+ key: string;
96
+ value: T | undefined;
97
+ }[];
98
+ newValues: {
99
+ key: string;
100
+ value: T | undefined;
101
+ }[];
102
+ };
103
+ /**
104
+ * Check if a key exists
105
+ * @param key Key name
106
+ * @returns Boolean representing whether a key exists
107
+ */
108
+ exists(key: string): boolean;
109
+ /** Get total number of entries in the database */
110
+ size(): number;
111
+ /** Get all keys in the database */
112
+ keys(): string[];
113
+ /** Get all values in the database */
114
+ values<K = T>(): K[];
115
+ /** Open the database */
116
+ open(): KVSync;
117
+ /** Close the database */
118
+ close(): KVSync;
119
+ }
120
+ //#endregion
121
+ export { JournalMode, JournalModes, KVError, KVSync, KVSyncProps, SQLitePath };
package/package.json CHANGED
@@ -1,40 +1,33 @@
1
1
  {
2
2
  "name": "node-sqlite-kv",
3
3
  "description": "Key-value store with node:sqlite",
4
- "version": "0.3.1",
4
+ "version": "1.0.0",
5
+ "license": "UNLICENSED",
5
6
  "repository": {
6
- "url": "https://github.com/e60m5ss/node-sqlite-kv"
7
+ "url": "https://github.com/andrewdku/node-sqlite-kv"
7
8
  },
8
9
  "author": {
9
- "name": "e60m5ss",
10
- "url": "https://github.com/e60m5ss"
10
+ "name": "andrewdku",
11
+ "url": "https://github.com/andrewdku"
11
12
  },
12
- "main": "./dist/index.js",
13
- "module": "./dist/index.mjs",
14
- "types": "./dist/index.d.ts",
13
+ "main": "./dist/index.cjs",
14
+ "exports": "./dist/index.cjs",
15
+ "types": "./dist/index.d.cts",
16
+ "type": "module",
15
17
  "engineStrict": true,
16
18
  "engines": {
17
19
  "node": ">=22.5.0"
18
20
  },
19
- "prettier": {
20
- "jsxSingleQuote": false,
21
- "printWidth": 85,
22
- "semi": true,
23
- "singleQuote": false,
24
- "tabWidth": 4,
25
- "trailingComma": "es5",
26
- "useTabs": false
27
- },
28
21
  "devDependencies": {
29
- "@types/node": "^25.2.0",
22
+ "@types/node": "^25.5.0",
30
23
  "prettier": "^3.8.1",
31
- "tsup": "^8.5.1",
24
+ "tsdown": "^0.21.4",
32
25
  "typescript": "^5.9.3"
33
26
  },
34
27
  "scripts": {
35
- "build": "tsup",
36
- "format": "prettier ./src --write --ignore-path=.prettierignore",
28
+ "build": "tsdown -c tsdown.config.mjs",
29
+ "format": "prettier --write . --config .prettierrc.json",
37
30
  "lint": "tsc --noEmit; prettier ./src --check --ignore-path=.prettierignore",
38
- "prepublish": "tsup"
31
+ "prepublish": "tsdown -c tsdown.config.mjs"
39
32
  }
40
33
  }
@@ -0,0 +1,17 @@
1
+ // @ts-check
2
+
3
+ import { defineConfig } from "tsdown"
4
+
5
+ export default defineConfig({
6
+ cjsDefault: true,
7
+ clean: true,
8
+ deps: { skipNodeModulesBundle: true },
9
+ dts: true,
10
+ entry: ["src/index.ts"],
11
+ format: ["cjs"],
12
+ minify: false,
13
+ platform: "node",
14
+ removeNodeProtocol: false,
15
+ shims: true,
16
+ target: "node22",
17
+ })
package/dist/index.d.mts DELETED
@@ -1,32 +0,0 @@
1
- type JournalMode = "DELETE" | "MEMORY" | "OFF" | "PERSIST" | "TRUNCATE" | "WAL";
2
- interface KVSyncOptions {
3
- path?: SQLitePath;
4
- journalMode?: JournalMode;
5
- }
6
- type SQLitePath = ":memory:" | (string & {});
7
- declare const journalModes: JournalMode[];
8
- declare class KVSync<T = any> {
9
- #private;
10
- constructor(options?: KVSyncOptions);
11
- set<K = T>(key: string, value: K | undefined): K;
12
- get<K = T>(key: string): K | null;
13
- delete(key: string): KVSync;
14
- all<K = T>(filter?: (key: string, value: K) => boolean): {
15
- key: string;
16
- value: K;
17
- }[];
18
- clear(): KVSync;
19
- setJournalMode(mode: JournalMode): this;
20
- transaction<R>(callback: (kv: KVSync<T>) => R): {
21
- oldValues: {
22
- key: string;
23
- value: T | null | undefined;
24
- }[];
25
- newValues: {
26
- key: string;
27
- value: T | null;
28
- }[];
29
- };
30
- }
31
-
32
- export { type JournalMode, KVSync, type KVSyncOptions, type SQLitePath, journalModes };
package/dist/index.d.ts DELETED
@@ -1,32 +0,0 @@
1
- type JournalMode = "DELETE" | "MEMORY" | "OFF" | "PERSIST" | "TRUNCATE" | "WAL";
2
- interface KVSyncOptions {
3
- path?: SQLitePath;
4
- journalMode?: JournalMode;
5
- }
6
- type SQLitePath = ":memory:" | (string & {});
7
- declare const journalModes: JournalMode[];
8
- declare class KVSync<T = any> {
9
- #private;
10
- constructor(options?: KVSyncOptions);
11
- set<K = T>(key: string, value: K | undefined): K;
12
- get<K = T>(key: string): K | null;
13
- delete(key: string): KVSync;
14
- all<K = T>(filter?: (key: string, value: K) => boolean): {
15
- key: string;
16
- value: K;
17
- }[];
18
- clear(): KVSync;
19
- setJournalMode(mode: JournalMode): this;
20
- transaction<R>(callback: (kv: KVSync<T>) => R): {
21
- oldValues: {
22
- key: string;
23
- value: T | null | undefined;
24
- }[];
25
- newValues: {
26
- key: string;
27
- value: T | null;
28
- }[];
29
- };
30
- }
31
-
32
- export { type JournalMode, KVSync, type KVSyncOptions, type SQLitePath, journalModes };
package/dist/index.js DELETED
@@ -1,220 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
- var __export = (target, all) => {
10
- for (var name in all)
11
- __defProp(target, name, { get: all[name], enumerable: true });
12
- };
13
- var __copyProps = (to, from, except, desc) => {
14
- if (from && typeof from === "object" || typeof from === "function") {
15
- for (let key of __getOwnPropNames(from))
16
- if (!__hasOwnProp.call(to, key) && key !== except)
17
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
- }
19
- return to;
20
- };
21
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
- // If the importer is in node compatibility mode or this is not an ESM
23
- // file that has been converted to a CommonJS file using a Babel-
24
- // compatible transform (i.e. "__esModule" has not been set), then set
25
- // "default" to the CommonJS "module.exports" for node compatibility.
26
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
- mod
28
- ));
29
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
-
31
- // src/index.ts
32
- var index_exports = {};
33
- __export(index_exports, {
34
- KVSync: () => KVSync,
35
- journalModes: () => journalModes
36
- });
37
- module.exports = __toCommonJS(index_exports);
38
- var import_node_sqlite = require("node:sqlite");
39
- var import_node_v8 = require("node:v8");
40
- var import_node_fs = __toESM(require("node:fs"));
41
- var import_node_path = __toESM(require("node:path"));
42
- var journalModes = [
43
- "DELETE",
44
- "MEMORY",
45
- "OFF",
46
- "PERSIST",
47
- "TRUNCATE",
48
- "WAL"
49
- ];
50
- var KVSync = class {
51
- static {
52
- __name(this, "KVSync");
53
- }
54
- #db;
55
- /**
56
- * Instantiate a new key-value store
57
- * @param path Where the database is stored, or `:memory:` for in-memory storage
58
- */
59
- constructor(options) {
60
- const dbPath = options?.path ?? ":memory:";
61
- if (dbPath !== ":memory:") {
62
- import_node_fs.default.mkdirSync(import_node_path.default.dirname(dbPath), { recursive: true });
63
- }
64
- this.#db = new import_node_sqlite.DatabaseSync(dbPath);
65
- this.setJournalMode(options?.journalMode ?? "DELETE");
66
- this.#db.exec(
67
- "CREATE TABLE IF NOT EXISTS kv (key TEXT PRIMARY KEY NOT NULL, value BLOB NOT NULL) STRICT;"
68
- );
69
- }
70
- /**
71
- * Set a key in the database
72
- * @param key Key name
73
- * @param value Key value
74
- * @returns Provided value
75
- */
76
- set(key, value) {
77
- if (!key || typeof key !== "string") {
78
- throw new Error(
79
- "[KVSync]: Key must be provided and be a non-empty string."
80
- );
81
- }
82
- if (value === void 0) {
83
- throw new Error(
84
- "[KVSync]: Provided value is undefined. Did you mean to use delete() instead?"
85
- );
86
- }
87
- this.#db.prepare("INSERT OR REPLACE INTO kv (key, value) VALUES (?, ?)").run(key, (0, import_node_v8.serialize)(value));
88
- return value;
89
- }
90
- /**
91
- * Get a value from the database
92
- * @param key Key name
93
- * @returns Value or null
94
- */
95
- get(key) {
96
- if (!key || typeof key !== "string") {
97
- throw new Error(
98
- "[KVSync]: Key must be provided and be a non-empty string."
99
- );
100
- }
101
- const row = this.#db.prepare("SELECT value FROM kv WHERE key = ?").get(key);
102
- return row ? (0, import_node_v8.deserialize)(row.value) : null;
103
- }
104
- /**
105
- * Delete a key from the database
106
- * @param key Key name
107
- * @returns KVSync instance
108
- */
109
- delete(key) {
110
- if (!key || typeof key !== "string") {
111
- throw new Error(
112
- "[KVSync]: Key must be provided and be a non-empty string."
113
- );
114
- }
115
- this.#db.prepare("DELETE FROM kv WHERE key = ?").run(key);
116
- return this;
117
- }
118
- /**
119
- * Get all data in the database
120
- * @returns Array of objects containing keys and values
121
- */
122
- all(filter) {
123
- const rows = this.#db.prepare("SELECT key, value FROM kv").iterate();
124
- const result = [];
125
- for (const row of rows) {
126
- const key = row.key;
127
- const value = (0, import_node_v8.deserialize)(row.value);
128
- if (!filter || filter(key, value)) {
129
- result.push({ key, value });
130
- }
131
- }
132
- return result;
133
- }
134
- /**
135
- * Remove all entries from the database
136
- */
137
- clear() {
138
- this.#db.exec("DELETE FROM kv;");
139
- return this;
140
- }
141
- /**
142
- * Update the journal mode
143
- * @param mode New journal mode
144
- */
145
- setJournalMode(mode) {
146
- if (!journalModes.includes(mode)) {
147
- throw new Error(
148
- `[KVSync]: Invalid journal mode specified. Received: "${mode}", expected one of: ${journalModes.join(", ")}`
149
- );
150
- }
151
- this.#db.exec(`PRAGMA journal_mode = ${mode};`);
152
- return this;
153
- }
154
- /**
155
- * Perform a transaction
156
- * @param callback Callback with KVSync instance
157
- * @returns Object containing oldValues and newValues each containing arrays of keys and values
158
- */
159
- transaction(callback) {
160
- if (!callback) {
161
- throw new Error(
162
- "[KVSync]: A callback must be provided when using transaction()."
163
- );
164
- }
165
- if (typeof callback !== "function") {
166
- throw new Error(
167
- `[KVSync]: Transaction callback must be of type function. Received: ${typeof callback}`
168
- );
169
- }
170
- const oldMap = /* @__PURE__ */ new Map();
171
- const newMap = /* @__PURE__ */ new Map();
172
- const tx = Object.create(this);
173
- tx.set = (key, value) => {
174
- if (!oldMap.has(key)) {
175
- const oldValue = this.get(key);
176
- oldMap.set(key, oldValue === null ? void 0 : oldValue);
177
- }
178
- newMap.set(key, value);
179
- return value ?? null;
180
- };
181
- tx.delete = (key) => {
182
- if (!oldMap.has(key)) {
183
- const oldValue = this.get(key);
184
- oldMap.set(key, oldValue === null ? void 0 : oldValue);
185
- }
186
- newMap.set(key, null);
187
- return tx;
188
- };
189
- try {
190
- callback(tx);
191
- this.#db.exec("BEGIN TRANSACTION;");
192
- for (const [key, value] of newMap.entries()) {
193
- if (value === null) {
194
- this.delete(key);
195
- } else {
196
- this.set(key, value);
197
- }
198
- }
199
- this.#db.exec("COMMIT;");
200
- } catch (error) {
201
- this.#db.exec("ROLLBACK;");
202
- throw error;
203
- }
204
- return {
205
- oldValues: Array.from(oldMap.entries()).map(([key, value]) => ({
206
- key,
207
- value
208
- })),
209
- newValues: Array.from(newMap.entries()).map(([key, value]) => ({
210
- key,
211
- value
212
- }))
213
- };
214
- }
215
- };
216
- // Annotate the CommonJS export names for ESM import in node:
217
- 0 && (module.exports = {
218
- KVSync,
219
- journalModes
220
- });
package/dist/index.mjs DELETED
@@ -1,186 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
-
4
- // src/index.ts
5
- import { DatabaseSync } from "node:sqlite";
6
- import { serialize, deserialize } from "node:v8";
7
- import fs from "node:fs";
8
- import path from "node:path";
9
- var journalModes = [
10
- "DELETE",
11
- "MEMORY",
12
- "OFF",
13
- "PERSIST",
14
- "TRUNCATE",
15
- "WAL"
16
- ];
17
- var KVSync = class {
18
- static {
19
- __name(this, "KVSync");
20
- }
21
- #db;
22
- /**
23
- * Instantiate a new key-value store
24
- * @param path Where the database is stored, or `:memory:` for in-memory storage
25
- */
26
- constructor(options) {
27
- const dbPath = options?.path ?? ":memory:";
28
- if (dbPath !== ":memory:") {
29
- fs.mkdirSync(path.dirname(dbPath), { recursive: true });
30
- }
31
- this.#db = new DatabaseSync(dbPath);
32
- this.setJournalMode(options?.journalMode ?? "DELETE");
33
- this.#db.exec(
34
- "CREATE TABLE IF NOT EXISTS kv (key TEXT PRIMARY KEY NOT NULL, value BLOB NOT NULL) STRICT;"
35
- );
36
- }
37
- /**
38
- * Set a key in the database
39
- * @param key Key name
40
- * @param value Key value
41
- * @returns Provided value
42
- */
43
- set(key, value) {
44
- if (!key || typeof key !== "string") {
45
- throw new Error(
46
- "[KVSync]: Key must be provided and be a non-empty string."
47
- );
48
- }
49
- if (value === void 0) {
50
- throw new Error(
51
- "[KVSync]: Provided value is undefined. Did you mean to use delete() instead?"
52
- );
53
- }
54
- this.#db.prepare("INSERT OR REPLACE INTO kv (key, value) VALUES (?, ?)").run(key, serialize(value));
55
- return value;
56
- }
57
- /**
58
- * Get a value from the database
59
- * @param key Key name
60
- * @returns Value or null
61
- */
62
- get(key) {
63
- if (!key || typeof key !== "string") {
64
- throw new Error(
65
- "[KVSync]: Key must be provided and be a non-empty string."
66
- );
67
- }
68
- const row = this.#db.prepare("SELECT value FROM kv WHERE key = ?").get(key);
69
- return row ? deserialize(row.value) : null;
70
- }
71
- /**
72
- * Delete a key from the database
73
- * @param key Key name
74
- * @returns KVSync instance
75
- */
76
- delete(key) {
77
- if (!key || typeof key !== "string") {
78
- throw new Error(
79
- "[KVSync]: Key must be provided and be a non-empty string."
80
- );
81
- }
82
- this.#db.prepare("DELETE FROM kv WHERE key = ?").run(key);
83
- return this;
84
- }
85
- /**
86
- * Get all data in the database
87
- * @returns Array of objects containing keys and values
88
- */
89
- all(filter) {
90
- const rows = this.#db.prepare("SELECT key, value FROM kv").iterate();
91
- const result = [];
92
- for (const row of rows) {
93
- const key = row.key;
94
- const value = deserialize(row.value);
95
- if (!filter || filter(key, value)) {
96
- result.push({ key, value });
97
- }
98
- }
99
- return result;
100
- }
101
- /**
102
- * Remove all entries from the database
103
- */
104
- clear() {
105
- this.#db.exec("DELETE FROM kv;");
106
- return this;
107
- }
108
- /**
109
- * Update the journal mode
110
- * @param mode New journal mode
111
- */
112
- setJournalMode(mode) {
113
- if (!journalModes.includes(mode)) {
114
- throw new Error(
115
- `[KVSync]: Invalid journal mode specified. Received: "${mode}", expected one of: ${journalModes.join(", ")}`
116
- );
117
- }
118
- this.#db.exec(`PRAGMA journal_mode = ${mode};`);
119
- return this;
120
- }
121
- /**
122
- * Perform a transaction
123
- * @param callback Callback with KVSync instance
124
- * @returns Object containing oldValues and newValues each containing arrays of keys and values
125
- */
126
- transaction(callback) {
127
- if (!callback) {
128
- throw new Error(
129
- "[KVSync]: A callback must be provided when using transaction()."
130
- );
131
- }
132
- if (typeof callback !== "function") {
133
- throw new Error(
134
- `[KVSync]: Transaction callback must be of type function. Received: ${typeof callback}`
135
- );
136
- }
137
- const oldMap = /* @__PURE__ */ new Map();
138
- const newMap = /* @__PURE__ */ new Map();
139
- const tx = Object.create(this);
140
- tx.set = (key, value) => {
141
- if (!oldMap.has(key)) {
142
- const oldValue = this.get(key);
143
- oldMap.set(key, oldValue === null ? void 0 : oldValue);
144
- }
145
- newMap.set(key, value);
146
- return value ?? null;
147
- };
148
- tx.delete = (key) => {
149
- if (!oldMap.has(key)) {
150
- const oldValue = this.get(key);
151
- oldMap.set(key, oldValue === null ? void 0 : oldValue);
152
- }
153
- newMap.set(key, null);
154
- return tx;
155
- };
156
- try {
157
- callback(tx);
158
- this.#db.exec("BEGIN TRANSACTION;");
159
- for (const [key, value] of newMap.entries()) {
160
- if (value === null) {
161
- this.delete(key);
162
- } else {
163
- this.set(key, value);
164
- }
165
- }
166
- this.#db.exec("COMMIT;");
167
- } catch (error) {
168
- this.#db.exec("ROLLBACK;");
169
- throw error;
170
- }
171
- return {
172
- oldValues: Array.from(oldMap.entries()).map(([key, value]) => ({
173
- key,
174
- value
175
- })),
176
- newValues: Array.from(newMap.entries()).map(([key, value]) => ({
177
- key,
178
- value
179
- }))
180
- };
181
- }
182
- };
183
- export {
184
- KVSync,
185
- journalModes
186
- };