propro-utils 1.6.2 → 1.6.3

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.
@@ -61,55 +61,6 @@ const getAccountProfile = async (redisClient, userSchema, accountId) => {
61
61
  }
62
62
  };
63
63
 
64
- /**
65
- * Consolidates multiple UserGlobalStyles documents for an account into one
66
- * @param {string} accountId - The account ID to consolidate styles for
67
- * @returns {Promise<Object>} The consolidated UserGlobalStyles document
68
- */
69
- async function consolidateGlobalStyles(accountId) {
70
- const userStyleSchema = await ServiceManager.getService("UserStyleSchema");
71
-
72
- // Find all global styles for this account
73
- const allStyles = await userStyleSchema
74
- .find({ accountId })
75
- .sort({ createdAt: 1 })
76
- .options({ allowDiskUse: true });
77
-
78
- if (allStyles.length <= 1) {
79
- return allStyles[0];
80
- }
81
-
82
- // Use the first document as the main one and merge shortcuts from others
83
- const mainStyle = allStyles[0];
84
- const uniqueShortcuts = new Map();
85
-
86
- // Merge all shortcuts, keeping the latest version of each shortcut by ID
87
- allStyles.forEach((style) => {
88
- style.styleShortcuts.forEach((shortcut) => {
89
- uniqueShortcuts.set(shortcut.id.toString(), shortcut);
90
- });
91
- });
92
-
93
- // Update the main style document with consolidated shortcuts
94
- mainStyle.styleShortcuts = Array.from(uniqueShortcuts.values());
95
- await mainStyle.save();
96
-
97
- // Delete other style documents
98
- await userStyleSchema.deleteMany({
99
- accountId,
100
- _id: { $ne: mainStyle._id },
101
- });
102
-
103
- // Update user reference if needed
104
- const userSchema = await ServiceManager.getService("UserSchema");
105
- await userSchema.updateMany(
106
- { accountId },
107
- { userGlobalStyles: mainStyle._id }
108
- );
109
-
110
- return mainStyle;
111
- }
112
-
113
64
  /**
114
65
  * Creates a new user global styles document with default style shortcuts.
115
66
  *
@@ -118,13 +69,6 @@ async function consolidateGlobalStyles(accountId) {
118
69
  * @returns {Promise<Object>} A promise that resolves to the created user global styles object.
119
70
  */
