powr-sdk-api 2.3.6 → 2.3.8

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/config.js CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  const config = {
4
4
  mongoUri: process.env.POWR_DB_URI,
5
- projectId: process.env.PROJECT_ID,
6
- jwtToken: process.env.JWT_TOKEN,
7
- storageBucket: process.env.STORAGE_BUCKET
5
+ jwtToken: process.env.JWT_TOKEN
8
6
  };
9
7
  module.exports = config;
@@ -5,10 +5,11 @@ const {
5
5
  ObjectId
6
6
  } = require('mongodb');
7
7
  const config = require('../config');
8
- const generateJWTToken = user => {
8
+ const generateJWTToken = (user, profile = null) => {
9
9
  return jwt.sign({
10
10
  userId: user._id,
11
- fullName: user.fullName
11
+ fullName: user.fullName,
12
+ access: profile === null || profile === void 0 ? void 0 : profile.access
12
13
  }, config.jwtToken, {
13
14
  expiresIn: '24h'
14
15
  });
@@ -28,20 +29,21 @@ const verifyToken = async (req, res, next) => {
28
29
 
29
30
  // Extract token (remove 'Bearer ' if present)
30
31
  const token = authHeader.startsWith("Bearer ") ? authHeader.slice(7) : authHeader;
32
+ if (!token) {
33
+ return res.status(401).json({
34
+ success: false,
35
+ message: 'No token provided'
36
+ });
37
+ }
31
38
 
32
39
  // Verify JWT token
33
40
  const decoded = jwt.verify(token, config.jwtToken);
34
41
  console.log("JWT Decoded user data:", JSON.stringify(decoded, null, 2));
35
-
36
- // Attach user info to request object
37
42
  req.user = {
38
- powrId: new ObjectId(decoded.userId),
39
- // powr-base user ID
40
- fullName: decoded.fullName // User's full name
43
+ powrId: decoded.userId,
44
+ fullName: decoded.fullName,
45
+ access: decoded.access
41
46
  };
42
- console.log("Authenticated user:", {
43
- powrId: req.user.powrId
44
- });
45
47
  next();
46
48
  } catch (error) {
47
49
  console.error("Error in auth middleware:", error);
@@ -23,7 +23,8 @@ router.post("/register", async (req, res) => {
23
23
  fullName,
24
24
  username,
25
25
  phoneOrEmail,
26
- password
26
+ password,
27
+ projectId
27
28
  } = req.body;
28
29
  try {
29
30
  if (!(username || phoneOrEmail)) {
@@ -44,6 +45,14 @@ router.post("/register", async (req, res) => {
44
45
  message: "Full name is required"
45
46
  });
46
47
  }
48
+
49
+ // if (!projectId) {
50
+ // return res.status(400).json({
51
+ // success: false,
52
+ // message: "Project ID is required"
53
+ // });
54
+ // }
55
+
47
56
  let q = username ? {
48
57
  username: username
49
58
  } : {
@@ -72,6 +81,15 @@ router.post("/register", async (req, res) => {
72
81
  createdAt: new Date()
73
82
  };
74
83
  const result = await getDb().collection("users").insertOne(newUser);
84
+ if (projectId) {
85
+ const newProfile = {
86
+ userId: result.insertedId,
87
+ projectId: projectId,
88
+ createdAt: new Date(),
89
+ updatedAt: new Date()
90
+ };
91
+ await getDb().collection("profiles").insertOne(newProfile);
92
+ }
75
93
  return res.status(201).json({
76
94
  success: true,
77
95
  message: "User registered successfully",
@@ -91,7 +109,8 @@ router.post("/login", async (req, res) => {
91
109
  const {
92
110
  username,
93
111
  phoneOrEmail,
94
- password
112
+ password,
113
+ projectId
95
114
  } = req.body;
96
115
  try {
97
116
  if (!(username || phoneOrEmail)) {
@@ -131,15 +150,66 @@ router.post("/login", async (req, res) => {
131
150
  message: "Invalid username or password."
132
151
  });
133
152
  }
134
- const token = generateJWTToken(user);
153
+
154
+ // Fetch profile data if projectId is provided
155
+ let profile = null;
156
+ if (projectId) {
157
+ profile = await getDb().collection("profiles").findOne({
158
+ userId: user._id,
159
+ projectId: projectId
160
+ });
161
+ if (profile) {
162
+ // Update lastActiveAt
163
+ await getDb().collection("profiles").updateOne({
164
+ _id: profile._id
165
+ }, {
166
+ $set: {
167
+ lastActiveAt: new Date()
168
+ }
169
+ });
170
+ } else {
171
+ // Create profile if it doesn't exist - only essential fields
172
+ const newProfile = {
173
+ userId: user._id,
174
+ projectId: projectId,
175
+ createdAt: new Date(),
176
+ updatedAt: new Date()
177
+ };
178
+ const profileResult = await getDb().collection("profiles").insertOne(newProfile);
179
+ profile = {
180
+ _id: profileResult.insertedId,
181
+ ...newProfile
182
+ };
183
+ }
184
+ }
185
+ const token = generateJWTToken(user, profile);
135
186
  const {
136
187
  password: _,
188
+ _id,
137
189
  ...userWithoutPassword
138
190
  } = user;
191
+ let mergedUser = {
192
+ ...userWithoutPassword,
193
+ powrId: user._id
194
+ };
195
+ if (profile) {
196
+ const {
197
+ _id,
198
+ userId,
199
+ projectId,
200
+ createdAt,
201
+ updatedAt,
202
+ ...profileData
203
+ } = profile;
204
+ mergedUser = {
205
+ ...mergedUser,
206
+ ...profileData
207
+ };
208
+ }
139
209
  return res.status(200).json({
140
210
  success: true,
141
211
  message: "Login successful",
142
- user: userWithoutPassword,
212
+ user: mergedUser,
143
213
  token: token
144
214
  });
145
215
  } catch (error) {
@@ -3,11 +3,7 @@
3
3
  const express = require('express');
4
4
  const multer = require('multer');
5
5
  // const { uploadToGCS, bucket } = require('../uploadToGCS')
6
- const {
7
- bucket,
8
- uploadToGCS,
9
- bucketName
10
- } = require('../uploadToGCS.js');
6
+ // const { bucket, uploadToGCS, bucketName } = require('../uploadToGCS.js')
11
7
  // const uploadToGCS = require('../uploadToGCS.js')
12
8
 
13
9
  const router = express.Router();
@@ -20,11 +16,13 @@ router.post('/', upload.single('file'), async (req, res) => {
20
16
  message: 'No file uploaded'
21
17
  });
22
18
  }
23
- const url = await uploadToGCS(req.file);
19
+
20
+ // const url = await uploadToGCS(req.file);
21
+
24
22
  return res.status(200).json({
25
23
  status: 'success',
26
- message: 'File uploaded successfully',
27
- url
24
+ message: 'File uploaded successfully'
25
+ // url,
28
26
  });
29
27
  } catch (err) {
30
28
  console.error('Error uploading file:', err);
@@ -37,12 +35,13 @@ router.post('/', upload.single('file'), async (req, res) => {
37
35
  });
38
36
  router.get('/', async (req, res) => {
39
37
  try {
40
- const [files] = await bucket.getFiles();
41
- const bucketName = bucket.name;
42
- const imageUrls = files.map(file => `https://storage.googleapis.com/${bucketName}/${file.name}`);
38
+ // const [files] = await bucket.getFiles();
39
+ // const bucketName = bucket.name;
40
+ // const imageUrls = files.map(file => `https://storage.googleapis.com/${bucketName}/${file.name}`);
41
+
43
42
  return res.status(200).json({
44
- message: 'Images fetched successfully',
45
- images: imageUrls
43
+ message: 'Images fetched successfully'
44
+ // images: imageUrls,
46
45
  });
47
46
  } catch (err) {
48
47
  console.error('Error listing files from GCS:', err);
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  const express = require('express');
4
+ const config = require('../config');
4
5
 
5
6
  // Import all route modules
6
7
  const commentsRoutes = require('./comments');
@@ -17,17 +18,30 @@ const authRoutes = require('./auth');
17
18
  const blogsRoutes = require('./blogs');
18
19
  const slidesRoutes = require('./slides');
19
20
  const notificationsRoutes = require('./notifications');
20
- const createPowrRoutes = () => {
21
+ const profilesRoutes = require('./profiles');
22
+ const createPowrRoutes = (options = {}) => {
21
23
  const router = express.Router();
22
24
 
25
+ // Check if this is a central service (like powr-base-cloud)
26
+ const isCentralService = options.isCentralService || false;
27
+
23
28
  // Middleware to inject projectId into all requests
24
29
  router.use((req, res, next) => {
25
30
  try {
26
- const {
27
- getConfig
28
- } = require('../config');
29
- const config = getConfig();
30
- req.projectId = config.projectId;
31
+ if (isCentralService) {
32
+ // For central services, get projectId from request
33
+ const projectId = req.query.projectId || req.body.projectId;
34
+ if (!projectId) {
35
+ return res.status(400).json({
36
+ success: false,
37
+ message: 'projectId is required for central services'
38
+ });
39
+ }
40
+ req.projectId = projectId;
41
+ } else {
42
+ // For individual APIs, use config.projectId
43
+ req.projectId = config.projectId;
44
+ }
31
45
  } catch (error) {
32
46
  console.error('❌ Config error:', error.message);
33
47
  return res.status(500).json({
@@ -38,8 +52,6 @@ const createPowrRoutes = () => {
38
52
  }
39
53
  next();
40
54
  });
41
-
42
- // Mount all route modules
43
55
  router.use('/comments', commentsRoutes);
44
56
  // router.use('/files', filesRoutes); // Commented out for now
45
57
  router.use('/forms', formsRoutes);
@@ -54,6 +66,7 @@ const createPowrRoutes = () => {
54
66
  router.use('/blogs', blogsRoutes);
55
67
  router.use('/slides', slidesRoutes);
56
68
  router.use('/notifications', notificationsRoutes);
69
+ router.use('/profiles', profilesRoutes);
57
70
  return router;
58
71
  };
59
72
  module.exports = {
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+
3
+ const express = require("express");
4
+ const router = express.Router();
5
+ const {
6
+ getDb
7
+ } = require("../services/dbService");
8
+
9
+ // Get all users for a project
10
+ router.get("/", async (req, res) => {
11
+ try {
12
+ const {
13
+ projectId
14
+ } = req.query;
15
+ const profiles = await getDb().collection("profiles").find({
16
+ projectId: projectId
17
+ }).toArray();
18
+ if (profiles.length === 0) {
19
+ return res.status(200).json({
20
+ success: true,
21
+ users: []
22
+ });
23
+ }
24
+
25
+ // Get core user data for all profiles
26
+ const userIds = profiles.map(profile => profile.userId);
27
+ const users = await getDb().collection("users").find({
28
+ _id: {
29
+ $in: userIds
30
+ }
31
+ }).toArray();
32
+
33
+ // Create a map for quick lookup
34
+ const usersMap = users.reduce((acc, user) => {
35
+ const {
36
+ password,
37
+ ...userWithoutPassword
38
+ } = user;
39
+ acc[user._id.toString()] = userWithoutPassword;
40
+ return acc;
41
+ }, {});
42
+
43
+ // Merge user and profile data
44
+ const usersWithProfiles = profiles.map(profile => ({
45
+ ...usersMap[profile.userId.toString()],
46
+ ...profile
47
+ }));
48
+ return res.status(200).json({
49
+ success: true,
50
+ users: usersWithProfiles
51
+ });
52
+ } catch (error) {
53
+ console.error("Error fetching project users:", error);
54
+ return res.status(500).json({
55
+ success: false,
56
+ message: "Failed to fetch project users"
57
+ });
58
+ }
59
+ });
60
+ module.exports = router;
@@ -3,38 +3,40 @@
3
3
  const {
4
4
  MongoClient
5
5
  } = require('mongodb');
6
-
7
- // Database service with lazy connection
8
- let client = null;
9
- let db = null;
10
- const getDb = async () => {
11
- // Return existing connection if available
12
- if (db) {
13
- return db;
14
- }
15
-
16
- // Connect only when first needed
6
+ const {
7
+ config
8
+ } = require('../config');
9
+ const mongoClient = new MongoClient(config.mongoUri, {
10
+ maxPoolSize: 10,
11
+ serverSelectionTimeoutMS: 5000,
12
+ socketTimeoutMS: 45000
13
+ });
14
+ let db;
15
+ async function connect() {
17
16
  try {
18
- const config = require('../config').getConfig();
19
- client = new MongoClient(config.mongoUri);
20
- await client.connect();
21
- db = client.db();
22
- console.log('✅ Connected to MongoDB via SDK (lazy connection)');
23
- return db;
17
+ await mongoClient.connect();
18
+ db = mongoClient.db();
19
+ console.log("Connected to MongoDB via SDK");
24
20
  } catch (error) {
25
- console.error('❌ MongoDB connection error:', error);
26
- throw error;
21
+ console.error("Failed to connect to MongoDB:", error);
22
+ process.exit(1);
27
23
  }
28
- };
24
+ }
25
+ function getDb() {
26
+ if (!db) {
27
+ throw new Error("Database not initialized. Call connectToMongo() first.");
28
+ }
29
+ return db;
30
+ }
29
31
  const closeConnection = async () => {
30
- if (client) {
31
- await client.close();
32
- client = null;
32
+ if (mongoClient) {
33
+ await mongoClient.close();
33
34
  db = null;
34
35
  console.log('✅ MongoDB connection closed');
35
36
  }
36
37
  };
37
38
  module.exports = {
39
+ connect,
38
40
  getDb,
39
41
  closeConnection
40
42
  };
package/package.json CHANGED
@@ -1,67 +1,67 @@
1
- {
2
- "name": "powr-sdk-api",
3
- "version": "2.3.6",
4
- "description": "Shared API core library for PowrStack projects",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "files": [
8
- "dist",
9
- "README.md"
10
- ],
11
- "scripts": {
12
- "test": "jest --passWithNoTests",
13
- "lint": "eslint .",
14
- "build": "babel src -d dist",
15
- "prepare": "npm run build",
16
- "prepublishOnly": "npm run test"
17
- },
18
- "keywords": [
19
- "api",
20
- "express",
21
- "middleware",
22
- "error-handling",
23
- "response-formatting",
24
- "logging",
25
- "swagger",
26
- "documentation"
27
- ],
28
- "author": "PowrStack",
29
- "license": "ISC",
30
- "repository": {
31
- "type": "git",
32
- "url": "git+https://github.com/powrstack/powr-sdk-api.git"
33
- },
34
- "bugs": {
35
- "url": "https://github.com/powrstack/powr-sdk-api/issues"
36
- },
37
- "homepage": "https://github.com/powrstack/powr-sdk-api#readme",
38
- "dependencies": {
39
- "@aws-sdk/client-s3": "^3.787.0",
40
- "@google-cloud/storage": "^7.16.0",
41
- "express": "^4.18.2",
42
- "jsonwebtoken": "^9.0.2",
43
- "swagger-jsdoc": "^6.2.8",
44
- "swagger-ui-express": "^5.0.0",
45
- "winston": "^3.17.0",
46
- "mongodb": "^6.3.0",
47
- "multer": "^1.4.5-lts.1",
48
- "bcrypt": "^5.1.1"
49
- },
50
- "devDependencies": {
51
- "@babel/cli": "^7.23.9",
52
- "@babel/core": "^7.24.0",
53
- "@babel/preset-env": "^7.24.0",
54
- "@types/express": "^4.17.21",
55
- "@types/swagger-jsdoc": "^6.0.4",
56
- "@types/swagger-ui-express": "^4.1.6",
57
- "eslint": "^8.57.0",
58
- "jest": "^29.7.0",
59
- "typescript": "^5.3.3"
60
- },
61
- "peerDependencies": {
62
- "express": "^4.18.2"
63
- },
64
- "engines": {
65
- "node": ">=14.0.0"
66
- }
67
- }
1
+ {
2
+ "name": "powr-sdk-api",
3
+ "version": "2.3.8",
4
+ "description": "Shared API core library for PowrStack projects",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "README.md"
10
+ ],
11
+ "scripts": {
12
+ "test": "jest --passWithNoTests",
13
+ "lint": "eslint .",
14
+ "build": "babel src -d dist",
15
+ "prepare": "npm run build",
16
+ "prepublishOnly": "npm run test"
17
+ },
18
+ "keywords": [
19
+ "api",
20
+ "express",
21
+ "middleware",
22
+ "error-handling",
23
+ "response-formatting",
24
+ "logging",
25
+ "swagger",
26
+ "documentation"
27
+ ],
28
+ "author": "PowrStack",
29
+ "license": "ISC",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/powrstack/powr-sdk-api.git"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/powrstack/powr-sdk-api/issues"
36
+ },
37
+ "homepage": "https://github.com/powrstack/powr-sdk-api#readme",
38
+ "dependencies": {
39
+ "@aws-sdk/client-s3": "^3.787.0",
40
+ "@google-cloud/storage": "^7.16.0",
41
+ "express": "^4.18.2",
42
+ "jsonwebtoken": "^9.0.2",
43
+ "swagger-jsdoc": "^6.2.8",
44
+ "swagger-ui-express": "^5.0.0",
45
+ "winston": "^3.17.0",
46
+ "mongodb": "^6.3.0",
47
+ "multer": "^1.4.5-lts.1",
48
+ "bcrypt": "^5.1.1"
49
+ },
50
+ "devDependencies": {
51
+ "@babel/cli": "^7.23.9",
52
+ "@babel/core": "^7.24.0",
53
+ "@babel/preset-env": "^7.24.0",
54
+ "@types/express": "^4.17.21",
55
+ "@types/swagger-jsdoc": "^6.0.4",
56
+ "@types/swagger-ui-express": "^4.1.6",
57
+ "eslint": "^8.57.0",
58
+ "jest": "^29.7.0",
59
+ "typescript": "^5.3.3"
60
+ },
61
+ "peerDependencies": {
62
+ "express": "^4.18.2"
63
+ },
64
+ "engines": {
65
+ "node": ">=14.0.0"
66
+ }
67
+ }