nexusbert commited on
Commit
8db1a4b
Β·
1 Parent(s): 7051cfb
package-lock.json CHANGED
@@ -22,6 +22,7 @@
22
  "paystack-node": "*",
23
  "pg": "*",
24
  "pinata": "*",
 
25
  "reflect-metadata": "*",
26
  "swagger-jsdoc": "*",
27
  "swagger-ui-express": "*",
@@ -5528,12 +5529,77 @@
5528
  "url": "https://opencollective.com/express"
5529
  }
5530
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5531
  "node_modules/react-is": {
5532
  "version": "18.3.1",
5533
  "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
5534
  "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
5535
  "dev": true
5536
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5537
  "node_modules/readable-stream": {
5538
  "version": "3.6.2",
5539
  "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
@@ -5716,6 +5782,12 @@
5716
  "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
5717
  "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
5718
  },
 
 
 
 
 
 
5719
  "node_modules/semver": {
5720
  "version": "6.3.1",
5721
  "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
@@ -5760,6 +5832,11 @@
5760
  "node": ">= 18"
5761
  }
5762
  },
 
 
 
 
 
5763
  "node_modules/set-function-length": {
5764
  "version": "1.2.2",
5765
  "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
 
22
  "paystack-node": "*",
23
  "pg": "*",
24
  "pinata": "*",
25
+ "react-router-dom": "^7.9.6",
26
  "reflect-metadata": "*",
27
  "swagger-jsdoc": "*",
28
  "swagger-ui-express": "*",
 
5529
  "url": "https://opencollective.com/express"
5530
  }
5531
  },
5532
+ "node_modules/react": {
5533
+ "version": "19.2.0",
5534
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
5535
+ "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
5536
+ "peer": true,
5537
+ "engines": {
5538
+ "node": ">=0.10.0"
5539
+ }
5540
+ },
5541
+ "node_modules/react-dom": {
5542
+ "version": "19.2.0",
5543
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
5544
+ "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
5545
+ "peer": true,
5546
+ "dependencies": {
5547
+ "scheduler": "^0.27.0"
5548
+ },
5549
+ "peerDependencies": {
5550
+ "react": "^19.2.0"
5551
+ }
5552
+ },
5553
  "node_modules/react-is": {
5554
  "version": "18.3.1",
5555
  "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
5556
  "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
5557
  "dev": true
5558
  },
5559
+ "node_modules/react-router": {
5560
+ "version": "7.9.6",
5561
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.6.tgz",
5562
+ "integrity": "sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA==",
5563
+ "dependencies": {
5564
+ "cookie": "^1.0.1",
5565
+ "set-cookie-parser": "^2.6.0"
5566
+ },
5567
+ "engines": {
5568
+ "node": ">=20.0.0"
5569
+ },
5570
+ "peerDependencies": {
5571
+ "react": ">=18",
5572
+ "react-dom": ">=18"
5573
+ },
5574
+ "peerDependenciesMeta": {
5575
+ "react-dom": {
5576
+ "optional": true
5577
+ }
5578
+ }
5579
+ },
5580
+ "node_modules/react-router-dom": {
5581
+ "version": "7.9.6",
5582
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.6.tgz",
5583
+ "integrity": "sha512-2MkC2XSXq6HjGcihnx1s0DBWQETI4mlis4Ux7YTLvP67xnGxCvq+BcCQSO81qQHVUTM1V53tl4iVVaY5sReCOA==",
5584
+ "dependencies": {
5585
+ "react-router": "7.9.6"
5586
+ },
5587
+ "engines": {
5588
+ "node": ">=20.0.0"
5589
+ },
5590
+ "peerDependencies": {
5591
+ "react": ">=18",
5592
+ "react-dom": ">=18"
5593
+ }
5594
+ },
5595
+ "node_modules/react-router/node_modules/cookie": {
5596
+ "version": "1.0.2",
5597
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
5598
+ "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
5599
+ "engines": {
5600
+ "node": ">=18"
5601
+ }
5602
+ },
5603
  "node_modules/readable-stream": {
5604
  "version": "3.6.2",
5605
  "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
 
5782
  "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
5783
  "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
5784
  },
5785
+ "node_modules/scheduler": {
5786
+ "version": "0.27.0",
5787
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
5788
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
5789
+ "peer": true
5790
+ },
5791
  "node_modules/semver": {
5792
  "version": "6.3.1",
5793
  "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
 
5832
  "node": ">= 18"
5833
  }
5834
  },
5835
+ "node_modules/set-cookie-parser": {
5836
+ "version": "2.7.2",
5837
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
5838
+ "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="
5839
+ },
5840
  "node_modules/set-function-length": {
5841
  "version": "1.2.2",
5842
  "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
package.json CHANGED
@@ -14,45 +14,51 @@
14
  "type": "git",
15
  "url": "https://huggingface.co/spaces/nexusbert/zurri"
16
  },
