dbnexus 0.4.0 → 0.5.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/dist/cli.js CHANGED
@@ -33113,7 +33113,7 @@ var import_dotenv = __toESM(require_main(), 1);
33113
33113
  import Database from "better-sqlite3";
33114
33114
 
33115
33115
  // packages/metadata/dist/schema.js
33116
- var SCHEMA_VERSION = 21;
33116
+ var SCHEMA_VERSION = 22;
33117
33117
  var MIGRATIONS = [
33118
33118
  // Version 1: Initial schema
33119
33119
  `
@@ -33598,6 +33598,50 @@ var MIGRATIONS = [
33598
33598
  CREATE INDEX IF NOT EXISTS idx_backups_created_by ON backups(created_by);
33599
33599
 
33600
33600
  UPDATE schema_version SET version = 21;
33601
+ `,
33602
+ // Version 22: Add is_public to resources + rename settings to user_preferences with user_id
33603
+ `
33604
+ -- Create system user for storing system-wide preferences (if not exists)
33605
+ INSERT OR IGNORE INTO users (id, email, password_hash, role, created_at, updated_at)
33606
+ VALUES ('system', 'system@internal', '', 'admin', datetime('now'), datetime('now'));
33607
+
33608
+ -- Ensure settings table exists (even if empty) to avoid errors in migration
33609
+ CREATE TABLE IF NOT EXISTS settings (
33610
+ key TEXT PRIMARY KEY,
33611
+ value TEXT NOT NULL,
33612
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
33613
+ );
33614
+
33615
+ -- Create user_preferences table (replaces settings)
33616
+ CREATE TABLE IF NOT EXISTS user_preferences (
33617
+ id TEXT PRIMARY KEY,
33618
+ user_id TEXT NOT NULL,
33619
+ key TEXT NOT NULL,
33620
+ value TEXT NOT NULL,
33621
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
33622
+ FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
33623
+ UNIQUE(user_id, key)
33624
+ );
33625
+
33626
+ -- Migrate existing settings as system defaults (user_id = 'system')
33627
+ INSERT OR IGNORE INTO user_preferences (id, user_id, key, value, updated_at)
33628
+ SELECT hex(randomblob(16)), 'system', key, value, updated_at FROM settings;
33629
+
33630
+ -- Drop old settings table
33631
+ DROP TABLE IF EXISTS settings;
33632
+
33633
+ -- Create index for user preferences
33634
+ CREATE INDEX IF NOT EXISTS idx_user_preferences_user ON user_preferences(user_id);
33635
+ CREATE INDEX IF NOT EXISTS idx_user_preferences_key ON user_preferences(user_id, key);
33636
+
33637
+ -- Add is_public to resources (default 0 = private, only owner can see)
33638
+ ALTER TABLE connections ADD COLUMN is_public INTEGER NOT NULL DEFAULT 0;
33639
+ ALTER TABLE servers ADD COLUMN is_public INTEGER NOT NULL DEFAULT 0;
33640
+ ALTER TABLE projects ADD COLUMN is_public INTEGER NOT NULL DEFAULT 0;
33641
+ ALTER TABLE database_groups ADD COLUMN is_public INTEGER NOT NULL DEFAULT 0;
33642
+ ALTER TABLE saved_queries ADD COLUMN is_public INTEGER NOT NULL DEFAULT 0;
33643
+
33644
+ UPDATE schema_version SET version = 22;
33601
33645
  `
33602
33646
  ];
33603
33647
 
