powr-sdk-api 4.8.7 → 4.9.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.
@@ -20,6 +20,57 @@ const {
20
20
  const {
21
21
  getClientIp
22
22
  } = require("../utils/getClientIp");
23
+ const {
24
+ normalizePhone,
25
+ getPhoneLookupVariants
26
+ } = require("../utils/phone");
27
+ function buildIdentifierQuery({
28
+ username,
29
+ phoneOrEmail
30
+ }) {
31
+ if (username) {
32
+ return {
33
+ username
34
+ };
35
+ }
36
+ if (!phoneOrEmail) {
37
+ return null;
38
+ }
39
+ if (phoneOrEmail.includes("@")) {
40
+ return {
41
+ $or: [{
42
+ phoneNumber: phoneOrEmail
43
+ }, {
44
+ email: phoneOrEmail
45
+ }]
46
+ };
47
+ }
48
+ const variants = getPhoneLookupVariants(phoneOrEmail);
49
+ return {
50
+ phoneNumber: {
51
+ $in: variants
52
+ }
53
+ };
54
+ }
55
+ function resolveStoredContact(phoneOrEmail) {
56
+ if (!phoneOrEmail) {
57
+ return {
58
+ email: "",
59
+ phoneNumber: ""
60
+ };
61
+ }
62
+ if (phoneOrEmail.includes("@")) {
63
+ return {
64
+ email: phoneOrEmail,
65
+ phoneNumber: phoneOrEmail
66
+ };
67
+ }
68
+ const phoneNumber = normalizePhone(phoneOrEmail);
69
+ return {
70
+ email: "",
71
+ phoneNumber
72
+ };
73
+ }
23
74
 
24
75
  // Register User
25
76
  router.post("/register", async (req, res) => {
@@ -50,15 +101,16 @@ router.post("/register", async (req, res) => {
50
101
  message: "Full name is required"
51
102
  });
52
103
  }
53
- let q = username ? {
54
- username: username
55
- } : {
56
- $or: [{
57
- phoneNumber: phoneOrEmail
58
- }, {
59
- email: phoneOrEmail
60
- }]
61
- };
104
+ let q = buildIdentifierQuery({
105
+ username,
106
+ phoneOrEmail
107
+ });
108
+ if (!q) {
109
+ return res.status(400).json({
110
+ success: false,
111
+ message: "Username or phone number or email is required"
112
+ });
113
+ }
62
114
  console.log(q);
63
115
  const db = await getDb();
64
116
  const existingUser = await db.collection("users").findOne(q);
@@ -70,10 +122,11 @@ router.post("/register", async (req, res) => {
70
122
  }
71
123
  const saltRounds = 10;
72
124
  const hashedPassword = await bcrypt.hash(password, saltRounds);
125
+ const contact = resolveStoredContact(phoneOrEmail);
73
126
  const newUser = {
74
127
  fullName,
75
- email: phoneOrEmail,
76
- phoneNumber: phoneOrEmail,
128
+ email: contact.email,
129
+ phoneNumber: contact.phoneNumber,
77
130
  username,
78
131
  password: hashedPassword,
79
132
  createdAt: new Date()
@@ -126,15 +179,16 @@ router.post("/login", async (req, res) => {
126
179
  message: "Password is required"
127
180
  });
128
181
  }
129
- let q = username ? {
130
- username: username
131
- } : {
132
- $or: [{
133
- phoneNumber: phoneOrEmail
134
- }, {
135
- email: phoneOrEmail
136
- }]
137
- };
182
+ let q = buildIdentifierQuery({
183
+ username,
184
+ phoneOrEmail
185
+ });
186
+ if (!q) {
187
+ return res.status(400).json({
188
+ success: false,
189
+ message: "Username or phone number or email is required"
190
+ });
191
+ }
138
192
  console.log(q);
139
193
  const db = await getDb();
140
194
  const user = await db.collection("users").findOne(q);
@@ -252,6 +252,7 @@ router.put('/update-form/:formName', verifyToken, async (req, res) => {
252
252
  formTitle,
253
253
  formId,
254
254
  description,
255
+ imageUrl,
255
256
  fields
256
257
  } = req.body;
257
258
  if (!(formTitle !== null && formTitle !== void 0 && formTitle.trim()) || !(formId !== null && formId !== void 0 && formId.trim())) {
@@ -282,6 +283,7 @@ router.put('/update-form/:formName', verifyToken, async (req, res) => {
282
283
  formTitle: formTitle.trim(),
283
284
  formId: formId.trim(),
284
285
  description: (description === null || description === void 0 ? void 0 : description.trim()) || '',
286
+ imageUrl: (imageUrl === null || imageUrl === void 0 ? void 0 : imageUrl.trim()) || '',
285
287
  fields,
286
288
  updatedAt: new Date()
287
289
  };
@@ -14,6 +14,9 @@ const {
14
14
  const {
15
15
  getClientIp
16
16
  } = require("../utils/getClientIp");
17
+ const {
18
+ normalizePhone
19
+ } = require("../utils/phone");
17
20
 
18
21
  // Create User
19
22
  router.post("/", verifyToken, async (req, res) => {
@@ -155,9 +158,10 @@ router.put("/:id", verifyToken, async (req, res) => {
155
158
  }
156
159
 
157
160
  // Update user
161
+ const normalizedPhone = phoneNumber && !String(phoneNumber).includes("@") ? normalizePhone(phoneNumber) : phoneNumber;
158
162
  const updateData = {
159
163
  ...userData,
160
- phoneNumber,
164
+ phoneNumber: normalizedPhone,
161
165
  email,
162
166
  updatedAt: new Date()
163
167
  };
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+
3
+ const {
4
+ parsePhoneNumberFromString,
5
+ getCountries,
6
+ getCountryCallingCode
7
+ } = require('libphonenumber-js');
8
+ const DEFAULT_COUNTRY = 'IN';
9
+ const DEFAULT_COUNTRY_CODE = '91';
10
+ const CALLING_CODE_TO_COUNTRY = {
11
+ '91': 'IN',
12
+ '1': 'US',
13
+ '44': 'GB',
14
+ '971': 'AE',
15
+ '65': 'SG',
16
+ '61': 'AU'
17
+ };
18
+ function digitsOnly(value) {
19
+ return (value || '').replace(/\D/g, '');
20
+ }
21
+ function parsePhone(input, defaultCountry = DEFAULT_COUNTRY) {
22
+ var _parsed, _parsed2, _parsed3;
23
+ if (!input || typeof input !== 'string' || input.includes('@')) return null;
24
+ const trimmed = input.trim();
25
+ if (!trimmed) return null;
26
+ let parsed = parsePhoneNumberFromString(trimmed);
27
+ if (!((_parsed = parsed) !== null && _parsed !== void 0 && _parsed.isValid())) {
28
+ parsed = parsePhoneNumberFromString(trimmed, defaultCountry);
29
+ }
30
+ if (!((_parsed2 = parsed) !== null && _parsed2 !== void 0 && _parsed2.isValid()) && !trimmed.startsWith('+')) {
31
+ parsed = parsePhoneNumberFromString(`+${digitsOnly(trimmed)}`);
32
+ }
33
+ return (_parsed3 = parsed) !== null && _parsed3 !== void 0 && _parsed3.isValid() ? parsed : null;
34
+ }
35
+ function normalizePhone(input, defaultCountry = DEFAULT_COUNTRY) {
36
+ if (!input || typeof input !== 'string') return '';
37
+ if (input.includes('@')) return input.trim();
38
+ const parsed = parsePhone(input, defaultCountry);
39
+ return parsed ? parsed.format('E.164') : '';
40
+ }
41
+ function isValidPhone(input, defaultCountry = DEFAULT_COUNTRY) {
42
+ if (!input || typeof input !== 'string' || input.includes('@')) return false;
43
+ return !!parsePhone(input, defaultCountry);
44
+ }
45
+ function getLocalPhoneNumber(input, defaultCountry = DEFAULT_COUNTRY) {
46
+ const parsed = parsePhone(input, defaultCountry);
47
+ return parsed ? parsed.nationalNumber : digitsOnly(input).slice(-15);
48
+ }
49
+ function legacyIndiaVariants(input) {
50
+ const digits = digitsOnly(input);
51
+ if (!digits) return [];
52
+ const variants = new Set();
53
+ if (digits.length === 10) {
54
+ variants.add(digits);
55
+ variants.add(`91${digits}`);
56
+ variants.add(`+91${digits}`);
57
+ variants.add(`0${digits}`);
58
+ }
59
+ if (digits.length === 12 && digits.startsWith('91')) {
60
+ const local = digits.slice(2);
61
+ variants.add(local);
62
+ variants.add(`+${digits}`);
63
+ variants.add(digits);
64
+ variants.add(`0${local}`);
65
+ }
66
+ return [...variants];
67
+ }
68
+ function getPhoneLookupVariants(input, defaultCountry = DEFAULT_COUNTRY) {
69
+ if (!input || typeof input !== 'string') return [];
70
+ if (input.includes('@')) return [input.trim()];
71
+ const variants = new Set([input.trim()]);
72
+ const parsed = parsePhone(input, defaultCountry);
73
+ if (parsed) {
74
+ const e164 = parsed.format('E.164');
75
+ variants.add(e164);
76
+ variants.add(e164.replace(/^\+/, ''));
77
+ variants.add(parsed.nationalNumber);
78
+ variants.add(`+${parsed.countryCallingCode}${parsed.nationalNumber}`);
79
+ variants.add(`${parsed.countryCallingCode}${parsed.nationalNumber}`);
80
+ }
81
+ legacyIndiaVariants(input).forEach(v => variants.add(v));
82
+ return [...variants].filter(Boolean);
83
+ }
84
+ module.exports = {
85
+ DEFAULT_COUNTRY,
86
+ DEFAULT_COUNTRY_CODE,
87
+ normalizePhone,
88
+ getLocalPhoneNumber,
89
+ isValidPhone,
90
+ getPhoneLookupVariants,
91
+ parsePhone,
92
+ getCountries,
93
+ getCountryCallingCode
94
+ };
package/package.json CHANGED
@@ -1,72 +1,74 @@
1
- {
2
- "name": "powr-sdk-api",
3
- "version": "4.8.7",
4
- "description": "Shared API core library for PowrStack projects. Zero dependencies - works with Express, Next.js API routes, and other frameworks. All features are optional and install only what you need.",
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
- "nextjs",
22
- "middleware",
23
- "error-handling",
24
- "response-formatting",
25
- "logging",
26
- "swagger",
27
- "documentation",
28
- "optional-dependencies",
29
- "modular",
30
- "framework-agnostic"
31
- ],
32
- "author": "Lawazia Tech",
33
- "license": "ISC",
34
- "repository": {
35
- "type": "git",
36
- "url": "git+https://github.com/powrstack/powr-sdk-api.git"
37
- },
38
- "bugs": {
39
- "url": "https://github.com/powrstack/powr-sdk-api/issues"
40
- },
41
- "homepage": "https://github.com/powrstack/powr-sdk-api#readme",
42
- "dependencies": {},
43
- "optionalDependencies": {
44
- "@aws-sdk/client-s3": "^3.787.0",
45
- "@google-cloud/storage": "^7.16.0",
46
- "date-fns": "^4.1.0",
47
- "axios": "^1.6.0",
48
- "bcrypt": "^5.1.1",
49
- "cron-parser": "^4.9.0",
50
- "express": "^4.18.2",
51
- "jsonwebtoken": "^9.0.2",
52
- "mongodb": "^6.3.0",
53
- "multer": "^1.4.5-lts.1",
54
- "nodemailer": "^6.10.0",
55
- "swagger-jsdoc": "^6.2.8",
56
- "winston": "^3.17.0"
57
- },
58
- "devDependencies": {
59
- "@babel/cli": "^7.23.9",
60
- "@babel/core": "^7.24.0",
61
- "@babel/preset-env": "^7.24.0",
62
- "@types/express": "^4.17.21",
63
- "@types/swagger-jsdoc": "^6.0.4",
64
- "@types/swagger-ui-express": "^4.1.6",
65
- "eslint": "^8.57.0",
66
- "jest": "^29.7.0",
67
- "typescript": "^5.3.3"
68
- },
69
- "engines": {
70
- "node": ">=14.0.0"
71
- }
72
- }
1
+ {
2
+ "name": "powr-sdk-api",
3
+ "version": "4.9.0",
4
+ "description": "Shared API core library for PowrStack projects. Zero dependencies - works with Express, Next.js API routes, and other frameworks. All features are optional and install only what you need.",
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
+ "nextjs",
22
+ "middleware",
23
+ "error-handling",
24
+ "response-formatting",
25
+ "logging",
26
+ "swagger",
27
+ "documentation",
28
+ "optional-dependencies",
29
+ "modular",
30
+ "framework-agnostic"
31
+ ],
32
+ "author": "Lawazia Tech",
33
+ "license": "ISC",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/powrstack/powr-sdk-api.git"
37
+ },
38
+ "bugs": {
39
+ "url": "https://github.com/powrstack/powr-sdk-api/issues"
40
+ },
41
+ "homepage": "https://github.com/powrstack/powr-sdk-api#readme",
42
+ "dependencies": {
43
+ "libphonenumber-js": "^1.12.9"
44
+ },
45
+ "optionalDependencies": {
46
+ "@aws-sdk/client-s3": "^3.787.0",
47
+ "@google-cloud/storage": "^7.16.0",
48
+ "axios": "^1.6.0",
49
+ "bcrypt": "^5.1.1",
50
+ "cron-parser": "^4.9.0",
51
+ "date-fns": "^4.1.0",
52
+ "express": "^4.18.2",
53
+ "jsonwebtoken": "^9.0.2",
54
+ "mongodb": "^6.3.0",
55
+ "multer": "^1.4.5-lts.1",
56
+ "nodemailer": "^6.10.0",
57
+ "swagger-jsdoc": "^6.2.8",
58
+ "winston": "^3.17.0"
59
+ },
60
+ "devDependencies": {
61
+ "@babel/cli": "^7.23.9",
62
+ "@babel/core": "^7.24.0",
63
+ "@babel/preset-env": "^7.24.0",
64
+ "@types/express": "^4.17.21",
65
+ "@types/swagger-jsdoc": "^6.0.4",
66
+ "@types/swagger-ui-express": "^4.1.6",
67
+ "eslint": "^8.57.0",
68
+ "jest": "^29.7.0",
69
+ "typescript": "^5.3.3"
70
+ },
71
+ "engines": {
72
+ "node": ">=14.0.0"
73
+ }
74
+ }