17
- "keywords": ["ai", "agents", "marketplace", "chat"],
 
 
 
 
 
18
  "author": "",
19
  "license": "ISC",
20
  "dependencies": {
21
- "express": "*",
22
- "typeorm": "*",
23
- "pg": "*",
24
- "jsonwebtoken": "*",
25
- "dotenv": "*",
26
- "cors": "*",
27
- "helmet": "*",
28
- "express-rate-limit": "*",
29
  "axios": "*",
30
- "uuid": "*",
31
- "reflect-metadata": "*",
32
  "bcryptjs": "*",
33
- "pinata": "*",
34
- "multer": "*",
 
 
35
  "form-data": "*",
36
- "swagger-ui-express": "*",
 
 
 
 
 
 
 
37
  "swagger-jsdoc": "*",
38
- "paystack-node": "*"
 
 
39
  },
40
  "devDependencies": {
 
 
41
  "@types/express": "*",
42
- "@types/node": "*",
43
  "@types/jsonwebtoken": "*",
44
- "@types/cors": "*",
45
- "@types/uuid": "*",
46
- "@types/bcryptjs": "*",
47
  "@types/multer": "*",
48
- "@types/jest": "*",
49
- "typescript": "*",
50
- "ts-node-dev": "*",
51
- "jest": "*",
52
- "ts-jest": "*",
53
- "supertest": "*",
54
  "@types/supertest": "*",
 
55
  "@types/swagger-ui-express": "*",
56
- "@types/swagger-jsdoc": "*"
 
 
 
 
 
57
  }
58
  }
 
14
  "type": "git",
15
  "url": "https://huggingface.co/spaces/nexusbert/zurri"
16
  },
17
+ "keywords": [
18
+ "ai",
19
+ "agents",
20
+ "marketplace",
21
+ "chat"
22
+ ],
23
  "author": "",
24
  "license": "ISC",
25
  "dependencies": {
 
 
 
 
 
 
 
 
26
  "axios": "*",
 
 
27
  "bcryptjs": "*",
28
+ "cors": "*",
29
+ "dotenv": "*",
30
+ "express": "*",
31
+ "express-rate-limit": "*",
32
  "form-data": "*",
33
+ "helmet": "*",
34
+ "jsonwebtoken": "*",
35
+ "multer": "*",
36
+ "paystack-node": "*",
37
+ "pg": "*",
38
+ "pinata": "*",
39
+ "react-router-dom": "^7.9.6",
40
+ "reflect-metadata": "*",
41
  "swagger-jsdoc": "*",
42
+ "swagger-ui-express": "*",
43
+ "typeorm": "*",
44
+ "uuid": "*"
45
  },
46
  "devDependencies": {
47
+ "@types/bcryptjs": "*",
48
+ "@types/cors": "*",
49
  "@types/express": "*",
50
+ "@types/jest": "*",
51
  "@types/jsonwebtoken": "*",
 
 
 
52
  "@types/multer": "*",
53
+ "@types/node": "*",
 
 
 
 
 
54
  "@types/supertest": "*",
55
+ "@types/swagger-jsdoc": "*",
56
  "@types/swagger-ui-express": "*",
57
+ "@types/uuid": "*",
58
+ "jest": "*",
59
+ "supertest": "*",
60
+ "ts-jest": "*",
61
+ "ts-node-dev": "*",
62
+ "typescript": "*"
63
  }
64
  }
src/scripts/createAdmin.ts CHANGED
@@ -10,8 +10,13 @@ if (fs.existsSync(envPath)) {
10
  dotenv.config();
11
  }
12
 
13
- const ADMIN_EMAIL = (process.env.EMAIL || 'omezirizion@gmail.com').trim();
14
- const ADMIN_PASSWORD = (process.env.PASSWORD || 'Amazon1@').trim();
 
 
 
 
 
15
 
16
  console.log('πŸ“§ Admin Email:', ADMIN_EMAIL);
17
  console.log('πŸ”‘ Password:', ADMIN_PASSWORD ? 'SET' : 'NOT SET');
@@ -22,7 +27,82 @@ import { AppDataSource } from '../config/database';
22
  import { User } from '../entities/User';