120
71
  async function createUserGlobalStyles(userStyleSchema, accountId) {
121
- // First check if any existing styles need to be consolidated
122
- const existingStyles = await userStyleSchema.find({ accountId });
123
-
124
- if (existingStyles.length > 0) {
125
- return await consolidateGlobalStyles(accountId);
126
- }
127
-
128
72
  return await userStyleSchema.create({
129
73
  id: uuidv4(),
130
74
  styleShortcuts: defaultUserGlobalStyleShortcuts,
@@ -156,7 +100,7 @@ async function createDefaultFolders(folderSchema, accountId) {
156
100
  }
157
101
 
158
102
  const DEFAULT_THEME = {
159
- canvasBackground: "#1E1D1D",
103
+ canvasBackground: "#000000",
160
104
  defaultItemWidth: 200,
161
105
  defaultColor: "#ffffff",
162
106
  fontSize: "16px",
@@ -173,6 +117,8 @@ const DEFAULT_THEME = {
173
117
  * @throws {Error} If there's an issue with database operations or invalid input
174
118
  */
175
119
  const checkIfUserExists = async (accountId) => {
120
+ console.log("Starting checkIfUserExists for accountId:", accountId);
121
+
176
122
  // Input validation
177
123
  if (!accountId || typeof accountId !== "string") {
178
124
  console.warn("Invalid accountId provided:", accountId);
@@ -180,6 +126,8 @@ const checkIfUserExists = async (accountId) => {
180
126
  }
181
127
 
182
128
  try {
129
+ console.log("Loading schemas...");
130
+ // Load all required schemas in parallel
183
131
  const schemaResults = await Promise.all([
184
132
  ServiceManager.getService("UserSchema"),
185
133
  ServiceManager.getService("UserStyleSchema"),
@@ -190,6 +138,14 @@ const checkIfUserExists = async (accountId) => {
190
138
  const [userSchema, userStyleSchema, folderSchema, themeSchema] =
191
139
  schemaResults;
192
140
 
141
+ // Log the status of each schema
142
+ console.log("Schema loading results:", {
143
+ userSchema: userSchema ? "Loaded" : "Not available",
144
+ userStyleSchema: userStyleSchema ? "Loaded" : "Not available",
145
+ folderSchema: folderSchema ? "Loaded" : "Not available",
146
+ themeSchema: themeSchema ? "Loaded" : "Not available",
147
+ });
148
+
193
149
  if (!userSchema) {
194
150
  throw new Error("UserSchema service not available");
195
151
  }
@@ -211,23 +167,83 @@ const checkIfUserExists = async (accountId) => {
211
167
  );
212
168
  }
213
169
 
214
- // Find existing user with populated fields
215
- const user = await userSchema
216
- .findOne({ accountId })
217
- .select("-theme -folderList -userGlobalStyles -mapList")
218
- .lean();
170
+ console.log("Schema loading and validation complete");
171
+
172
+ // Find existing user without excluding fields we need to check
173
+ const user = await userSchema.findOne({ accountId }).lean();
174
+
175
+ console.log("User lookup result:", user ? "User found" : "User not found");
219
176
 
220
177
  if (user) {
178
+ console.log("Updating existing user data...");
221
179
  const updates = [];
222
180
 
223
- // Handle userGlobalStyles
181
+ // Handle userGlobalStyles - check properly if styles exist in the database
224
182
  if (userStyleSchema) {
225
- // Consolidate any duplicate global styles
226
- await consolidateGlobalStyles(accountId);
183
+ // Check if the user has a userGlobalStyles reference
184
+ const hasStyleReference = user.userGlobalStyles != null;
185
+
186
+ if (hasStyleReference) {
187
+ // Verify the referenced style document actually exists
188
+ const styleExists = await userStyleSchema.exists({
189
+ _id: user.userGlobalStyles,
190
+ });
191
+
192
+ if (!styleExists) {
193
+ console.log(
194
+ "User has style reference but document not found, creating new styles..."
195
+ );
196
+ updates.push(
197
+ createUserGlobalStyles(userStyleSchema, accountId).then(
198
+ async (styles) => {
199
+ console.log("UserGlobalStyles created successfully");
200
+ await userSchema.updateOne(
201
+ { _id: user._id },
202
+ { userGlobalStyles: styles._id }
203
+ );
204
+ return styles;
205
+ }
206
+ )
207
+ );
208
+ } else {
209
+ // Style exists, check if it has shortcuts
210
+ const styleDoc = await userStyleSchema.findById(
211
+ user.userGlobalStyles
212
+ );
213
+ if (
214
+ !styleDoc.styleShortcuts ||
215
+ styleDoc.styleShortcuts.length === 0
216
+ ) {
217
+ console.log("Updating empty styleShortcuts with defaults...");
218
+ updates.push(
219
+ userStyleSchema.updateOne(
220
+ { _id: user.userGlobalStyles },
221
+ { styleShortcuts: defaultUserGlobalStyleShortcuts }
222
+ )
223
+ );
224
+ }
225
+ }
226
+ } else {
227
+ // No style reference, create new styles
228
+ console.log("Creating missing userGlobalStyles...");
229
+ updates.push(
230
+ createUserGlobalStyles(userStyleSchema, accountId).then(
231
+ async (styles) => {
232
+ console.log("UserGlobalStyles created successfully");
233
+ await userSchema.updateOne(
234
+ { _id: user._id },
235
+ { userGlobalStyles: styles._id }
236
+ );
237
+ return styles;
238
+ }
239
+ )
240
+ );
241
+ }
227
242
  }
228
243
 
229
244
  // Handle folders
230
245
  if (folderSchema) {
246
+ console.log("Checking folders...");
231
247
  updates.push(
232
248
  (async () => {
233
249
  const existingFolders = await folderSchema
@@ -235,6 +251,7 @@ const checkIfUserExists = async (accountId) => {
235
251
  .select("name")
236
252
  .lean();
237
253
 
254
+ console.log("Existing folders count:", existingFolders.length);
238
255
  const existingFolderNames = new Set(
239
256
  existingFolders.map((f) => f.name)
240
257
  );
@@ -256,6 +273,7 @@ const checkIfUserExists = async (accountId) => {
256
273
 
257
274
  // Handle themes
258
275
  if (themeSchema) {
276
+ console.log("Checking themes...");
259
277
  updates.push(
260
278
  (async () => {
261
279
  const defaultThemeExists = await themeSchema.exists({
@@ -263,6 +281,7 @@ const checkIfUserExists = async (accountId) => {
263
281
  accountId,
264
282
  });
265
283
 
284
+ console.log("Default theme exists:", defaultThemeExists);
266
285
  if (!defaultThemeExists) {
267
286
  const defaultTheme = await themeSchema.create({
268
287
  ...DEFAULT_THEME,
@@ -282,13 +301,12 @@ const checkIfUserExists = async (accountId) => {
282
301
  }
283
302
 
284
303
  // Wait for all updates to complete
304
+ console.log("Waiting for all updates to complete...");
285
305
  await Promise.all(updates);
306
+ console.log("All updates completed successfully");
286
307
 
287
- // Return fresh user data after updates, excluding specified fields
288
- return userSchema
289
- .findOne({ accountId })
290
- .select("-theme -folderList -userGlobalStyles -mapList")
291
- .lean();
308
+ // Return fresh user data after updates
309
+ return userSchema.findOne({ accountId }).lean();
292
310
  }
293
311
 
294
312
  // Create new user with all associated data
@@ -342,10 +360,8 @@ const checkIfUserExists = async (accountId) => {
342
360
  await createDefaultFolders(folderSchema, newUser.id);
343
361
  }
344
362
 
345
- return userSchema
346
- .findById(newUser._id)
347
- .select("-theme -folderList -userGlobalStyles -mapList")
348
- .lean();
363
+ console.log("Operation completed successfully");
364
+ return userSchema.findById(newUser._id).lean();
349
365
  } catch (error) {
350
366
  console.error("Detailed error in checkIfUserExists:", {
351
367
  accountId,
@@ -358,44 +374,7 @@ const checkIfUserExists = async (accountId) => {
358
374
  }
359
375
  };
360
376
 
361
- const updateUserGlobalStyleShortcuts = async (userId, shortcutId, shortcut) => {
362
- try {
363
- const user = await userSchema
364
- .findOne({ id: userId })
365
- .populate("userGlobalStyles");
366
- if (!user) {
367
- throw new Error("User not found");
368
- }
369
-
370
- // Ensure we have consolidated styles
371
- const consolidatedStyles = await consolidateGlobalStyles(user.accountId);
372
-
373
- // Find the index of the shortcut to update
374
- const shortcutIndex = consolidatedStyles.styleShortcuts.findIndex(
375
- (s) => s.id.toString() === shortcutId
376
- );
377
-
378
- if (shortcutIndex === -1) {
379
- // If the shortcut doesn't exist, add it
380
- consolidatedStyles.styleShortcuts.push(shortcut);
381
- } else {
382
- // If the shortcut exists, update it
383
- consolidatedStyles.styleShortcuts[shortcutIndex] = {
384
- ...consolidatedStyles.styleShortcuts[shortcutIndex],
385
- ...shortcut,
386
- };
387
- }
388
-
389
- await consolidatedStyles.save();
390
- return consolidatedStyles;
391
- } catch (error) {
392
- console.error("Error updating user global style shortcuts:", error);
393
- throw error;
394
- }
395
- };
396
-
397
377
  module.exports = {
398
378
  getAccountProfile,
399
379
  checkIfUserExists,
400
- updateUserGlobalStyleShortcuts,
401
380
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "propro-utils",
3
- "version": "1.6.2",
3
+ "version": "1.6.3",
4
4
  "description": "Auth middleware for propro-auth",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -3,19 +3,19 @@
3
3
  * This module provides functions for setting and clearing authentication cookies.
4
4
  */
5
5
 
6
- const { URL } = require("url");
6
+ const { URL } = require('url');
7
7
 
8
8
  /**
9
9
  * Safely stringify an object, handling circular references
10
10
  * @param {Object} obj - The object to stringify
11
11
  * @return {string} A JSON string representation of the object
12
12
  */
13
- const safeStringify = (obj) => {
13
+ const safeStringify = obj => {
14
14
  const seen = new WeakSet();
15
15
  return JSON.stringify(obj, (key, value) => {
16
- if (typeof value === "object" && value !== null) {
16
+ if (typeof value === 'object' && value !== null) {
17
17
  if (seen.has(value)) {
18
- return "[Circular]";
18
+ return '[Circular]';
19
19
  }
20
20
  seen.add(value);
21
21
  }
@@ -28,7 +28,7 @@ const safeStringify = (obj) => {
28
28
  * @param {Object} user - The user object to sanitize
29
29
  * @return {Object} A sanitized version of the user object
30
30
  */
31
- const sanitizeUser = (user) => {
31
+ const sanitizeUser = user => {
32
32
  const sanitized = { ...user };
33
33
 
34
34
  delete sanitized.password;
@@ -61,10 +61,10 @@ const sanitizeUser = (user) => {
61
61
  * @param {Object} details - Cookie details
62
62
  * @returns {Promise} Promise that resolves when cookie is set
63
63
  */
64
- const setChromeExtensionCookie = (details) => {
64
+ const setChromeExtensionCookie = details => {
65
65
  return new Promise((resolve, reject) => {
66
66
  try {
67
- chrome.cookies.set(details, (cookie) => {
67
+ chrome.cookies.set(details, cookie => {
68
68
  if (chrome.runtime.lastError) {
69
69
  reject(chrome.runtime.lastError);
70
70
  } else {
@@ -83,13 +83,13 @@ const setChromeExtensionCookie = (details) => {
83
83
  */
84
84
  const setAuthCookies = async (res, tokens, account, user, appUrl) => {
85
85
  if (!tokens?.refresh?.token || !tokens?.access?.token) {
86
- throw new Error("Invalid tokens object");
86
+ throw new Error('Invalid tokens object');
87
87
  }
88
88
  if (!account) {
89
- throw new Error("Invalid account object");
89
+ throw new Error('Invalid account object');
90
90
  }
91
91
  if (!user) {
92
- throw new Error("Invalid user object");
92
+ throw new Error('Invalid user object');
93
93
  }
94
94
 
95
95
  const currentDateTime = new Date();
@@ -102,34 +102,34 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
102
102
  let domain;
103
103
  try {
104
104
  domain = appUrl ? new URL(appUrl).hostname : undefined;
105
- if (domain?.includes("mapmap.app")) {
106
- domain = ".mapmap.app";
105
+ if (domain?.includes('mapmap.app')) {
106
+ domain = '.mapmap.app';
107
107
  }
108
- if (domain?.includes("localhost")) {
108
+ if (domain?.includes('localhost')) {
109
109
  domain = undefined;
110
110
  }
111
- if (domain?.includes("propro.so")) {
112
- domain = ".propro.so";
111
+ if (domain?.includes('propro.so')) {
112
+ domain = 'propro.so';
113
113
  }
114
114
  } catch (error) {
115
- console.error("Invalid appUrl:", { error, appUrl });
115
+ console.error('Invalid appUrl:', { error, appUrl });
116
116
  domain = undefined;
117
117
  }
118
118
 
119
119
  const commonAttributes = {
120
120
  secure: true,
121
- sameSite: "None",
121
+ sameSite: 'None',
122
122
  domain,
123
- path: "/",
123
+ path: '/',
124
124
  };
125
125
 
126
126
  const httpOnlyCookies = {
127
- "x-refresh-token": {
127
+ 'x-refresh-token': {
128
128
  value: tokens.refresh.token,
129
129
  maxAge: refreshMaxAge,
130
130
  httpOnly: true,
131
131
  },
132
- "x-access-token": {
132
+ 'x-access-token': {
133
133
  value: tokens.access.token,
134
134
  maxAge: accessMaxAge,
135
135
  httpOnly: true,
@@ -150,7 +150,7 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
150
150
  maxAge: refreshMaxAge,
151
151
  },
152
152
  has_account_token: {
153
- value: JSON.stringify({ value: "true", expires: accessMaxAge }),
153
+ value: JSON.stringify({ value: 'true', expires: accessMaxAge }),
154
154
  maxAge: accessMaxAge,
155
155
  },
156
156
  };
@@ -170,21 +170,21 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
170
170
  ...regularCookies,
171
171
  }).map(([name, config]) => {
172
172
  return setChromeExtensionCookie({
173
- url: `https://${domain || "propro.so"}`,
173
+ url: `https://${domain || 'propro.so'}`,
174
174
  name,
175
175
  value: config.value,
176
176
  secure: true,
177
177
  httpOnly: !!config.httpOnly,
178
- sameSite: "no_restriction",
179
- path: "/",
178
+ sameSite: 'no_restriction',
179
+ path: '/',
180
180
  expirationDate: Math.floor((Date.now() + config.maxAge) / 1000),
181
- domain: domain?.startsWith(".") ? domain : `.${domain || "propro.so"}`,
181
+ domain: domain?.startsWith('.') ? domain : `.${domain || 'propro.so'}`,
182
182
  });
183
183
  });
184
184
 
185
185
  await Promise.allSettled(extensionCookiePromises);
186
186
 
187
- console.log("Auth cookies set successfully", {
187
+ console.log('Auth cookies set successfully', {
188
188
  domain,
189
189
  sameSite: commonAttributes.sameSite,
190
190
  cookieNames: [
@@ -193,11 +193,11 @@ const setAuthCookies = async (res, tokens, account, user, appUrl) => {
193
193
  ],
194
194
  });
195
195
  } catch (error) {
196
- console.error("Error setting cookies:", {
196
+ console.error('Error setting cookies:', {
197
197
  error: error.message,
198
198
  stack: error.stack,
199
199
  });
200
- throw new Error("Failed to set authentication cookies");
200
+ throw new Error('Failed to set authentication cookies');
201
201
  }
202
202
  };
203
203
 
@@ -208,44 +208,44 @@ const clearAuthCookies = async (res, appUrl) => {
208
208
  let domain;
209
209
  try {
210
210
  domain = appUrl ? new URL(appUrl).hostname : undefined;
211
- if (domain?.includes("mapmap.app")) {
212
- domain = ".mapmap.app";
211
+ if (domain?.includes('mapmap.app')) {
212
+ domain = '.mapmap.app';
213
213
  }
214
- if (domain?.includes("localhost")) {
214
+ if (domain?.includes('localhost')) {
215
215
  domain = undefined;
216
216
  }
217
217
  } catch (error) {
218
- console.error("Invalid appUrl:", error);
218
+ console.error('Invalid appUrl:', error);
219
219
  domain = undefined;
220
220
  }
221
221
 
222
222
  const commonAttributes = {
223
223
  secure: true,
224
- sameSite: "None",
224
+ sameSite: 'None',
225
225
  domain,
226
- path: "/",
226
+ path: '/',
227
227
  };
228
228
 
229
229
  const cookieNames = [
230
- "x-refresh-token",
231
- "x-access-token",
232
- "user",
233
- "account",
234
- "has_account_token",
230
+ 'x-refresh-token',
231
+ 'x-access-token',
232
+ 'user',
233
+ 'account',
234
+ 'has_account_token',
235
235
  ];
236
236
 
237
237
  // Clear web cookies
238
- cookieNames.forEach((cookieName) => {
238
+ cookieNames.forEach(cookieName => {
239
239
  res.clearCookie(cookieName, commonAttributes);
240
240
  });
241
241
 
242
242
  try {
243
243
  const extensionClearPromises = cookieNames.map(
244
- (name) =>
245
- new Promise((resolve) => {
244
+ name =>
245
+ new Promise(resolve => {
246
246
  chrome.cookies.remove(
247
247
  {
248
- url: `https://${domain || "mapmap.app"}`,
248
+ url: `https://${domain || 'mapmap.app'}`,
249
249
  name,
250
250
  },
251
251
  resolve
@@ -258,7 +258,7 @@ const clearAuthCookies = async (res, appUrl) => {
258
258
  // Not in extension context, ignore
259
259
  }
260
260
 
261
- console.log("Auth cookies cleared successfully", {
261
+ console.log('Auth cookies cleared successfully', {
262
262
  domain,
263
263
  cookieNames,
264
264
  sameSite: commonAttributes.sameSite,