local-kv-cli 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # local-kv-cli
2
+
3
+ A tiny, zero-dependency CLI to store key-value pairs locally on your machine.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g local-kv-cli
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```bash
14
+ lkv set api_url https://example.com # create a pair
15
+ lkv get api_url # print a value
16
+ lkv update api_url https://new.com # change an existing value
17
+ lkv list # show all pairs (add --json for JSON)
18
+ lkv delete api_url # remove a pair
19
+ lkv clear # remove everything
20
+ lkv path # show where data is stored
21
+ ```
22
+
23
+ `set` won't overwrite an existing key; use `update`, or `set <key> <value> --force`.
24
+
25
+ Data is stored in `~/.local-kv/store.json`. Set `LKV_STORE_PATH` to use a different file.
26
+
27
+ ## Use from code
28
+
29
+ ```ts
30
+ import { Store } from "local-kv-cli";
31
+
32
+ const store = new Store();
33
+ store.set("visits", "1");
34
+ store.get("visits"); // "1"
35
+ ```
36
+
37
+ ## License
38
+
39
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { Store } from "./store";
3
+ export declare function run(argv: string[], store?: Store): void;
package/dist/cli.js ADDED
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.run = run;
5
+ const store_1 = require("./store");
6
+ const HELP = `lkv - store key-value pairs locally
7
+
8
+ Usage:
9
+ lkv set <key> <value> [--force] Create a pair (--force overwrites)
10
+ lkv get <key> Print the value of a key
11
+ lkv update <key> <value> Change the value of an existing key
12
+ lkv delete <key> Remove a pair
13
+ lkv list [--json] Show all pairs
14
+ lkv clear Remove all pairs
15
+ lkv path Show where the data file lives
16
+ lkv help Show this help
17
+
18
+ Tip: quote values with spaces, e.g. lkv set greeting "hello world"`;
19
+ function fail(message) {
20
+ console.error(`Error: ${message}`);
21
+ process.exit(1);
22
+ }
23
+ function requireArgs(args, count, usage) {
24
+ if (args.length < count)
25
+ fail(`Usage: lkv ${usage}`);
26
+ }
27
+ function run(argv, store = new store_1.Store()) {
28
+ const flags = new Set(argv.filter((a) => a.startsWith("--")));
29
+ const [command, ...args] = argv.filter((a) => !a.startsWith("--"));
30
+ switch (command) {
31
+ case "set": {
32
+ requireArgs(args, 2, "set <key> <value>");
33
+ const [key, ...rest] = args;
34
+ store.set(key, rest.join(" "), flags.has("--force"));
35
+ console.log(`Saved "${key}"`);
36
+ break;
37
+ }
38
+ case "get": {
39
+ requireArgs(args, 1, "get <key>");
40
+ const value = store.get(args[0]);
41
+ if (value === undefined)
42
+ fail(`Key "${args[0]}" not found`);
43
+ console.log(value);
44
+ break;
45
+ }
46
+ case "update": {
47
+ requireArgs(args, 2, "update <key> <value>");
48
+ const [key, ...rest] = args;
49
+ store.update(key, rest.join(" "));
50
+ console.log(`Updated "${key}"`);
51
+ break;
52
+ }
53
+ case "delete":
54
+ case "rm": {
55
+ requireArgs(args, 1, "delete <key>");
56
+ if (!store.delete(args[0]))
57
+ fail(`Key "${args[0]}" not found`);
58
+ console.log(`Deleted "${args[0]}"`);
59
+ break;
60
+ }
61
+ case "list":
62
+ case "ls": {
63
+ const data = store.all();
64
+ if (flags.has("--json")) {
65
+ console.log(JSON.stringify(data, null, 2));
66
+ break;
67
+ }
68
+ const keys = Object.keys(data);
69
+ if (keys.length === 0) {
70
+ console.log("(empty)");
71
+ break;
72
+ }
73
+ const width = Math.max(...keys.map((k) => k.length));
74
+ for (const key of keys)
75
+ console.log(`${key.padEnd(width)} ${data[key]}`);
76
+ break;
77
+ }
78
+ case "clear":
79
+ store.clear();
80
+ console.log("All pairs removed");
81
+ break;
82
+ case "path":
83
+ console.log(store.path);
84
+ break;
85
+ case undefined:
86
+ case "help":
87
+ console.log(HELP);
88
+ break;
89
+ default:
90
+ fail(`Unknown command "${command}". Run "lkv help".`);
91
+ }
92
+ }
93
+ if (require.main === module) {
94
+ try {
95
+ run(process.argv.slice(2));
96
+ }
97
+ catch (err) {
98
+ fail(err instanceof Error ? err.message : String(err));
99
+ }
100
+ }
@@ -0,0 +1,2 @@
1
+ export { Store, getStorePath } from "./store";
2
+ export type { Data } from "./store";
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getStorePath = exports.Store = void 0;
4
+ // Public API, so the store can also be used from code: import { Store } from "local-kv-cli"
5
+ var store_1 = require("./store");
6
+ Object.defineProperty(exports, "Store", { enumerable: true, get: function () { return store_1.Store; } });
7
+ Object.defineProperty(exports, "getStorePath", { enumerable: true, get: function () { return store_1.getStorePath; } });
@@ -0,0 +1,20 @@
1
+ export type Data = Record<string, string>;
2
+ /** Where the data lives. Override with the LKV_STORE_PATH env variable. */
3
+ export declare function getStorePath(): string;
4
+ export declare class Store {
5
+ private readonly filePath;
6
+ constructor(filePath?: string);
7
+ get path(): string;
8
+ private read;
9
+ private write;
10
+ has(key: string): boolean;
11
+ /** Create a new pair. Throws if the key already exists (use update, or force). */
12
+ set(key: string, value: string, force?: boolean): void;
13
+ get(key: string): string | undefined;
14
+ /** Change an existing pair. Throws if the key does not exist. */
15
+ update(key: string, value: string): void;
16
+ /** Returns true if the key existed and was removed. */
17
+ delete(key: string): boolean;
18
+ all(): Data;
19
+ clear(): void;
20
+ }
package/dist/store.js ADDED
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.Store = void 0;
37
+ exports.getStorePath = getStorePath;
38
+ const fs = __importStar(require("fs"));
39
+ const os = __importStar(require("os"));
40
+ const path = __importStar(require("path"));
41
+ /** Where the data lives. Override with the LKV_STORE_PATH env variable. */
42
+ function getStorePath() {
43
+ return process.env.LKV_STORE_PATH || path.join(os.homedir(), ".local-kv", "store.json");
44
+ }
45
+ class Store {
46
+ filePath;
47
+ constructor(filePath = getStorePath()) {
48
+ this.filePath = filePath;
49
+ }
50
+ get path() {
51
+ return this.filePath;
52
+ }
53
+ read() {
54
+ // Prototype-less object so keys like "constructor" or "__proto__" are just normal keys.
55
+ const data = Object.create(null);
56
+ if (!fs.existsSync(this.filePath))
57
+ return data;
58
+ const raw = fs.readFileSync(this.filePath, "utf8");
59
+ if (!raw.trim())
60
+ return data;
61
+ try {
62
+ return Object.assign(data, JSON.parse(raw));
63
+ }
64
+ catch {
65
+ throw new Error(`Store file is corrupted: ${this.filePath}`);
66
+ }
67
+ }
68
+ write(data) {
69
+ fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
70
+ // Write to a temp file then rename, so a crash never leaves a half-written store.
71
+ const tmp = `${this.filePath}.tmp`;
72
+ fs.writeFileSync(tmp, JSON.stringify(data, null, 2));
73
+ fs.renameSync(tmp, this.filePath);
74
+ }
75
+ has(key) {
76
+ return key in this.read();
77
+ }
78
+ /** Create a new pair. Throws if the key already exists (use update, or force). */
79
+ set(key, value, force = false) {
80
+ const data = this.read();
81
+ if (!force && key in data) {
82
+ throw new Error(`Key "${key}" already exists. Use "update" to change it.`);
83
+ }
84
+ data[key] = value;
85
+ this.write(data);
86
+ }
87
+ get(key) {
88
+ const data = this.read();
89
+ return key in data ? data[key] : undefined;
90
+ }
91
+ /** Change an existing pair. Throws if the key does not exist. */
92
+ update(key, value) {
93
+ const data = this.read();
94
+ if (!(key in data)) {
95
+ throw new Error(`Key "${key}" not found. Use "set" to create it.`);
96
+ }
97
+ data[key] = value;
98
+ this.write(data);
99
+ }
100
+ /** Returns true if the key existed and was removed. */
101
+ delete(key) {
102
+ const data = this.read();
103
+ if (!(key in data))
104
+ return false;
105
+ delete data[key];
106
+ this.write(data);
107
+ return true;
108
+ }
109
+ all() {
110
+ return this.read();
111
+ }
112
+ clear() {
113
+ this.write({});
114
+ }
115
+ }
116
+ exports.Store = Store;
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "local-kv-cli",
3
+ "version": "1.0.0",
4
+ "description": "A tiny CLI to store key-value pairs locally on your machine",
5
+ "keywords": [
6
+ "cli",
7
+ "key-value",
8
+ "kv",
9
+ "store",
10
+ "local",
11
+ "storage"
12
+ ],
13
+ "license": "MIT",
14
+ "author": "",
15
+ "type": "commonjs",
16
+ "main": "dist/index.js",
17
+ "types": "dist/index.d.ts",
18
+ "bin": {
19
+ "lkv": "dist/cli.js"
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "engines": {
25
+ "node": ">=18"
26
+ },
27
+ "scripts": {
28
+ "build": "tsc",
29
+ "test": "npm run build && node --test",
30
+ "prepublishOnly": "npm test"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^26.6.3",
34
+ "typescript": "^7.0.2"
35
+ }
36
+ }