23
  import bcrypt from 'bcryptjs';
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  async function createAdmin() {
 
 
 
 
 
 
 
 
26
  try {
27
  console.log('\nπŸ”§ Initializing database connection...');
28
  await AppDataSource.initialize();
@@ -30,43 +110,40 @@ async function createAdmin() {
30
 
31
  const userRepository = AppDataSource.getRepository(User);
32
 
33
- console.log(`\nπŸ” Looking for user: ${ADMIN_EMAIL}`);
34
 
35
- let user = await userRepository.findOne({ where: { email: ADMIN_EMAIL.toLowerCase() } });
36
 
37
  if (user) {
38
- console.log('βœ… User found, updating to admin...');
39
  user.isAdmin = true;
40
  user.isActive = true;
41
 
42
- const passwordValidation = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]).{8,}$/;
43
- if (passwordValidation.test(ADMIN_PASSWORD)) {
44
- const hashedPassword = await bcrypt.hash(ADMIN_PASSWORD, 12);
45
- user.password = hashedPassword;
46
- console.log('βœ… Password updated');
47
- }
48
 
49
  await userRepository.save(user);
50
- console.log('βœ… User updated to admin successfully!');
51
  console.log(`\nπŸ“§ Email: ${user.email}`);
52
  console.log(`πŸ‘€ Admin: ${user.isAdmin}`);
53
  console.log(`πŸ†” User ID: ${user.id}`);
54
  } else {
55
- console.log('⚠️ User not found, creating new admin user...');
56
 
57
- const hashedPassword = await bcrypt.hash(ADMIN_PASSWORD, 12);
58
 
59
  user = userRepository.create({
60
- email: ADMIN_EMAIL.toLowerCase(),
61
  password: hashedPassword,
62
- name: 'Admin User',
63
  isAdmin: true,
64
  isActive: true,
65
  isCreator: false,
66
  });
67
 
68
  await userRepository.save(user);
69
- console.log('βœ… Admin user created successfully!');
70
  console.log(`\nπŸ“§ Email: ${user.email}`);
71
  console.log(`πŸ‘€ Admin: ${user.isAdmin}`);
72
  console.log(`πŸ†” User ID: ${user.id}`);
@@ -85,4 +162,7 @@ async function createAdmin() {
85
  }
86
  }
87
 
88
- createAdmin();
 
 
 
 
10
  dotenv.config();
11
  }
12
 
13
+ const ADMIN_EMAIL = process.env.ADMIN_EMAIL?.trim();
14
+ const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD?.trim();
15
+
16
+ if (!ADMIN_EMAIL || !ADMIN_PASSWORD) {
17
+ console.error('❌ ADMIN_EMAIL and ADMIN_PASSWORD must be set in environment variables');
18
+ process.exit(1);
19
+ }
20
 
21
  console.log('πŸ“§ Admin Email:', ADMIN_EMAIL);
22
  console.log('πŸ”‘ Password:', ADMIN_PASSWORD ? 'SET' : 'NOT SET');
 
27
  import { User } from '../entities/User';
28
  import bcrypt from 'bcryptjs';
29
 
