@blackcode_sa/metaestetics-api 1.12.15 → 1.12.17

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.d.mts CHANGED
@@ -6185,11 +6185,10 @@ declare class AuthService extends BaseService {
6185
6185
  }>;
6186
6186
  /**
6187
6187
  * Signs in a user with a Google ID token from a mobile client.
6188
- * If the user does not exist in our database, the login is rejected.
6188
+ * If the user does not exist, a new user is created.
6189
6189
  * @param idToken - The Google ID token obtained from the mobile app.
6190
- * @param initialRole - The role to assign to the user (currently unused).
6191
- * @returns The signed-in user if they exist in our database.
6192
- * @throws AuthError if no user profile is found.
6190
+ * @param initialRole - The role to assign to the user if they are being created.
6191
+ * @returns The signed-in or newly created user.
6193
6192
  */
6194
6193
  signInWithGoogleIdToken(idToken: string, initialRole?: UserRole): Promise<User>;
6195
6194
  /**
package/dist/index.d.ts CHANGED
@@ -6185,11 +6185,10 @@ declare class AuthService extends BaseService {
6185
6185
  }>;
6186
6186
  /**
6187
6187
  * Signs in a user with a Google ID token from a mobile client.
6188
- * If the user does not exist in our database, the login is rejected.
6188
+ * If the user does not exist, a new user is created.
6189
6189
  * @param idToken - The Google ID token obtained from the mobile app.
6190
- * @param initialRole - The role to assign to the user (currently unused).
6191
- * @returns The signed-in user if they exist in our database.
6192
- * @throws AuthError if no user profile is found.
6190
+ * @param initialRole - The role to assign to the user if they are being created.
6191
+ * @returns The signed-in or newly created user.
6193
6192
  */
6194
6193
  signInWithGoogleIdToken(idToken: string, initialRole?: UserRole): Promise<User>;
6195
6194
  /**
package/dist/index.js CHANGED
@@ -10344,37 +10344,43 @@ var AuthService = class extends BaseService {
10344
10344
  }
10345
10345
  /**
10346
10346
  * Signs in a user with a Google ID token from a mobile client.
10347
- * If the user does not exist in our database, the login is rejected.
10347
+ * If the user does not exist, a new user is created.
10348
10348
  * @param idToken - The Google ID token obtained from the mobile app.
10349
- * @param initialRole - The role to assign to the user (currently unused).
10350
- * @returns The signed-in user if they exist in our database.
10351
- * @throws AuthError if no user profile is found.
10349
+ * @param initialRole - The role to assign to the user if they are being created.
10350
+ * @returns The signed-in or newly created user.
10352
10351
  */