@@ -33717,9 +33761,9 @@ var ConnectionRepository = class {
33717
33761
  const encryptedPwd = input.password ? encryptPassword(input.password) : null;
33718
33762
  const connectionType = input.connectionType || this.inferConnectionType(input.host);
33719
33763
  this.db.prepare(`
33720
- INSERT INTO connections (id, name, engine, connection_type, host, port, database, username, encrypted_password, ssl, default_schema, tags, read_only, server_id, project_id, group_id, created_by, created_at, updated_at)
33721
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
33722
- `).run(id, input.name, input.engine, connectionType, input.host, input.port, input.database, input.username, encryptedPwd, input.ssl ? 1 : 0, input.defaultSchema || null, JSON.stringify(input.tags ?? []), input.readOnly ? 1 : 0, input.serverId || null, input.projectId || null, input.groupId || null, userId || null, now, now);
33764
+ INSERT INTO connections (id, name, engine, connection_type, host, port, database, username, encrypted_password, ssl, default_schema, tags, read_only, server_id, project_id, group_id, is_public, created_by, created_at, updated_at)
33765
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
33766
+ `).run(id, input.name, input.engine, connectionType, input.host, input.port, input.database, input.username, encryptedPwd, input.ssl ? 1 : 0, input.defaultSchema || null, JSON.stringify(input.tags ?? []), input.readOnly ? 1 : 0, input.serverId || null, input.projectId || null, input.groupId || null, input.isPublic ? 1 : 0, userId || null, now, now);
33723
33767
  return this.findById(id);
33724
33768
  }
33725
33769
  /**
@@ -33775,7 +33819,7 @@ var ConnectionRepository = class {
33775
33819
  `;
33776
33820
  const params = [];
33777
33821
  if (userContext && !userContext.isAdmin && userContext.userId) {
33778
- query += ` WHERE c.created_by = ? OR c.created_by IS NULL`;
33822
+ query += ` WHERE (c.created_by = ? OR c.created_by IS NULL OR c.is_public = 1)`;
33779
33823
  params.push(userContext.userId);
33780
33824
  }
33781
33825
  query += ` ORDER BY p.name, dg.name, c.name`;
@@ -33800,7 +33844,7 @@ var ConnectionRepository = class {
33800
33844
  `;
33801
33845
  const params = [projectId];
33802
33846
  if (userContext && !userContext.isAdmin && userContext.userId) {
33803
- query += ` AND (c.created_by = ? OR c.created_by IS NULL)`;
33847
+ query += ` AND (c.created_by = ? OR c.created_by IS NULL OR c.is_public = 1)`;
33804
33848
  params.push(userContext.userId);
33805
33849
  }
33806
33850
  query += ` ORDER BY dg.name, c.name`;
@@ -33825,7 +33869,7 @@ var ConnectionRepository = class {
33825
33869
  `;
33826
33870
  const params = [groupId];
33827
33871
  if (userContext && !userContext.isAdmin && userContext.userId) {
33828
- query += ` AND (c.created_by = ? OR c.created_by IS NULL)`;
33872
+ query += ` AND (c.created_by = ? OR c.created_by IS NULL OR c.is_public = 1)`;
33829
33873
  params.push(userContext.userId);
33830
33874
  }
33831
33875
  query += ` ORDER BY c.name`;
@@ -33850,7 +33894,7 @@ var ConnectionRepository = class {
33850
33894
  `;
33851
33895
  const params = [];
33852
33896
  if (userContext && !userContext.isAdmin && userContext.userId) {
33853
- query += ` AND (c.created_by = ? OR c.created_by IS NULL)`;
33897
+ query += ` AND (c.created_by = ? OR c.created_by IS NULL OR c.is_public = 1)`;
33854
33898
  params.push(userContext.userId);
33855
33899
  }
33856
33900
  query += ` ORDER BY c.name`;
@@ -33874,7 +33918,7 @@ var ConnectionRepository = class {
33874
33918
  `;
33875
33919
  const params = [];
33876
33920
  if (userContext && !userContext.isAdmin && userContext.userId) {
33877
- query += ` WHERE c.created_by = ? OR c.created_by IS NULL`;
33921
+ query += ` WHERE (c.created_by = ? OR c.created_by IS NULL OR c.is_public = 1)`;
33878
33922
  params.push(userContext.userId);
33879
33923
  }
33880
33924
  query += ` ORDER BY c.name`;
@@ -33949,6 +33993,10 @@ var ConnectionRepository = class {
33949
33993
  updates.push("server_id = ?");
33950
33994
  values.push(input.serverId);
33951
33995
  }
33996
+ if (input.isPublic !== void 0) {
33997
+ updates.push("is_public = ?");
33998
+ values.push(input.isPublic ? 1 : 0);
33999
+ }
33952
34000
  if (updates.length > 0) {
33953
34001
  updates.push("updated_at = ?");
33954
34002
  values.push((/* @__PURE__ */ new Date()).toISOString());
@@ -34020,21 +34068,23 @@ var ConnectionRepository = class {
34020
34068
  projectId: row.project_id || void 0,
34021
34069
  groupId: row.group_id || void 0,
34022
34070
  createdBy: row.created_by || void 0,
34071
+ isPublic: row.is_public === 1,
34023
34072
  serverName: row.server_name,
34024
34073
  projectName: row.project_name,
34025
34074
  groupName: row.group_name
34026
34075
  };
34027
34076
  }
34028
34077
  /**
34029
- * Check if user can access a connection
34078
+ * Check if user can access (view) a connection
34079
+ * Accessible if: owner, admin, not private, or created_by is null (legacy)
34030
34080
  */
34031
34081
  canAccess(connectionId, userContext) {
34032
34082
  if (userContext.isAdmin)
34033
34083
  return true;
34034
- const row = this.db.prepare("SELECT created_by FROM connections WHERE id = ?").get(connectionId);
34084
+ const row = this.db.prepare("SELECT created_by, is_public FROM connections WHERE id = ?").get(connectionId);
34035
34085
  if (!row)
34036
34086
  return false;
34037
- return row.created_by === null || row.created_by === userContext.userId;
34087
+ return row.created_by === null || row.created_by === userContext.userId || row.is_public === 1;
34038
34088
  }
34039
34089
  /**
34040
34090
  * Find connections by server ID (filtered by user unless admin)
@@ -34053,13 +34103,25 @@ var ConnectionRepository = class {
34053
34103
  `;
34054
34104
  const params = [serverId];
34055
34105
  if (userContext && !userContext.isAdmin && userContext.userId) {
34056
- query += ` AND (c.created_by = ? OR c.created_by IS NULL)`;
34106
+ query += ` AND (c.created_by = ? OR c.created_by IS NULL OR c.is_public = 1)`;
34057
34107
  params.push(userContext.userId);
34058
34108
  }
34059
34109
  query += ` ORDER BY c.name`;
34060
34110
  const rows = this.db.prepare(query).all(...params);
34061
34111
  return rows.map((row) => this.rowToConnection(row));
34062
34112
  }
34113
+ /**
34114
+ * Check if user can modify (update/delete) a connection
34115
+ * Only owner or admin can modify
34116
+ */
34117
+ canModify(connectionId, userContext) {
34118
+ if (userContext.isAdmin)
34119
+ return true;
34120
+ const row = this.db.prepare("SELECT created_by FROM connections WHERE id = ?").get(connectionId);
34121
+ if (!row)
34122
+ return false;
34123
+ return row.created_by === null || row.created_by === userContext.userId;
34124
+ }
34063
34125
  };
34064
34126
 
34065
34127
  // packages/metadata/dist/repositories/server.repository.js
@@ -34096,6 +34158,7 @@ var ServerRepository = class {
34096
34158
  createdAt: new Date(row.created_at),
34097
34159
  updatedAt: new Date(row.updated_at),
34098
34160
  createdBy: row.created_by ?? void 0,
34161
+ isPublic: row.is_public === 1,
34099
34162
  databaseCount: row.database_count
34100
34163
  };
34101
34164
  }
@@ -34148,7 +34211,7 @@ var ServerRepository = class {
34148
34211
  `;
34149
34212
  const params = [];
34150
34213
  if (userContext && !userContext.isAdmin && userContext.userId) {
34151
- query += ` WHERE s.created_by = ? OR s.created_by IS NULL`;
34214
+ query += ` WHERE (s.created_by = ? OR s.created_by IS NULL OR s.is_public = 1)`;
34152
34215
  params.push(userContext.userId);
34153
34216
  }
34154
34217
  query += ` ORDER BY s.name`;
@@ -34167,7 +34230,7 @@ var ServerRepository = class {
34167
34230
  `;
34168
34231
  const params = [engine];
34169
34232
  if (userContext && !userContext.isAdmin && userContext.userId) {
34170
- query += ` AND (s.created_by = ? OR s.created_by IS NULL)`;
34233
+ query += ` AND (s.created_by = ? OR s.created_by IS NULL OR s.is_public = 1)`;
34171
34234
  params.push(userContext.userId);
34172
34235
  }
34173
34236
  query += ` ORDER BY s.name`;
@@ -34175,9 +34238,20 @@ var ServerRepository = class {
34175
34238
  return rows.map((row) => this.rowToServer(row));
34176
34239
  }
34177
34240
  /**
34178
- * Check if user can access a server
34241
+ * Check if user can access (view) a server
34179
34242
  */
34180
34243
  canAccess(serverId, userContext) {
34244
+ if (userContext.isAdmin)
34245
+ return true;
34246
+ const row = this.db.prepare("SELECT created_by, is_public FROM servers WHERE id = ?").get(serverId);
34247
+ if (!row)
34248
+ return false;
34249
+ return row.created_by === null || row.created_by === userContext.userId || row.is_public === 1;
34250
+ }
34251
+ /**
34252
+ * Check if user can modify (update/delete) a server
34253
+ */
34254
+ canModify(serverId, userContext) {
34181
34255
  if (userContext.isAdmin)
34182
34256
  return true;
34183
34257
  const row = this.db.prepare("SELECT created_by FROM servers WHERE id = ?").get(serverId);
@@ -34235,6 +34309,10 @@ var ServerRepository = class {
34235
34309
  updates.push("stop_command = ?");
34236
34310
  values.push(input.stopCommand || null);
34237
34311
  }
34312
+ if (input.isPublic !== void 0) {
34313
+ updates.push("is_public = ?");
34314
+ values.push(input.isPublic ? 1 : 0);
34315
+ }
34238
34316
  if (updates.length === 0) {
34239
34317
  return existing;
34240
34318
  }
@@ -34279,7 +34357,7 @@ var ServerRepository = class {
34279
34357
  };
34280
34358
 
34281
34359
  // apps/cli/dist/version.js
34282
- var VERSION = true ? "0.4.0" : "0.1.10";
34360
+ var VERSION = true ? "0.5.0" : "0.1.10";
34283
34361
 
34284
34362
  // apps/cli/dist/commands/init.js
34285
34363
  function loadEnvFile(cwd) {
@@ -34751,7 +34829,7 @@ var PostgresConnector = class {
34751
34829
  port: this.config.port,
34752
34830
  database: this.config.database,
34753
34831
  user: this.config.username,
34754
- password: this.config.password,
34832
+ password: this.config.password ?? "",
34755
34833
  ssl: this.config.ssl ? { rejectUnauthorized: this.config.sslVerify ?? false } : false,
34756
34834
  connectionTimeoutMillis: 5e3,
34757
34835
  max: 1
@@ -34783,7 +34861,7 @@ var PostgresConnector = class {
34783
34861
  port: this.config.port,
34784
34862
  database: this.config.database,
34785
34863
  user: this.config.username,
34786
- password: this.config.password,
34864
+ password: this.config.password ?? "",
34787
34865
  ssl: this.config.ssl ? { rejectUnauthorized: this.config.sslVerify ?? false } : false,
34788
34866
  max: 10,
34789
34867
  idleTimeoutMillis: 3e4,