@captainsafia/burrow 1.0.0-preview.0a24dbc → 1.0.0-preview.6e67e96

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.
Files changed (2) hide show
  1. package/dist/api.js +55 -57
  2. package/package.json +1 -1
package/dist/api.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/storage/index.ts
2
- import { mkdir, rename, readFile, unlink } from "node:fs/promises";
2
+ import { Database } from "bun:sqlite";
3
+ import { mkdir } from "node:fs/promises";
3
4
  import { join as join2 } from "node:path";
4
- import { randomBytes } from "node:crypto";
5
5
 
6
6
  // src/platform/index.ts
7
7
  import { homedir } from "node:os";
@@ -44,18 +44,12 @@ function isWindows() {
44
44
  }
45
45
 
46
46
  // src/storage/index.ts
47
- var STORE_VERSION = 1;
48
- var DEFAULT_STORE_FILE = "store.json";
49
- function createEmptyStore() {
50
- return {
51
- version: STORE_VERSION,
52
- paths: {}
53
- };
54
- }
47
+ var DEFAULT_STORE_FILE = "store.db";
55
48
 
56
49
  class Storage {
57
50
  configDir;
58
51
  storeFileName;
52
+ db = null;
59
53
  constructor(options = {}) {
60
54
  this.configDir = options.configDir ?? getConfigDir();
61
55
  this.storeFileName = options.storeFileName ?? DEFAULT_STORE_FILE;
@@ -63,66 +57,70 @@ class Storage {
63
57
  get storePath() {
64
58
  return join2(this.configDir, this.storeFileName);
65
59
  }
66
- async read() {
67
- try {
68
- const content = await readFile(this.storePath, "utf-8");
69
- const store = JSON.parse(content);
70
- if (store.version !== STORE_VERSION) {
71
- throw new Error(`Unsupported store version: ${store.version}. Expected: ${STORE_VERSION}`);
72
- }
73
- return store;
74
- } catch (error) {
75
- if (error.code === "ENOENT") {
76
- return createEmptyStore();
77
- }
78
- throw error;
60
+ async ensureDb() {
61
+ if (this.db) {
62
+ return this.db;
79
63
  }
80
- }
81
- async write(store) {
82
64
  await mkdir(this.configDir, { recursive: true });
83
- const tempFileName = `.store-${randomBytes(8).toString("hex")}.tmp`;
84
- const tempPath = join2(this.configDir, tempFileName);
85
- const content = JSON.stringify(store, null, 2);
86
- try {
87
- const file = Bun.file(tempPath);
88
- await Bun.write(file, content);
89
- await rename(tempPath, this.storePath);
90
- } catch (error) {
91
- try {
92
- await unlink(tempPath);
93
- } catch {}
94
- throw error;
65
+ this.db = new Database(this.storePath);
66
+ this.db.run("PRAGMA journal_mode = WAL");
67
+ this.db.run(`
68
+ CREATE TABLE IF NOT EXISTS secrets (
69
+ path TEXT NOT NULL,
70
+ key TEXT NOT NULL,
71
+ value TEXT,
72
+ updated_at TEXT NOT NULL,
73
+ PRIMARY KEY (path, key)
74
+ )
75
+ `);
76
+ this.db.run("CREATE INDEX IF NOT EXISTS idx_secrets_path ON secrets (path)");
77
+ const versionResult = this.db.query("PRAGMA user_version").get();
78
+ const currentVersion = versionResult?.user_version ?? 0;
79
+ if (currentVersion === 0) {
80
+ this.db.run("PRAGMA user_version = 1");
81
+ } else if (currentVersion !== 1) {
82
+ throw new Error(`Unsupported store version: ${currentVersion}. Expected: 1`);
95
83
  }
84
+ return this.db;
96
85
  }
97
86
  async setSecret(canonicalPath, key, value) {
98
- const store = await this.read();
99
- if (!store.paths[canonicalPath]) {
100
- store.paths[canonicalPath] = {};
101
- }
102
- store.paths[canonicalPath][key] = {
103
- value,
104
- updatedAt: new Date().toISOString()
105
- };
106
- await this.write(store);
87
+ const db = await this.ensureDb();
88
+ const updatedAt = new Date().toISOString();
89
+ db.query(`
90
+ INSERT INTO secrets (path, key, value, updated_at)
91
+ VALUES (?, ?, ?, ?)
92
+ ON CONFLICT(path, key) DO UPDATE SET
93
+ value = excluded.value,
94
+ updated_at = excluded.updated_at
95
+ `).run(canonicalPath, key, value, updatedAt);
107
96
  }
108
97
  async getPathSecrets(canonicalPath) {
109
- const store = await this.read();
110
- return store.paths[canonicalPath];
98
+ const db = await this.ensureDb();
99
+ const rows = db.query("SELECT key, value, updated_at FROM secrets WHERE path = ?").all(canonicalPath);
100
+ if (rows.length === 0) {
101
+ return;
102
+ }
103
+ const secrets = {};
104
+ for (const row of rows) {
105
+ secrets[row.key] = {
106
+ value: row.value,
107
+ updatedAt: row.updated_at
108
+ };
109
+ }
110
+ return secrets;
111
111
  }
112
112
  async getAllPaths() {
113
- const store = await this.read();
114
- return Object.keys(store.paths);
113
+ const db = await this.ensureDb();
114
+ const rows = db.query("SELECT DISTINCT path FROM secrets").all();
115
+ return rows.map((row) => row.path);
115
116
  }
116
117
  async removeKey(canonicalPath, key) {
117
- const store = await this.read();
118
- if (!store.paths[canonicalPath]?.[key]) {
118
+ const db = await this.ensureDb();
119
+ const existing = db.query("SELECT path FROM secrets WHERE path = ? AND key = ?").get(canonicalPath, key);
120
+ if (!existing) {
119
121
  return false;
120
122
  }
121
- delete store.paths[canonicalPath][key];
122
- if (Object.keys(store.paths[canonicalPath]).length === 0) {
123
- delete store.paths[canonicalPath];
124
- }
125
- await this.write(store);
123
+ db.query("DELETE FROM secrets WHERE path = ? AND key = ?").run(canonicalPath, key);
126
124
  return true;
127
125
  }
128
126
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@captainsafia/burrow",
3
- "version": "1.0.0-preview.0a24dbc",
3
+ "version": "1.0.0-preview.6e67e96",
4
4
  "description": "Platform-agnostic, directory-scoped secrets manager",
5
5
  "type": "module",
6
6
  "main": "dist/api.js",