10353
10352
  async signInWithGoogleIdToken(idToken, initialRole = "patient" /* PATIENT */) {
10354
10353
  try {
10355
10354
  console.log("[AUTH] Signing in with Google ID Token");
10356
- const credential = import_auth7.GoogleAuthProvider.credential(idToken);
10357
- const decodedToken = JSON.parse(atob(idToken.split(".")[1]));
10358
- const userEmail = decodedToken.email;
10359
- const userUid = decodedToken.sub;
10360
- console.log("[AUTH] Checking if Firebase Auth user exists with email:", userEmail);
10361
- let existingAuthUser;
10355
+ let email;
10362
10356
  try {
10363
- const admin = await import("firebase-admin");
10364
- existingAuthUser = await admin.auth().getUserByEmail(userEmail);
10365
- console.log("[AUTH] Firebase Auth user found:", existingAuthUser.uid);
10366
- } catch (authError) {
10367
- if (authError.code === "auth/user-not-found") {
10368
- console.log("[AUTH] No Firebase Auth user found for email:", userEmail);
10369
- throw new AuthError(
10370
- 'No account found. Please complete registration by starting with "Get Started".',
10371
- "AUTH/USER_NOT_FOUND",
10372
- 404
10373
- );
10374
- }
10375
- throw authError;
10357
+ const payloadBase64 = idToken.split(".")[1];
10358
+ const payloadJson = globalThis.atob ? globalThis.atob(payloadBase64) : Buffer.from(payloadBase64, "base64").toString("utf8");
10359
+ const payload = JSON.parse(payloadJson);
10360
+ email = payload.email;
10361
+ } catch (decodeError) {
10362
+ console.warn("[AUTH] Failed to decode email from Google ID token:", decodeError);
10363
+ }
10364
+ if (!email) {
10365
+ throw new AuthError(
10366
+ "Unable to read email from Google token. Please try again or use another sign-in method.",
10367
+ "AUTH/INVALID_GOOGLE_TOKEN",
10368
+ 400
10369
+ );
10370
+ }
10371
+ const methods = await (0, import_auth7.fetchSignInMethodsForEmail)(this.auth, email);
10372
+ console.log("[AUTH] Fetch sign in methods for email:", email, methods);
10373
+ const hasGoogleMethod = methods.includes(import_auth7.GoogleAuthProvider.GOOGLE_SIGN_IN_METHOD);
10374
+ console.log("[AUTH] Has Google method:", hasGoogleMethod);
10375
+ if (!hasGoogleMethod) {
10376
+ console.log("[AUTH] No existing Google credential for email, aborting login:", email);
10377
+ throw new AuthError(
10378
+ "No account found for this Google user. Please complete registration first.",
10379
+ "AUTH/USER_NOT_FOUND",
10380
+ 404
10381
+ );
10376
10382
  }
10377
- console.log("[AUTH] Firebase Auth user exists, proceeding with sign-in");
10383
+ const credential = import_auth7.GoogleAuthProvider.credential(idToken);
10378
10384
  const { user: firebaseUser } = await (0, import_auth7.signInWithCredential)(this.auth, credential);
10379
10385
  console.log("[AUTH] Firebase user signed in:", firebaseUser.uid);
10380
10386
  const existingUser = await this.userService.getUserById(firebaseUser.uid);
@@ -10382,11 +10388,12 @@ var AuthService = class extends BaseService {
10382
10388
  console.log("[AUTH] Existing user found, returning profile:", existingUser.uid);
10383
10389
  return existingUser;
10384
10390
  }
10391
+ console.log("[AUTH] No existing MetaEstetics user for Google account \u2013 signing out.");
10385
10392
  await (0, import_auth7.signOut)(this.auth);
10386
10393
  throw new AuthError(
10387
- "Account found but registration incomplete. Please complete registration.",
10388
- "AUTH/INCOMPLETE_REGISTRATION",
10389
- 400
10394
+ 'No account found. Please complete registration by starting with "Get Started".',
10395
+ "AUTH/USER_NOT_FOUND",
10396
+ 404
10390
10397
  );
10391
10398
  } catch (error) {
10392
10399
  console.error("[AUTH] Error in signInWithGoogleIdToken:", error);
package/dist/index.mjs CHANGED
@@ -1798,6 +1798,7 @@ import {
1798
1798
  sendPasswordResetEmail,
1799
1799
  verifyPasswordResetCode,
1800
1800
  confirmPasswordReset,
1801
+ fetchSignInMethodsForEmail as fetchSignInMethodsForEmail2,
1801
1802
  signInWithCredential
1802
1803
  } from "firebase/auth";
1803
1804
  import {
@@ -10448,37 +10449,43 @@ var AuthService = class extends BaseService {
10448
10449
  }
10449
10450
  /**
10450
10451
  * Signs in a user with a Google ID token from a mobile client.
10451
- * If the user does not exist in our database, the login is rejected.
10452
+ * If the user does not exist, a new user is created.
10452
10453
  * @param idToken - The Google ID token obtained from the mobile app.
10453
- * @param initialRole - The role to assign to the user (currently unused).
10454
- * @returns The signed-in user if they exist in our database.
10455
- * @throws AuthError if no user profile is found.
10454
+ * @param initialRole - The role to assign to the user if they are being created.
10455
+ * @returns The signed-in or newly created user.
10456
10456
  */
10457
10457
  async signInWithGoogleIdToken(idToken, initialRole = "patient" /* PATIENT */) {
10458
10458
  try {
10459
10459
  console.log("[AUTH] Signing in with Google ID Token");
10460
- const credential = GoogleAuthProvider.credential(idToken);
10461
- const decodedToken = JSON.parse(atob(idToken.split(".")[1]));
10462
- const userEmail = decodedToken.email;
10463
- const userUid = decodedToken.sub;
10464
- console.log("[AUTH] Checking if Firebase Auth user exists with email:", userEmail);
10465
- let existingAuthUser;
10460
+ let email;
10466
10461
  try {
10467
- const admin = await import("firebase-admin");
10468
- existingAuthUser = await admin.auth().getUserByEmail(userEmail);
10469
- console.log("[AUTH] Firebase Auth user found:", existingAuthUser.uid);
10470
- } catch (authError) {
10471
- if (authError.code === "auth/user-not-found") {
10472
- console.log("[AUTH] No Firebase Auth user found for email:", userEmail);
10473
- throw new AuthError(
10474
- 'No account found. Please complete registration by starting with "Get Started".',
10475
- "AUTH/USER_NOT_FOUND",
10476
- 404
10477
- );
10478
- }
10479
- throw authError;
10462
+ const payloadBase64 = idToken.split(".")[1];
10463
+ const payloadJson = globalThis.atob ? globalThis.atob(payloadBase64) : Buffer.from(payloadBase64, "base64").toString("utf8");
10464
+ const payload = JSON.parse(payloadJson);
10465
+ email = payload.email;
10466
+ } catch (decodeError) {
10467
+ console.warn("[AUTH] Failed to decode email from Google ID token:", decodeError);
10468
+ }
10469
+ if (!email) {
10470
+ throw new AuthError(
10471
+ "Unable to read email from Google token. Please try again or use another sign-in method.",
10472
+ "AUTH/INVALID_GOOGLE_TOKEN",
10473
+ 400
10474
+ );
10475
+ }
10476
+ const methods = await fetchSignInMethodsForEmail2(this.auth, email);
10477
+ console.log("[AUTH] Fetch sign in methods for email:", email, methods);
10478
+ const hasGoogleMethod = methods.includes(GoogleAuthProvider.GOOGLE_SIGN_IN_METHOD);
10479
+ console.log("[AUTH] Has Google method:", hasGoogleMethod);
10480
+ if (!hasGoogleMethod) {
10481
+ console.log("[AUTH] No existing Google credential for email, aborting login:", email);
10482
+ throw new AuthError(
10483
+ "No account found for this Google user. Please complete registration first.",
10484
+ "AUTH/USER_NOT_FOUND",
10485
+ 404
10486
+ );
10480
10487
  }
10481
- console.log("[AUTH] Firebase Auth user exists, proceeding with sign-in");
10488
+ const credential = GoogleAuthProvider.credential(idToken);
10482
10489
  const { user: firebaseUser } = await signInWithCredential(this.auth, credential);
10483
10490
  console.log("[AUTH] Firebase user signed in:", firebaseUser.uid);
10484
10491
  const existingUser = await this.userService.getUserById(firebaseUser.uid);
@@ -10486,11 +10493,12 @@ var AuthService = class extends BaseService {
10486
10493
  console.log("[AUTH] Existing user found, returning profile:", existingUser.uid);
10487
10494
  return existingUser;
10488
10495
  }
10496
+ console.log("[AUTH] No existing MetaEstetics user for Google account \u2013 signing out.");
10489
10497
  await firebaseSignOut(this.auth);
10490
10498
  throw new AuthError(
10491
- "Account found but registration incomplete. Please complete registration.",
10492
- "AUTH/INCOMPLETE_REGISTRATION",
10493
- 400
10499
+ 'No account found. Please complete registration by starting with "Get Started".',
10500
+ "AUTH/USER_NOT_FOUND",
10501
+ 404
10494
10502
  );
10495
10503
  } catch (error) {
10496
10504
  console.error("[AUTH] Error in signInWithGoogleIdToken:", error);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blackcode_sa/metaestetics-api",
3
3
  "private": false,
4
- "version": "1.12.15",
4
+ "version": "1.12.17",
5
5
  "description": "Firebase authentication service with anonymous upgrade support",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
@@ -872,11 +872,10 @@ export class AuthService extends BaseService {
872
872
 
873
873
  /**
874
874
  * Signs in a user with a Google ID token from a mobile client.
875
- * If the user does not exist in our database, the login is rejected.
875
+ * If the user does not exist, a new user is created.
876
876
  * @param idToken - The Google ID token obtained from the mobile app.
877
- * @param initialRole - The role to assign to the user (currently unused).
878
- * @returns The signed-in user if they exist in our database.
879
- * @throws AuthError if no user profile is found.
877
+ * @param initialRole - The role to assign to the user if they are being created.
878
+ * @returns The signed-in or newly created user.
880
879
  */
881
880
  async signInWithGoogleIdToken(
882
881
  idToken: string,
@@ -885,55 +884,61 @@ export class AuthService extends BaseService {
885
884
  try {
886
885
  console.log('[AUTH] Signing in with Google ID Token');
887
886
 
888
- // First, decode the ID token to get the user's email without signing them in
889
- const credential = GoogleAuthProvider.credential(idToken);
890
-
891
- // Parse the ID token to get user info without creating a Firebase Auth session
892
- const decodedToken = JSON.parse(atob(idToken.split('.')[1]));
893
- const userEmail = decodedToken.email;
894
- const userUid = decodedToken.sub; // This will be the Firebase UID
895
-
896
- console.log('[AUTH] Checking if Firebase Auth user exists with email:', userEmail);
897
-
898
- // Check if a Firebase Auth user with this email already exists
899
- let existingAuthUser;
887
+ // 1) Extract the email claim from the raw JWT so we can check Auth records *before* sign-in
888
+ let email: string | undefined;
900
889
  try {
901
- const admin = await import('firebase-admin');
902
- existingAuthUser = await admin.auth().getUserByEmail(userEmail);
903
- console.log('[AUTH] Firebase Auth user found:', existingAuthUser.uid);
904
- } catch (authError: any) {
905
- if (authError.code === 'auth/user-not-found') {
906
- // No Firebase Auth user exists - reject the login
907
- console.log('[AUTH] No Firebase Auth user found for email:', userEmail);
908
- throw new AuthError(
909
- 'No account found. Please complete registration by starting with "Get Started".',
910
- 'AUTH/USER_NOT_FOUND',
911
- 404,
912
- );
913
- }
914
- // Re-throw other auth errors
915
- throw authError;
890
+ const payloadBase64 = idToken.split('.')[1];
891
+ const payloadJson = globalThis.atob
892
+ ? globalThis.atob(payloadBase64)
893
+ : Buffer.from(payloadBase64, 'base64').toString('utf8');
894
+ const payload = JSON.parse(payloadJson);
895
+ email = payload.email as string | undefined;
896
+ } catch (decodeError) {
897
+ console.warn('[AUTH] Failed to decode email from Google ID token:', decodeError);
898
+ }
899
+
900
+ if (!email) {
901
+ throw new AuthError(
902
+ 'Unable to read email from Google token. Please try again or use another sign-in method.',
903
+ 'AUTH/INVALID_GOOGLE_TOKEN',
904
+ 400,
905
+ );
916
906
  }
917
907
 
918
- console.log('[AUTH] Firebase Auth user exists, proceeding with sign-in');
908
+ // 2) Check if this email already has a Google credential in Firebase Auth.
909
+ // If not, abort early so we *never* create an unwanted Auth user.
910
+ const methods = await fetchSignInMethodsForEmail(this.auth, email);
911
+ console.log('[AUTH] Fetch sign in methods for email:', email, methods);
912
+ const hasGoogleMethod = methods.includes(GoogleAuthProvider.GOOGLE_SIGN_IN_METHOD);
913
+ console.log('[AUTH] Has Google method:', hasGoogleMethod);
914
+ if (!hasGoogleMethod) {
915
+ console.log('[AUTH] No existing Google credential for email, aborting login:', email);
916
+ throw new AuthError(
917
+ 'No account found for this Google user. Please complete registration first.',
918
+ 'AUTH/USER_NOT_FOUND',
919
+ 404,
920
+ );
921
+ }
919
922
 
920
- // Now proceed with the actual Firebase sign-in since we know the auth user exists
923
+ // 3) Safe to sign-in we know the credential belongs to an existing Auth account.
924
+ const credential = GoogleAuthProvider.credential(idToken);
921
925
  const { user: firebaseUser } = await signInWithCredential(this.auth, credential);
922
926
  console.log('[AUTH] Firebase user signed in:', firebaseUser.uid);
923
927
 
924
- // Get the user profile from our database
928
+ // 4) Load our domain user document.
925
929
  const existingUser = await this.userService.getUserById(firebaseUser.uid);
926
930
  if (existingUser) {
927
931
  console.log('[AUTH] Existing user found, returning profile:', existingUser.uid);
928
932
  return existingUser;
929
933
  }
930
934
 
931
- // Auth user exists but no profile - this means incomplete registration
935
+ // 5) If no profile exists we sign out immediately and error – but crucially no phantom user was created.
936
+ console.log('[AUTH] No existing MetaEstetics user for Google account – signing out.');
932
937
  await firebaseSignOut(this.auth);
933
938
  throw new AuthError(
934
- 'Account found but registration incomplete. Please complete registration.',
935
- 'AUTH/INCOMPLETE_REGISTRATION',
936
- 400,
939
+ 'No account found. Please complete registration by starting with "Get Started".',
940
+ 'AUTH/USER_NOT_FOUND',
941
+ 404,
937
942
  );
938
943
  } catch (error) {
939
944
  console.error('[AUTH] Error in signInWithGoogleIdToken:', error);