apiro-db 1.0.6 → 1.0.7

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 CHANGED
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,103 +1,107 @@
1
- # Apiro DB
2
-
3
- A lightweight, zero-dependency, encrypted data store for Node.js.
4
-
5
- No configuration. No secrets. Just import and use.
6
-
7
- ---
8
-
9
- ## Features
10
-
11
- * Zero dependencies
12
- * Fully asynchronous API
13
- * AES-256-GCM encrypted storage
14
- * Automatic key generation
15
- * Machine-bound encryption
16
- * Human-unreadable data at rest
17
- * Simple, familiar database methods
18
-
19
- ---
20
-
21
- ## Installation
22
-
23
- ```bash
24
- npm install apiro-db
25
- ```
26
-
27
- ---
28
-
29
- ## Usage
30
-
31
- ```js
32
- import { SecureStore } from "apiro-db";
33
-
34
- const db = new SecureStore({
35
- file: "./data.db", // Optional
36
- });
37
-
38
- await db.set("coins", 100);
39
- await db.add("coins", 25);
40
- await db.push("items", "shield");
41
-
42
- console.log(await db.get("coins")); // 125
43
- ```
44
-
45
- ---
46
-
47
- ## Configuration
48
-
49
- | Option | Type | Required | Description |
50
- | -------- | ------ | -------- | ----------------------------------- |
51
- | `file` | string | No | Path to the encrypted data file |
52
-
53
- ---
54
-
55
- ## API Reference
56
-
57
- ### `get(key)`
58
-
59
- Returns the value stored under the key.
60
-
61
- ### `set(key, value)`
62
-
63
- Sets a value for the key.
64
-
65
- ### `delete(key)`
66
-
67
- Deletes a key and returns `true` if it existed.
68
-
69
- ### `add(key, number)`
70
-
71
- Adds a number to an existing numeric value.
72
-
73
- ### `subtract(key, number)`
74
-
75
- Subtracts a number from a value.
76
-
77
- ### `push(key, value)`
78
-
79
- Pushes a value onto an array.
80
-
81
- ---
82
-
83
- ## Security
84
-
85
- * Uses AES-256-GCM authenticated encryption
86
- * Key derivation via `scrypt`
87
- * Tamper detection built in
88
- * No plaintext data stored on disk
89
- * No external crypto dependencies
90
-
91
- ---
92
-
93
- ## Limitations
94
-
95
- * Single-file storage
96
- * Not designed for concurrent multi-process writes
97
- * Entire store is encrypted as a single unit
98
-
99
- ---
100
-
101
- ## License
102
-
103
- MIT
1
+ # Apiro DB
2
+
3
+ A lightweight, zero-dependency, encrypted data store for Node.js.
4
+
5
+ No configuration. No secrets. Just import and use.
6
+
7
+ ---
8
+
9
+ ## Features
10
+
11
+ * Zero dependencies
12
+ * Fully asynchronous API
13
+ * AES-256-GCM encrypted storage
14
+ * Automatic key generation
15
+ * Machine-bound encryption
16
+ * Human-unreadable data at rest
17
+ * Simple, familiar database methods
18
+
19
+ ---
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install apiro-db
25
+ ```
26
+
27
+ ---
28
+
29
+ ## Usage
30
+
31
+ ```js
32
+ import { SecureStore } from "apiro-db";
33
+
34
+ const db = new SecureStore({
35
+ file: "./data.db", // Optional
36
+ });
37
+
38
+ await db.set("coins", 100);
39
+ await db.add("coins", 25);
40
+ await db.push("items", "shield");
41
+
42
+ console.log(await db.get("coins")); // 125
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Configuration
48
+
49
+ | Option | Type | Required | Description |
50
+ | -------- | ------ | -------- | ----------------------------------- |
51
+ | `file` | string | No | Path to the encrypted data file |
52
+
53
+ ---
54
+
55
+ ## API Reference
56
+
57
+ ### `get(key)`
58
+
59
+ Returns the value stored under the key.
60
+
61
+ ### `set(key, value)`
62
+
63
+ Sets a value for the key.
64
+
65
+ ### `delete(key)`
66
+
67
+ Deletes a key and returns `true` if it existed.
68
+
69
+ ### `add(key, number)`
70
+
71
+ Adds a number to an existing numeric value.
72
+
73
+ ### `subtract(key, number)`
74
+
75
+ Subtracts a number from a value.
76
+
77
+ ### `push(key, value)`
78
+
79
+ Pushes a value onto an array.
80
+
81
+ ### `has(key, value) or has(key)`
82
+
83
+ Checks for a value in a directory, or for the directory itself.
84
+
85
+ ---
86
+
87
+ ## Security
88
+
89
+ * Uses AES-256-GCM authenticated encryption
90
+ * Key derivation via `scrypt`
91
+ * Tamper detection built in
92
+ * No plaintext data stored on disk
93
+ * No external crypto dependencies
94
+
95
+ ---
96
+
97
+ ## Limitations
98
+
99
+ * Single-file storage
100
+ * Not designed for concurrent multi-process writes
101
+ * Entire store is encrypted as a single unit
102
+
103
+ ---
104
+
105
+ ## License
106
+
107
+ MIT
package/lib/path.js ADDED
@@ -0,0 +1,35 @@
1
+ function getByPath(obj, path) {
2
+ return path.split(".").reduce((o, k) => (o ? o[k] : undefined), obj);
3
+ }
4
+
5
+ function setByPath(obj, path, value) {
6
+ const keys = path.split(".");
7
+ let curr = obj;
8
+
9
+ for (let i = 0; i < keys.length - 1; i++) {
10
+ if (typeof curr[keys[i]] !== "object" || curr[keys[i]] === null) {
11
+ curr[keys[i]] = {};
12
+ }
13
+ curr = curr[keys[i]];
14
+ }
15
+
16
+ curr[keys[keys.length - 1]] = value;
17
+ }
18
+
19
+ function deleteByPath(obj, path) {
20
+ const keys = path.split(".");
21
+ let curr = obj;
22
+
23
+ for (let i = 0; i < keys.length - 1; i++) {
24
+ if (!curr[keys[i]]) return false;
25
+ curr = curr[keys[i]];
26
+ }
27
+
28
+ return delete curr[keys[keys.length - 1]];
29
+ }
30
+
31
+ module.exports = {
32
+ getByPath,
33
+ setByPath,
34
+ deleteByPath
35
+ };
package/lib/store.js CHANGED
@@ -2,6 +2,11 @@ const crypto = require("crypto");
2
2
  const { readFile, writeFile } = require("./file");
