propro-utils 1.6.1 → 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,54 +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 with allowDiskUse option
73
- const allStyles = await userStyleSchema
74
- .find({ accountId })
75
- // .sort({ createdAt: 1 })
76
- .option({ 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
64
  /**
113
65
  * Creates a new user global styles document with default style shortcuts.
114
66
  *
@@ -117,13 +69,6 @@ async function consolidateGlobalStyles(accountId) {
117
69
  * @returns {Promise<Object>} A promise that resolves to the created user global styles object.
118
70
  */
119
71
  async function createUserGlobalStyles(userStyleSchema, accountId) {
120
- // First check if any existing styles need to be consolidated
121
- const existingStyles = await userStyleSchema.find({ accountId });
122
-
123
- if (existingStyles.length > 0) {
124
- return await consolidateGlobalStyles(accountId);
125
- }
126
-
127
72
  return await userStyleSchema.create({
128
73
  id: uuidv4(),
129
74
  styleShortcuts: defaultUserGlobalStyleShortcuts,
@@ -155,7 +100,7 @@ async function createDefaultFolders(folderSchema, accountId) {
155
100
  }
156
101
 
157
102
  const DEFAULT_THEME = {
158
- canvasBackground: "#1E1D1D",
103
+ canvasBackground: "#000000",
159
104
  defaultItemWidth: 200,
160
105
  defaultColor: "#ffffff",
161
106
  fontSize: "16px",
@@ -172,6 +117,8 @@ const DEFAULT_THEME = {
172
117
  * @throws {Error} If there's an issue with database operations or invalid input
173
118
  */
174
119
  const checkIfUserExists = async (accountId) => {
120
+ console.log("Starting checkIfUserExists for accountId:", accountId);
121
+
175
122
  // Input validation
176
123
  if (!accountId || typeof accountId !== "string") {
177
124
  console.warn("Invalid accountId provided:", accountId);
@@ -179,6 +126,8 @@ const checkIfUserExists = async (accountId) => {
179
126
  }
180
127
 
181
128
  try {
129
+ console.log("Loading schemas...");
130
+ // Load all required schemas in parallel
182
131
  const schemaResults = await Promise.all([
183
132
  ServiceManager.getService("UserSchema"),
184
133
  ServiceManager.getService("UserStyleSchema"),
@@ -189,6 +138,14 @@ const checkIfUserExists = async (accountId) => {
189
138
  const [userSchema, userStyleSchema, folderSchema, themeSchema] =
190
139
  schemaResults;
191
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
+
192
149
  if (!userSchema) {
193
150
  throw new Error("UserSchema service not available");
194
151
  }
@@ -210,23 +167,83 @@ const checkIfUserExists = async (accountId) => {
210
167
  );
211
168
  }
212
169
 
213
- // Find existing user with populated fields
214
- const user = await userSchema
215
- .findOne({ accountId })
216
- .select("-theme -folderList -userGlobalStyles -mapList")
217
- .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");
218
176
 
219
177
  if (user) {
178
+ console.log("Updating existing user data...");
220
179
  const updates = [];
221
180
 
222
- // Handle userGlobalStyles
181
+ // Handle userGlobalStyles - check properly if styles exist in the database
223
182
  if (userStyleSchema) {
224
- // Consolidate any duplicate global styles
225
- 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
+ }
226
242
  }
227
243
 
228
244
  // Handle folders
229
245
  if (folderSchema) {
246
+ console.log("Checking folders...");
230
247
  updates.push(
231
248
  (async () => {
232
249
  const existingFolders = await folderSchema
@@ -234,6 +251,7 @@ const checkIfUserExists = async (accountId) => {
234
251
  .select("name")
235
252
  .lean();
236
253
 
254
+ console.log("Existing folders count:", existingFolders.length);
237
255
  const existingFolderNames = new Set(
238
256
  existingFolders.map((f) => f.name)
239
257
  );
@@ -255,6 +273,7 @@ const checkIfUserExists = async (accountId) => {
255
273
 
256
274
  // Handle themes
257
275
  if (themeSchema) {
276
+ console.log("Checking themes...");
258
277
  updates.push(
259
278
  (async () => {
260
279
  const defaultThemeExists = await themeSchema.exists({
@@ -262,6 +281,7 @@ const checkIfUserExists = async (accountId) => {
262
281
  accountId,
263
282
  });
264
283
 
284
+ console.log("Default theme exists:", defaultThemeExists);
265
285
  if (!defaultThemeExists) {
266
286
  const defaultTheme = await themeSchema.create({
267
287
  ...DEFAULT_THEME,
@@ -281,13 +301,12 @@ const checkIfUserExists = async (accountId) => {
281
301
  }
282
302
 
283
303
  // Wait for all updates to complete
304
+ console.log("Waiting for all updates to complete...");
284
305
  await Promise.all(updates);
306
+ console.log("All updates completed successfully");
285
307
 
286
- // Return fresh user data after updates, excluding specified fields
287
- return userSchema
288
- .findOne({ accountId })
289
- .select("-theme -folderList -userGlobalStyles -mapList")
290
- .lean();
308
+ // Return fresh user data after updates
309
+ return userSchema.findOne({ accountId }).lean();
291
310
  }
292
311
 
293
312
  // Create new user with all associated data
@@ -341,10 +360,8 @@ const checkIfUserExists = async (accountId) => {
341
360
  await createDefaultFolders(folderSchema, newUser.id);
342
361
  }
343
362
 
344
- return userSchema
345
- .findById(newUser._id)
346
- .select("-theme -folderList -userGlobalStyles -mapList")
347
- .lean();
363
+ console.log("Operation completed successfully");
364
+ return userSchema.findById(newUser._id).lean();
348
365
  } catch (error) {
349
366
  console.error("Detailed error in checkIfUserExists:", {
350
367
  accountId,
@@ -357,44 +374,7 @@ const checkIfUserExists = async (accountId) => {
357
374
  }
358
375
  };
359
376
 
360
- const updateUserGlobalStyleShortcuts = async (userId, shortcutId, shortcut) => {
361
- try {
362
- const user = await userSchema
363
- .findOne({ id: userId })
364
- .populate("userGlobalStyles");
365
- if (!user) {
366
- throw new Error("User not found");
367
- }
368
-
369
- // Ensure we have consolidated styles
370
- const consolidatedStyles = await consolidateGlobalStyles(user.accountId);
371
-
372
- // Find the index of the shortcut to update
373
- const shortcutIndex = consolidatedStyles.styleShortcuts.findIndex(
374
- (s) => s.id.toString() === shortcutId
375
- );
376
-
377
- if (shortcutIndex === -1) {
378
- // If the shortcut doesn't exist, add it
379
- consolidatedStyles.styleShortcuts.push(shortcut);
380
- } else {
381
- // If the shortcut exists, update it
382
- consolidatedStyles.styleShortcuts[shortcutIndex] = {
383
- ...consolidatedStyles.styleShortcuts[shortcutIndex],
384
- ...shortcut,
385
- };
386
- }
387
-
388
- await consolidatedStyles.save();
389
- return consolidatedStyles;
390
- } catch (error) {
391
- console.error("Error updating user global style shortcuts:", error);
392
- throw error;
393
- }
394
- };
395
-
396
377
  module.exports = {
397
378
  getAccountProfile,
398
379
  checkIfUserExists,
399
- updateUserGlobalStyleShortcuts,
400
380
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "propro-utils",
3
- "version": "1.6.1",
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,