@blackcode_sa/metaestetics-api 1.14.0 → 1.14.1

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/index.js CHANGED
@@ -11308,6 +11308,9 @@ var PractitionerService = class extends BaseService {
11308
11308
  */
11309
11309
  async processBasicInfo(basicInfo, practitionerId) {
11310
11310
  const processedBasicInfo = { ...basicInfo };
11311
+ if (processedBasicInfo.email) {
11312
+ processedBasicInfo.email = processedBasicInfo.email.toLowerCase().trim();
11313
+ }
11311
11314
  if (basicInfo.profileImageUrl) {
11312
11315
  const uploadedUrl = await this.handleProfilePhotoUpload(
11313
11316
  basicInfo.profileImageUrl,
@@ -11731,7 +11734,8 @@ var PractitionerService = class extends BaseService {
11731
11734
  try {
11732
11735
  const normalizedEmail = email.toLowerCase().trim();
11733
11736
  console.log("[PRACTITIONER] Searching for all draft practitioners by email", {
11734
- email: normalizedEmail
11737
+ email: normalizedEmail,
11738
+ originalEmail: email
11735
11739
  });
11736
11740
  const q = (0, import_firestore32.query)(
11737
11741
  (0, import_firestore32.collection)(this.db, PRACTITIONERS_COLLECTION),
@@ -11742,7 +11746,26 @@ var PractitionerService = class extends BaseService {
11742
11746
  const querySnapshot = await (0, import_firestore32.getDocs)(q);
11743
11747
  if (querySnapshot.empty) {
11744
11748
  console.log("[PRACTITIONER] No draft practitioners found for email", {
11745
- email: normalizedEmail
11749
+ email: normalizedEmail,
11750
+ originalEmail: email
11751
+ });
11752
+ const debugQ = (0, import_firestore32.query)(
11753
+ (0, import_firestore32.collection)(this.db, PRACTITIONERS_COLLECTION),
11754
+ (0, import_firestore32.where)("basicInfo.email", "==", normalizedEmail),
11755
+ (0, import_firestore32.limit)(5)
11756
+ );
11757
+ const debugSnapshot = await (0, import_firestore32.getDocs)(debugQ);
11758
+ console.log("[PRACTITIONER] Debug: Found practitioners with this email (any status):", {
11759
+ count: debugSnapshot.size,
11760
+ practitioners: debugSnapshot.docs.map((doc47) => {
11761
+ var _a;
11762
+ return {
11763
+ id: doc47.id,
11764
+ email: (_a = doc47.data().basicInfo) == null ? void 0 : _a.email,
11765
+ status: doc47.data().status,
11766
+ userRef: doc47.data().userRef
11767
+ };
11768
+ })
11746
11769
  });
11747
11770
  return [];
11748
11771
  }
@@ -16029,6 +16052,7 @@ var AuthService = class extends BaseService {
16029
16052
  * @returns Object containing user, practitioner (if exists), and draft profiles (if any)
16030
16053
  */
16031
16054
  async signUpPractitionerWithGoogle(idToken) {
16055
+ var _a, _b;
16032
16056
  try {
16033
16057
  console.log("[AUTH] Starting practitioner Google Sign-In/Sign-Up");
16034
16058
  let email;
@@ -16062,12 +16086,48 @@ var AuthService = class extends BaseService {
16062
16086
  console.log("[AUTH] User exists with Google provider, signing in");
16063
16087
  const credential2 = import_auth8.GoogleAuthProvider.credential(idToken);
16064
16088
  const { user: firebaseUser2 } = await (0, import_auth8.signInWithCredential)(this.auth, credential2);
16065
- const existingUser2 = await this.userService.getUserById(firebaseUser2.uid);
16089
+ let existingUser2 = null;
16090
+ try {
16091
+ existingUser2 = await this.userService.getUserById(firebaseUser2.uid);
16092
+ console.log("[AUTH] User document found:", existingUser2.uid);
16093
+ } catch (userError) {
16094
+ console.log("[AUTH] User document not found in Firestore, checking for draft profiles", {
16095
+ errorCode: userError == null ? void 0 : userError.code,
16096
+ errorMessage: userError == null ? void 0 : userError.message,
16097
+ errorType: (_a = userError == null ? void 0 : userError.constructor) == null ? void 0 : _a.name,
16098
+ isAuthError: userError instanceof AuthError
16099
+ });
16100
+ const practitionerService2 = new PractitionerService(this.db, this.auth, this.app);
16101
+ const draftProfiles3 = await practitionerService2.getDraftProfilesByEmail(normalizedEmail);
16102
+ console.log("[AUTH] Draft profiles check result:", {
16103
+ email: normalizedEmail,
16104
+ draftProfilesCount: draftProfiles3.length,
16105
+ draftProfileIds: draftProfiles3.map((p) => p.id)
16106
+ });
16107
+ if (draftProfiles3.length === 0) {
16108
+ console.log("[AUTH] No draft profiles found, signing out and throwing error");
16109
+ try {
16110
+ await (0, import_auth8.signOut)(this.auth);
16111
+ } catch (signOutError) {
16112
+ console.warn("[AUTH] Error signing out Firebase user (non-critical):", signOutError);
16113
+ }
16114
+ throw new AuthError(
16115
+ "No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.",
16116
+ "AUTH/NO_DRAFT_PROFILES",
16117
+ 404
16118
+ );
16119
+ }
16120
+ console.log("[AUTH] Draft profiles found, creating user document");
16121
+ existingUser2 = await this.userService.createUser(firebaseUser2, ["practitioner" /* PRACTITIONER */], {
16122
+ skipProfileCreation: true
16123
+ });
16124
+ console.log("[AUTH] Created user document for existing Firebase user with draft profiles:", existingUser2.uid);
16125
+ }
16066
16126
  if (!existingUser2) {
16067
16127
  await (0, import_auth8.signOut)(this.auth);
16068
16128
  throw new AuthError(
16069
- "No account found. Please contact support.",
16070
- "AUTH/USER_NOT_FOUND",
16129
+ "No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.",
16130
+ "AUTH/NO_DRAFT_PROFILES",
16071
16131
  404
16072
16132
  );
16073
16133
  }
@@ -16117,16 +16177,47 @@ var AuthService = class extends BaseService {
16117
16177
  console.error("[AUTH] Error checking for existing user:", error);
16118
16178
  }
16119
16179
  console.log("[AUTH] Checking for draft profiles");
16120
- const draftProfiles = await practitionerService.getDraftProfilesByEmail(normalizedEmail);
16180
+ let draftProfiles = [];
16181
+ try {
16182
+ draftProfiles = await practitionerService.getDraftProfilesByEmail(normalizedEmail);
16183
+ console.log("[AUTH] Draft profiles check complete", { count: draftProfiles.length });
16184
+ } catch (draftCheckError) {
16185
+ console.error("[AUTH] Error checking draft profiles:", draftCheckError);
16186
+ try {
16187
+ await (0, import_auth8.signOut)(this.auth);
16188
+ } catch (signOutError) {
16189
+ console.warn("[AUTH] Error signing out Firebase user (non-critical):", signOutError);
16190
+ }
16191
+ throw new AuthError(
16192
+ "No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.",
16193
+ "AUTH/NO_DRAFT_PROFILES",
16194
+ 404
16195
+ );
16196
+ }
16121
16197
  let user;
16122
16198
  if (existingUser) {
16123
16199
  user = existingUser;
16124
16200
  console.log("[AUTH] Using existing user account");
16125
16201
  } else {
16202
+ if (draftProfiles.length === 0) {
16203
+ console.log("[AUTH] No draft profiles found, signing out and throwing error");
16204
+ try {
16205
+ await (0, import_auth8.signOut)(this.auth);
16206
+ } catch (signOutError) {
16207
+ console.warn("[AUTH] Error signing out Firebase user (non-critical):", signOutError);
16208
+ }
16209
+ const noDraftError = new AuthError(
16210
+ "No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.",
16211
+ "AUTH/NO_DRAFT_PROFILES",
16212
+ 404
16213
+ );
16214
+ console.log("[AUTH] Throwing NO_DRAFT_PROFILES error:", noDraftError.code);
16215
+ throw noDraftError;
16216
+ }
16126
16217
  user = await this.userService.createUser(firebaseUser, ["practitioner" /* PRACTITIONER */], {
16127
16218
  skipProfileCreation: true
16128
16219
  });
16129
- console.log("[AUTH] Created new user account");
16220
+ console.log("[AUTH] Created new user account with draft profiles available");
16130
16221
  }
16131
16222
  let practitioner = null;
16132
16223
  if (user.practitionerProfile) {
@@ -16144,10 +16235,33 @@ var AuthService = class extends BaseService {
16144
16235
  };
16145
16236
  } catch (error) {
16146
16237
  console.error("[AUTH] Error in signUpPractitionerWithGoogle:", error);
16238
+ console.error("[AUTH] Error type:", (_b = error == null ? void 0 : error.constructor) == null ? void 0 : _b.name);
16239
+ console.error("[AUTH] Error instanceof AuthError:", error instanceof AuthError);
16240
+ console.error("[AUTH] Error code:", error == null ? void 0 : error.code);
16241
+ console.error("[AUTH] Error message:", error == null ? void 0 : error.message);
16147
16242
  if (error instanceof AuthError) {
16243
+ console.log("[AUTH] Preserving AuthError:", error.code);
16148
16244
  throw error;
16149
16245
  }
16150
- throw handleFirebaseError(error);
16246
+ const errorMessage = (error == null ? void 0 : error.message) || (error == null ? void 0 : error.toString()) || "";
16247
+ if (errorMessage.includes("NO_DRAFT_PROFILES") || errorMessage.includes("clinic invitation")) {
16248
+ console.log("[AUTH] Detected clinic invitation error in message, converting to AuthError");
16249
+ throw new AuthError(
16250
+ "No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.",
16251
+ "AUTH/NO_DRAFT_PROFILES",
16252
+ 404
16253
+ );
16254
+ }
16255
+ const wrappedError = handleFirebaseError(error);
16256
+ console.log("[AUTH] Wrapped error:", wrappedError.message);
16257
+ if (wrappedError.message.includes("permissions") || wrappedError.message.includes("Account creation failed")) {
16258
+ throw new AuthError(
16259
+ "No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.",
16260
+ "AUTH/NO_DRAFT_PROFILES",
16261
+ 404
16262
+ );
16263
+ }
16264
+ throw wrappedError;
16151
16265
  }
16152
16266
  }
16153
16267
  /**
package/dist/index.mjs CHANGED
@@ -11331,6 +11331,9 @@ var PractitionerService = class extends BaseService {
11331
11331
  */
11332
11332
  async processBasicInfo(basicInfo, practitionerId) {
11333
11333
  const processedBasicInfo = { ...basicInfo };
11334
+ if (processedBasicInfo.email) {
11335
+ processedBasicInfo.email = processedBasicInfo.email.toLowerCase().trim();
11336
+ }
11334
11337
  if (basicInfo.profileImageUrl) {
11335
11338
  const uploadedUrl = await this.handleProfilePhotoUpload(
11336
11339
  basicInfo.profileImageUrl,
@@ -11754,7 +11757,8 @@ var PractitionerService = class extends BaseService {
11754
11757
  try {
11755
11758
  const normalizedEmail = email.toLowerCase().trim();
11756
11759
  console.log("[PRACTITIONER] Searching for all draft practitioners by email", {
11757
- email: normalizedEmail
11760
+ email: normalizedEmail,
11761
+ originalEmail: email
11758
11762
  });
11759
11763
  const q = query13(
11760
11764
  collection13(this.db, PRACTITIONERS_COLLECTION),
@@ -11765,7 +11769,26 @@ var PractitionerService = class extends BaseService {
11765
11769
  const querySnapshot = await getDocs13(q);
11766
11770
  if (querySnapshot.empty) {
11767
11771
  console.log("[PRACTITIONER] No draft practitioners found for email", {
11768
- email: normalizedEmail
11772
+ email: normalizedEmail,
11773
+ originalEmail: email
11774
+ });
11775
+ const debugQ = query13(
11776
+ collection13(this.db, PRACTITIONERS_COLLECTION),
11777
+ where13("basicInfo.email", "==", normalizedEmail),
11778
+ limit7(5)
11779
+ );
11780
+ const debugSnapshot = await getDocs13(debugQ);
11781
+ console.log("[PRACTITIONER] Debug: Found practitioners with this email (any status):", {
11782
+ count: debugSnapshot.size,
11783
+ practitioners: debugSnapshot.docs.map((doc47) => {
11784
+ var _a;
11785
+ return {
11786
+ id: doc47.id,
11787
+ email: (_a = doc47.data().basicInfo) == null ? void 0 : _a.email,
11788
+ status: doc47.data().status,
11789
+ userRef: doc47.data().userRef
11790
+ };
11791
+ })
11769
11792
  });
11770
11793
  return [];
11771
11794
  }
@@ -16116,6 +16139,7 @@ var AuthService = class extends BaseService {
16116
16139
  * @returns Object containing user, practitioner (if exists), and draft profiles (if any)
16117
16140
  */
16118
16141
  async signUpPractitionerWithGoogle(idToken) {
16142
+ var _a, _b;
16119
16143
  try {
16120
16144
  console.log("[AUTH] Starting practitioner Google Sign-In/Sign-Up");
16121
16145
  let email;
@@ -16149,12 +16173,48 @@ var AuthService = class extends BaseService {
16149
16173
  console.log("[AUTH] User exists with Google provider, signing in");
16150
16174
  const credential2 = GoogleAuthProvider.credential(idToken);
16151
16175
  const { user: firebaseUser2 } = await signInWithCredential(this.auth, credential2);
16152
- const existingUser2 = await this.userService.getUserById(firebaseUser2.uid);
16176
+ let existingUser2 = null;
16177
+ try {
16178
+ existingUser2 = await this.userService.getUserById(firebaseUser2.uid);
16179
+ console.log("[AUTH] User document found:", existingUser2.uid);
16180
+ } catch (userError) {
16181
+ console.log("[AUTH] User document not found in Firestore, checking for draft profiles", {
16182
+ errorCode: userError == null ? void 0 : userError.code,
16183
+ errorMessage: userError == null ? void 0 : userError.message,
16184
+ errorType: (_a = userError == null ? void 0 : userError.constructor) == null ? void 0 : _a.name,
16185
+ isAuthError: userError instanceof AuthError
16186
+ });
16187
+ const practitionerService2 = new PractitionerService(this.db, this.auth, this.app);
16188
+ const draftProfiles3 = await practitionerService2.getDraftProfilesByEmail(normalizedEmail);
16189
+ console.log("[AUTH] Draft profiles check result:", {
16190
+ email: normalizedEmail,
16191
+ draftProfilesCount: draftProfiles3.length,
16192
+ draftProfileIds: draftProfiles3.map((p) => p.id)
16193
+ });
16194
+ if (draftProfiles3.length === 0) {
16195
+ console.log("[AUTH] No draft profiles found, signing out and throwing error");
16196
+ try {
16197
+ await firebaseSignOut(this.auth);
16198
+ } catch (signOutError) {
16199
+ console.warn("[AUTH] Error signing out Firebase user (non-critical):", signOutError);
16200
+ }
16201
+ throw new AuthError(
16202
+ "No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.",
16203
+ "AUTH/NO_DRAFT_PROFILES",
16204
+ 404
16205
+ );
16206
+ }
16207
+ console.log("[AUTH] Draft profiles found, creating user document");
16208
+ existingUser2 = await this.userService.createUser(firebaseUser2, ["practitioner" /* PRACTITIONER */], {
16209
+ skipProfileCreation: true
16210
+ });
16211
+ console.log("[AUTH] Created user document for existing Firebase user with draft profiles:", existingUser2.uid);
16212
+ }
16153
16213
  if (!existingUser2) {
16154
16214
  await firebaseSignOut(this.auth);
16155
16215
  throw new AuthError(
16156
- "No account found. Please contact support.",
16157
- "AUTH/USER_NOT_FOUND",
16216
+ "No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.",
16217
+ "AUTH/NO_DRAFT_PROFILES",
16158
16218
  404
16159
16219
  );
16160
16220
  }
@@ -16204,16 +16264,47 @@ var AuthService = class extends BaseService {
16204
16264
  console.error("[AUTH] Error checking for existing user:", error);
16205
16265
  }
16206
16266
  console.log("[AUTH] Checking for draft profiles");
16207
- const draftProfiles = await practitionerService.getDraftProfilesByEmail(normalizedEmail);
16267
+ let draftProfiles = [];
16268
+ try {
16269
+ draftProfiles = await practitionerService.getDraftProfilesByEmail(normalizedEmail);
16270
+ console.log("[AUTH] Draft profiles check complete", { count: draftProfiles.length });
16271
+ } catch (draftCheckError) {
16272
+ console.error("[AUTH] Error checking draft profiles:", draftCheckError);
16273
+ try {
16274
+ await firebaseSignOut(this.auth);
16275
+ } catch (signOutError) {
16276
+ console.warn("[AUTH] Error signing out Firebase user (non-critical):", signOutError);
16277
+ }
16278
+ throw new AuthError(
16279
+ "No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.",
16280
+ "AUTH/NO_DRAFT_PROFILES",
16281
+ 404
16282
+ );
16283
+ }
16208
16284
  let user;
16209
16285
  if (existingUser) {
16210
16286
  user = existingUser;
16211
16287
  console.log("[AUTH] Using existing user account");
16212
16288
  } else {
16289
+ if (draftProfiles.length === 0) {
16290
+ console.log("[AUTH] No draft profiles found, signing out and throwing error");
16291
+ try {
16292
+ await firebaseSignOut(this.auth);
16293
+ } catch (signOutError) {
16294
+ console.warn("[AUTH] Error signing out Firebase user (non-critical):", signOutError);
16295
+ }
16296
+ const noDraftError = new AuthError(
16297
+ "No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.",
16298
+ "AUTH/NO_DRAFT_PROFILES",
16299
+ 404
16300
+ );
16301
+ console.log("[AUTH] Throwing NO_DRAFT_PROFILES error:", noDraftError.code);
16302
+ throw noDraftError;
16303
+ }
16213
16304
  user = await this.userService.createUser(firebaseUser, ["practitioner" /* PRACTITIONER */], {
16214
16305
  skipProfileCreation: true
16215
16306
  });
16216
- console.log("[AUTH] Created new user account");
16307
+ console.log("[AUTH] Created new user account with draft profiles available");
16217
16308
  }
16218
16309
  let practitioner = null;
16219
16310
  if (user.practitionerProfile) {
@@ -16231,10 +16322,33 @@ var AuthService = class extends BaseService {
16231
16322
  };
16232
16323
  } catch (error) {
16233
16324
  console.error("[AUTH] Error in signUpPractitionerWithGoogle:", error);
16325
+ console.error("[AUTH] Error type:", (_b = error == null ? void 0 : error.constructor) == null ? void 0 : _b.name);
16326
+ console.error("[AUTH] Error instanceof AuthError:", error instanceof AuthError);
16327
+ console.error("[AUTH] Error code:", error == null ? void 0 : error.code);
16328
+ console.error("[AUTH] Error message:", error == null ? void 0 : error.message);
16234
16329
  if (error instanceof AuthError) {
16330
+ console.log("[AUTH] Preserving AuthError:", error.code);
16235
16331
  throw error;
16236
16332
  }
16237
- throw handleFirebaseError(error);
16333
+ const errorMessage = (error == null ? void 0 : error.message) || (error == null ? void 0 : error.toString()) || "";
16334
+ if (errorMessage.includes("NO_DRAFT_PROFILES") || errorMessage.includes("clinic invitation")) {
16335
+ console.log("[AUTH] Detected clinic invitation error in message, converting to AuthError");
16336
+ throw new AuthError(
16337
+ "No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.",
16338
+ "AUTH/NO_DRAFT_PROFILES",
16339
+ 404
16340
+ );
16341
+ }
16342
+ const wrappedError = handleFirebaseError(error);
16343
+ console.log("[AUTH] Wrapped error:", wrappedError.message);
16344
+ if (wrappedError.message.includes("permissions") || wrappedError.message.includes("Account creation failed")) {
16345
+ throw new AuthError(
16346
+ "No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.",
16347
+ "AUTH/NO_DRAFT_PROFILES",
16348
+ 404
16349
+ );
16350
+ }
16351
+ throw wrappedError;
16238
16352
  }
16239
16353
  }
16240
16354
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blackcode_sa/metaestetics-api",
3
3
  "private": false,
4
- "version": "1.14.0",
4
+ "version": "1.14.1",
5
5
  "description": "Firebase authentication service with anonymous upgrade support",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
@@ -1061,12 +1061,57 @@ export class AuthService extends BaseService {
1061
1061
  const credential = GoogleAuthProvider.credential(idToken);
1062
1062
  const { user: firebaseUser } = await signInWithCredential(this.auth, credential);
1063
1063
 
1064
- const existingUser = await this.userService.getUserById(firebaseUser.uid);
1064
+ let existingUser: User | null = null;
1065
+ try {
1066
+ existingUser = await this.userService.getUserById(firebaseUser.uid);
1067
+ console.log('[AUTH] User document found:', existingUser.uid);
1068
+ } catch (userError: any) {
1069
+ // User document doesn't exist in Firestore
1070
+ console.log('[AUTH] User document not found in Firestore, checking for draft profiles', {
1071
+ errorCode: userError?.code,
1072
+ errorMessage: userError?.message,
1073
+ errorType: userError?.constructor?.name,
1074
+ isAuthError: userError instanceof AuthError,
1075
+ });
1076
+
1077
+ // Check for draft profiles before signing out
1078
+ const practitionerService = new PractitionerService(this.db, this.auth, this.app);
1079
+ const draftProfiles = await practitionerService.getDraftProfilesByEmail(normalizedEmail);
1080
+
1081
+ console.log('[AUTH] Draft profiles check result:', {
1082
+ email: normalizedEmail,
1083
+ draftProfilesCount: draftProfiles.length,
1084
+ draftProfileIds: draftProfiles.map(p => p.id),
1085
+ });
1086
+
1087
+ if (draftProfiles.length === 0) {
1088
+ // No draft profiles - sign out and throw error
1089
+ console.log('[AUTH] No draft profiles found, signing out and throwing error');
1090
+ try {
1091
+ await firebaseSignOut(this.auth);
1092
+ } catch (signOutError) {
1093
+ console.warn('[AUTH] Error signing out Firebase user (non-critical):', signOutError);
1094
+ }
1095
+ throw new AuthError(
1096
+ 'No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.',
1097
+ 'AUTH/NO_DRAFT_PROFILES',
1098
+ 404,
1099
+ );
1100
+ }
1101
+
1102
+ // Draft profiles exist - create user document and continue
1103
+ console.log('[AUTH] Draft profiles found, creating user document');
1104
+ existingUser = await this.userService.createUser(firebaseUser, [UserRole.PRACTITIONER], {
1105
+ skipProfileCreation: true,
1106
+ });
1107
+ console.log('[AUTH] Created user document for existing Firebase user with draft profiles:', existingUser.uid);
1108
+ }
1109
+
1065
1110
  if (!existingUser) {
1066
1111
  await firebaseSignOut(this.auth);
1067
1112
  throw new AuthError(
1068
- 'No account found. Please contact support.',
1069
- 'AUTH/USER_NOT_FOUND',
1113
+ 'No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.',
1114
+ 'AUTH/NO_DRAFT_PROFILES',
1070
1115
  404,
1071
1116
  );
1072
1117
  }
@@ -1134,7 +1179,24 @@ export class AuthService extends BaseService {
1134
1179
 
1135
1180
  // Check for draft profiles
1136
1181
  console.log('[AUTH] Checking for draft profiles');
1137
- const draftProfiles = await practitionerService.getDraftProfilesByEmail(normalizedEmail);
1182
+ let draftProfiles: Practitioner[] = [];
1183
+ try {
1184
+ draftProfiles = await practitionerService.getDraftProfilesByEmail(normalizedEmail);
1185
+ console.log('[AUTH] Draft profiles check complete', { count: draftProfiles.length });
1186
+ } catch (draftCheckError: any) {
1187
+ console.error('[AUTH] Error checking draft profiles:', draftCheckError);
1188
+ // If checking draft profiles fails, sign out and throw appropriate error
1189
+ try {
1190
+ await firebaseSignOut(this.auth);
1191
+ } catch (signOutError) {
1192
+ console.warn('[AUTH] Error signing out Firebase user (non-critical):', signOutError);
1193
+ }
1194
+ throw new AuthError(
1195
+ 'No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.',
1196
+ 'AUTH/NO_DRAFT_PROFILES',
1197
+ 404,
1198
+ );
1199
+ }
1138
1200
 
1139
1201
  let user: User;
1140
1202
  if (existingUser) {
@@ -1142,11 +1204,32 @@ export class AuthService extends BaseService {
1142
1204
  user = existingUser;
1143
1205
  console.log('[AUTH] Using existing user account');
1144
1206
  } else {
1145
- // Create new user document
1207
+ // For new users: Only create account if there are draft profiles OR if user already has a practitioner profile
1208
+ // Since doctors can only join via clinic invitation, we should not create accounts without invitations
1209
+ if (draftProfiles.length === 0) {
1210
+ console.log('[AUTH] No draft profiles found, signing out and throwing error');
1211
+ // Sign out the Firebase user since we're not creating an account
1212
+ // Wrap in try-catch to handle any sign-out errors gracefully
1213
+ try {
1214
+ await firebaseSignOut(this.auth);
1215
+ } catch (signOutError) {
1216
+ console.warn('[AUTH] Error signing out Firebase user (non-critical):', signOutError);
1217
+ // Continue anyway - the important part is we're not creating the account
1218
+ }
1219
+ const noDraftError = new AuthError(
1220
+ 'No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.',
1221
+ 'AUTH/NO_DRAFT_PROFILES',
1222
+ 404,
1223
+ );
1224
+ console.log('[AUTH] Throwing NO_DRAFT_PROFILES error:', noDraftError.code);
1225
+ throw noDraftError;
1226
+ }
1227
+
1228
+ // Create new user document only if draft profiles exist
1146
1229
  user = await this.userService.createUser(firebaseUser, [UserRole.PRACTITIONER], {
1147
1230
  skipProfileCreation: true,
1148
1231
  });
1149
- console.log('[AUTH] Created new user account');
1232
+ console.log('[AUTH] Created new user account with draft profiles available');
1150
1233
  }
1151
1234
 
1152
1235
  // Check if user already has practitioner profile
@@ -1166,12 +1249,46 @@ export class AuthService extends BaseService {
1166
1249
  practitioner,
1167
1250
  draftProfiles,
1168
1251
  };
1169
- } catch (error) {
1252
+ } catch (error: any) {
1170
1253
  console.error('[AUTH] Error in signUpPractitionerWithGoogle:', error);
1254
+ console.error('[AUTH] Error type:', error?.constructor?.name);
1255
+ console.error('[AUTH] Error instanceof AuthError:', error instanceof AuthError);
1256
+ console.error('[AUTH] Error code:', error?.code);
1257
+ console.error('[AUTH] Error message:', error?.message);
1258
+
1259
+ // Preserve AuthError instances (like NO_DRAFT_PROFILES) without wrapping
1171
1260
  if (error instanceof AuthError) {
1261
+ console.log('[AUTH] Preserving AuthError:', error.code);
1172
1262
  throw error;
1173
1263
  }
1174
- throw handleFirebaseError(error);
1264
+
1265
+ // Check if error message contains NO_DRAFT_PROFILES before wrapping
1266
+ const errorMessage = error?.message || error?.toString() || '';
1267
+ if (errorMessage.includes('NO_DRAFT_PROFILES') || errorMessage.includes('clinic invitation')) {
1268
+ console.log('[AUTH] Detected clinic invitation error in message, converting to AuthError');
1269
+ throw new AuthError(
1270
+ 'No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.',
1271
+ 'AUTH/NO_DRAFT_PROFILES',
1272
+ 404,
1273
+ );
1274
+ }
1275
+
1276
+ // For other errors, wrap them but preserve the original message if it's helpful
1277
+ const wrappedError = handleFirebaseError(error);
1278
+ console.log('[AUTH] Wrapped error:', wrappedError.message);
1279
+
1280
+ // If the wrapped error message is generic, try to preserve more context
1281
+ if (wrappedError.message.includes('permissions') || wrappedError.message.includes('Account creation failed')) {
1282
+ // This might be a permissions error during sign-out or user creation
1283
+ // If we got here and there were no draft profiles, it's likely the same issue
1284
+ throw new AuthError(
1285
+ 'No clinic invitation found for this email. Please contact your clinic administrator to receive an invitation, or use the token provided by your clinic.',
1286
+ 'AUTH/NO_DRAFT_PROFILES',
1287
+ 404,
1288
+ );
1289
+ }
1290
+
1291
+ throw wrappedError;
1175
1292
  }
1176
1293
  }
1177
1294
 
@@ -158,6 +158,11 @@ export class PractitionerService extends BaseService {
158
158
  ): Promise<PractitionerBasicInfo> {
159
159
  const processedBasicInfo = { ...basicInfo };
160
160
 
161
+ // Normalize email to lowercase to ensure consistent matching
162
+ if (processedBasicInfo.email) {
163
+ processedBasicInfo.email = processedBasicInfo.email.toLowerCase().trim();
164
+ }
165
+
161
166
  // Handle profile photo upload if needed
162
167
  if (basicInfo.profileImageUrl) {
163
168
  const uploadedUrl = await this.handleProfilePhotoUpload(
@@ -734,6 +739,7 @@ export class PractitionerService extends BaseService {
734
739
 
735
740
  console.log("[PRACTITIONER] Searching for all draft practitioners by email", {
736
741
  email: normalizedEmail,
742
+ originalEmail: email,
737
743
  });
738
744
 
739
745
  const q = query(
@@ -748,7 +754,26 @@ export class PractitionerService extends BaseService {
748
754
  if (querySnapshot.empty) {
749
755
  console.log("[PRACTITIONER] No draft practitioners found for email", {
750
756
  email: normalizedEmail,
757
+ originalEmail: email,
751
758
  });
759
+
760
+ // Debug: Try to find ANY practitioners with this email (regardless of status)
761
+ const debugQ = query(
762
+ collection(this.db, PRACTITIONERS_COLLECTION),
763
+ where("basicInfo.email", "==", normalizedEmail),
764
+ limit(5)
765
+ );
766
+ const debugSnapshot = await getDocs(debugQ);
767
+ console.log("[PRACTITIONER] Debug: Found practitioners with this email (any status):", {
768
+ count: debugSnapshot.size,
769
+ practitioners: debugSnapshot.docs.map(doc => ({
770
+ id: doc.id,
771
+ email: doc.data().basicInfo?.email,
772
+ status: doc.data().status,
773
+ userRef: doc.data().userRef,
774
+ })),
775
+ });
776
+
752
777
  return [];
753
778
  }
754
779