vodia-pharmacy-ai 0.2.0 → 0.2.1

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.
@@ -293,6 +293,19 @@ function createDatabase({ installDir, demo }) {
293
293
  }
294
294
  }
295
295
 
296
+
297
+ function seedAdminUser({ installDir, email, password }) {
298
+ const script = path.join(packageRoot, "seeds", "seed-admin.cjs");
299
+
300
+ if (!fs.existsSync(script)) {
301
+ console.log("Admin seed script not found. Skipping admin seed.");
302
+ return;
303
+ }
304
+
305
+ console.log("Seeding admin portal user...");
306
+ sh("node " + q(script) + " " + q(installDir) + " " + q(email) + " " + q(password));
307
+ }
308
+
296
309
  function installDemo() {
297
310
  const installDir = getArg("--dir", "/opt/vodia-pharmacy-ai-demo");
298
311
  const port = getArg("--port", "3200");
@@ -343,6 +356,11 @@ function installDemo() {
343
356
  sh("cd " + q(installDir) + " && npm install --omit=dev");
344
357
 
345
358
  createDatabase({ installDir, demo: true });
359
+ seedAdminUser({
360
+ installDir,
361
+ email: "admin@example.com",
362
+ password: secrets.adminPassword
363
+ });
346
364
 
347
365
  ensurePm2();
348
366
  sh("pm2 delete " + q(appName) + " >/dev/null 2>&1 || true");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vodia-pharmacy-ai",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Installer CLI for Vodia Pharmacy AI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,128 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { createRequire } = require("module");
4
+
5
+ const installDir = process.argv[2] || process.cwd();
6
+ const email = process.argv[3] || "admin@example.com";
7
+ const password = process.argv[4];
8
+
9
+ if (!password) {
10
+ console.error("Missing admin password.");
11
+ process.exit(1);
12
+ }
13
+
14
+ const appRequire = createRequire(path.join(installDir, "package.json"));
15
+ const sqlite3 = appRequire("sqlite3").verbose();
16
+ const bcrypt = appRequire("bcrypt");
17
+
18
+ const dbPath = path.join(installDir, "pharmacy.db");
19
+ const db = new sqlite3.Database(dbPath);
20
+
21
+ function run(sql, params = []) {
22
+ return new Promise((resolve, reject) => {
23
+ db.run(sql, params, function (err) {
24
+ if (err) reject(err);
25
+ else resolve(this);
26
+ });
27
+ });
28
+ }
29
+
30
+ function all(sql, params = []) {
31
+ return new Promise((resolve, reject) => {
32
+ db.all(sql, params, function (err, rows) {
33
+ if (err) reject(err);
34
+ else resolve(rows);
35
+ });
36
+ });
37
+ }
38
+
39
+ (async () => {
40
+ const tables = await all("SELECT name FROM sqlite_master WHERE type='table' AND name='portal_users'");
41
+ if (!tables.length) {
42
+ console.log("portal_users table not found. Creating it.");
43
+ await run(`
44
+ CREATE TABLE portal_users (
45
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
46
+ name TEXT NOT NULL,
47
+ username TEXT UNIQUE,
48
+ email TEXT UNIQUE,
49
+ password_hash TEXT NOT NULL,
50
+ role TEXT DEFAULT 'admin',
51
+ active INTEGER DEFAULT 1,
52
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP,
53
+ updated_at TEXT
54
+ )
55
+ `);
56
+ }
57
+
58
+ const cols = await all("PRAGMA table_info(portal_users)");
59
+ const names = new Set(cols.map(c => c.name));
60
+ const hash = await bcrypt.hash(password, 10);
61
+
62
+ const where = [];
63
+ const whereParams = [];
64
+
65
+ if (names.has("email")) {
66
+ where.push("email = ?");
67
+ whereParams.push(email);
68
+ }
69
+
70
+ if (names.has("username")) {
71
+ where.push("username = ?");
72
+ whereParams.push(email);
73
+ }
74
+
75
+ if (where.length) {
76
+ await run(`DELETE FROM portal_users WHERE ${where.join(" OR ")}`, whereParams);
77
+ }
78
+
79
+ const fields = [];
80
+ const marks = [];
81
+ const params = [];
82
+
83
+ function add(name, value) {
84
+ if (names.has(name) && !fields.includes(name)) {
85
+ fields.push(name);
86
+ marks.push("?");
87
+ params.push(value);
88
+ }
89
+ }
90
+
91
+ add("name", "Pharmacy Admin");
92
+ add("full_name", "Pharmacy Admin");
93
+ add("display_name", "Pharmacy Admin");
94
+ add("username", email);
95
+ add("email", email);
96
+ add("password_hash", hash);
97
+ add("password", hash);
98
+ add("role", "admin");
99
+ add("active", 1);
100
+ add("is_active", 1);
101
+ add("is_admin", 1);
102
+ add("created_at", new Date().toISOString());
103
+ add("updated_at", new Date().toISOString());
104
+
105
+ for (const c of cols) {
106
+ if (c.pk) continue;
107
+ if (fields.includes(c.name)) continue;
108
+ if (c.notnull && c.dflt_value === null) {
109
+ const t = String(c.type || "").toUpperCase();
110
+ add(c.name, t.includes("INT") || t.includes("REAL") || t.includes("NUM") ? 0 : "");
111
+ }
112
+ }
113
+
114
+ await run(
115
+ `INSERT INTO portal_users (${fields.join(", ")}) VALUES (${marks.join(", ")})`,
116
+ params
117
+ );
118
+
119
+ console.log("Admin login seeded ✅");
120
+ console.log("Username:", email);
121
+ console.log("Password:", password);
122
+
123
+ db.close();
124
+ })().catch(err => {
125
+ console.error(err);
126
+ db.close();
127
+ process.exit(1);
128
+ });