30
+ /**
31
+ * Initialize permanent admin user from environment variables
32
+ * This ensures the admin user always exists and maintains admin status
33
+ */
34
+ export async function initializeAdmin(): Promise<void> {
35
+ const adminEmail = process.env.ADMIN_EMAIL?.trim();
36
+ const adminPassword = process.env.ADMIN_PASSWORD?.trim();
37
+
38
+ if (!adminEmail || !adminPassword) {
39
+ console.log('⚠️ ADMIN_EMAIL and ADMIN_PASSWORD not set - skipping admin initialization');
40
+ return;
41
+ }
42
+
43
+ try {
44
+ // Check if database is already initialized
45
+ if (!AppDataSource.isInitialized) {
46
+ await AppDataSource.initialize();
47
+ }
48
+
49
+ const userRepository = AppDataSource.getRepository(User);
50
+
51
+ let user = await userRepository.findOne({ where: { email: adminEmail.toLowerCase() } });
52
+
53
+ if (user) {
54
+ // User exists - ensure they are admin and update password if needed
55
+ const needsUpdate = !user.isAdmin || !user.isActive;
56
+
57
+ if (needsUpdate) {
58
+ user.isAdmin = true;
59
+ user.isActive = true;
60
+ console.log(`βœ… Updated user ${adminEmail} to admin status`);
61
+ }
62
+
63
+ // Always update password to match env (ensures it stays in sync)
64
+ const hashedPassword = await bcrypt.hash(adminPassword, 12);
65
+ user.password = hashedPassword;
66
+
67
+ await userRepository.save(user);
68
+ console.log(`βœ… Permanent admin user maintained: ${adminEmail}`);
69
+ } else {
70
+ // Create new admin user
71
+ const hashedPassword = await bcrypt.hash(adminPassword, 12);
72
+
73
+ user = userRepository.create({
74
+ email: adminEmail.toLowerCase(),
75
+ password: hashedPassword,
76
+ name: process.env.ADMIN_NAME || 'Admin User',
77
+ isAdmin: true,
78
+ isActive: true,
79
+ isCreator: false,
80
+ });
81
+
82
+ await userRepository.save(user);
83
+ console.log(`βœ… Permanent admin user created: ${adminEmail}`);
84
+ }
85
+ } catch (error) {
86
+ console.error('❌ Error initializing admin:', error);
87
+ if (error instanceof Error) {
88
+ console.error('Error message:', error.message);
89
+ }
90
+ // Don't throw - allow app to continue even if admin init fails
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Standalone script to create/update admin user
96
+ */
97
  async function createAdmin() {
98
+ const adminEmail = ADMIN_EMAIL;
99
+ const adminPassword = ADMIN_PASSWORD;
100
+
101
+ if (!adminEmail || !adminPassword) {
102
+ console.error('❌ ADMIN_EMAIL and ADMIN_PASSWORD must be set in environment variables');
103
+ process.exit(1);
104
+ }
105
+
106
  try {
107
  console.log('\nπŸ”§ Initializing database connection...');
108
  await AppDataSource.initialize();
 
110
 
111
  const userRepository = AppDataSource.getRepository(User);
112
 
113
+ console.log(`\nπŸ” Looking for user: ${adminEmail}`);
114
 
115
+ let user = await userRepository.findOne({ where: { email: adminEmail.toLowerCase() } });
116
 
117
  if (user) {
118
+ console.log('βœ… User found, updating to permanent admin...');
119
  user.isAdmin = true;
120
  user.isActive = true;
121
 
122
+ const hashedPassword = await bcrypt.hash(adminPassword, 12);
123
+ user.password = hashedPassword;
124
+ console.log('βœ… Password updated');
 
 
 
125
 
126
  await userRepository.save(user);
127
+ console.log('βœ… User updated to permanent admin successfully!');
128
  console.log(`\nπŸ“§ Email: ${user.email}`);
129
  console.log(`πŸ‘€ Admin: ${user.isAdmin}`);
130
  console.log(`πŸ†” User ID: ${user.id}`);
131
  } else {
132
+ console.log('⚠️ User not found, creating new permanent admin user...');
133
 
134
+ const hashedPassword = await bcrypt.hash(adminPassword, 12);
135
 
136
  user = userRepository.create({
137
+ email: adminEmail.toLowerCase(),
138
  password: hashedPassword,
139
+ name: process.env.ADMIN_NAME || 'Admin User',
140
  isAdmin: true,
141
  isActive: true,
142
  isCreator: false,
143
  });
144
 
145
  await userRepository.save(user);
146
+ console.log('βœ… Permanent admin user created successfully!');
147
  console.log(`\nπŸ“§ Email: ${user.email}`);
148
  console.log(`πŸ‘€ Admin: ${user.isAdmin}`);
149
  console.log(`πŸ†” User ID: ${user.id}`);
 
162
  }
163
  }
164
 
165
+ // Only run if this file is executed directly (not imported)
166
+ if (require.main === module) {
167
+ createAdmin();
168
+ }
src/server.ts CHANGED
@@ -21,6 +21,7 @@ if (!isHuggingFaceSpace && !isProduction) {
21
  import 'reflect-metadata';
22
  import { AppDataSource } from './config/database';
23
  import app from './app';
 
24
 
25
  const PORT = parseInt(process.env.PORT || process.env.SPACE_PORT || '7860', 10);
26
 
@@ -51,6 +52,9 @@ AppDataSource.initialize()
51
  }
52
  }
53
 
 
 
 
54
  app.listen(PORT, '0.0.0.0', () => {
55
  console.log(`πŸš€ Server running on port ${PORT}`);
56
  console.log(`🌍 Server accessible at http://0.0.0.0:${PORT}`);
 
21
  import 'reflect-metadata';
22
  import { AppDataSource } from './config/database';
23
  import app from './app';
24
+ import { initializeAdmin } from './scripts/createAdmin';
25
 
26
  const PORT = parseInt(process.env.PORT || process.env.SPACE_PORT || '7860', 10);
27
 
 
52
  }
53
  }
54
 
55
+ // Initialize permanent admin user from environment variables
56
+ await initializeAdmin();
57
+
58
  app.listen(PORT, '0.0.0.0', () => {
59
  console.log(`πŸš€ Server running on port ${PORT}`);
60
  console.log(`🌍 Server accessible at http://0.0.0.0:${PORT}`);
zurri-mock-frontend CHANGED
@@ -1 +1 @@
1
- Subproject commit 5bd3ab29cf56611ae3a97d0fdd81f97ddb9fa1d2
 
1
+ Subproject commit 05aab1df678d680e947fa3e24b05c8fd35266c7b
zurriwebsite ADDED
@@ -0,0 +1 @@
 
 
1
+ Subproject commit 4013f080c954f64ecc95a16ae6477460eb8b0762