3
3
  const { encrypt, decrypt } = require("./crypto");
4
4
  const { generateMasterKey, encryptMasterKey, decryptMasterKey } = require("./masterKey");
5
+ const {
6
+ getByPath,
7
+ setByPath,
8
+ deleteByPath
9
+ } = require("./path");
5
10
 
6
11
  class SecureStore {
7
12
  constructor(options = {}) {
@@ -45,43 +50,79 @@ class SecureStore {
45
50
 
46
51
  async get(key) {
47
52
  await this.ready;
48
- return this.data[key];
53
+ return getByPath(this.data, key);
49
54
  }
50
55
 
51
56
  async set(key, value) {
52
57
  await this.ready;
53
- this.data[key] = value;
58
+ setByPath(this.data, key, value);
54
59
  await this._save();
55
60
  return value;
56
61
  }
57
62
 
58
63
  async delete(key) {
59
64
  await this.ready;
60
- const existed = key in this.data;
61
- delete this.data[key];
65
+ const existed = deleteByPath(this.data, key);
62
66
  await this._save();
63
67
  return existed;
64
68
  }
65
69
 
66
70
  async add(key, amount) {
67
71
  await this.ready;
68
- if (typeof this.data[key] !== "number") this.data[key] = 0;
69
- this.data[key] += amount;
72
+
73
+ let current = getByPath(this.data, key);
74
+ if (typeof current !== "number") current = 0;
75
+
76
+ const next = current + amount;
77
+ setByPath(this.data, key, next);
78
+
70
79
  await this._save();
71
- return this.data[key];
80
+ return next;
72
81
  }
73
82
 
74
83
  async subtract(key, amount) {
75
- return this.add(key, -amount);
84
+ await this.ready;
85
+
86
+ let current = getByPath(this.data, key);
87
+ if (typeof current !== "number") current = 0;
88
+
89
+ const next = current - amount;
90
+ setByPath(this.data, key, next);
91
+
92
+ await this._save();
93
+ return next;
76
94
  }
77
95
 
78
96
  async push(key, value) {
79
97
  await this.ready;
80
- if (!Array.isArray(this.data[key])) this.data[key] = [];
81
- this.data[key].push(value);
98
+
99
+ let arr = getByPath(this.data, key);
100
+ if (!Array.isArray(arr)) arr = [];
101
+
102
+ arr.push(value);
103
+ setByPath(this.data, key, arr);
104
+
82
105
  await this._save();
83
- return this.data[key];
106
+ return arr;
84
107
  }
108
+
109
+ async has(path, value) {
110
+ await this.ready;
111
+
112
+ const current = getByPath(this.data, path);
113
+
114
+ if (current === undefined) return false;
115
+
116
+ if (value === undefined) return true;
117
+
118
+ // If current is an array, check includes
119
+ if (Array.isArray(current)) {
120
+ return current.includes(value);
121
+ }
122
+
123
+ return current === value;
124
+ }
125
+
85
126
  }
86
127
 
87
128
  module.exports = { SecureStore };
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
- {
2
- "name": "apiro-db",
3
- "version": "1.0.6",
4
- "description": "A lightweight, zero-dependency, encrypted data store for Node.js.",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
8
- },
9
- "keywords": ["database", "storage", "encryption", "secure"],
10
- "author": "krispowers",
11
- "license": "ISC",
12
- "files": [
13
- "Readme.md",
14
- "index.js",
15
- "lib/",
16
- "LICENSE"
17
- ]
18
- }
1
+ {
2
+ "name": "apiro-db",
3
+ "version": "1.0.7",
4
+ "description": "A lightweight, zero-dependency, encrypted data store for Node.js.",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": ["database", "storage", "encryption", "secure"],
10
+ "author": "krispowers",
11
+ "license": "ISC",
12
+ "files": [
13
+ "Readme.md",
14
+ "index.js",
15
+ "lib/",
16
+ "LICENSE"
17
+ ]
18
+ }