@blackcode_sa/metaestetics-api 1.14.16 → 1.14.18

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
@@ -8321,6 +8321,23 @@ declare class AuthService extends BaseService {
8321
8321
  private googleProvider;
8322
8322
  private userService;
8323
8323
  constructor(db: Firestore, auth: Auth, app: FirebaseApp, userService: UserService);
8324
+ /**
8325
+ * Waits for Firebase Auth state to settle after sign-in.
8326
+ *
8327
+ * In React Native with AsyncStorage persistence, there's a critical issue:
8328
+ * 1. signInWithCredential() sets auth.currentUser in memory immediately
8329
+ * 2. But AsyncStorage persistence happens asynchronously
8330
+ * 3. If AsyncStorage reads an old NULL value, it can OVERWRITE the current auth state
8331
+ * 4. This causes auth.currentUser to become NULL even after it was set
8332
+ *
8333
+ * This method uses onAuthStateChanged to wait for the auth state to be SET and STABLE.
8334
+ * It ensures the auth state persists through AsyncStorage operations.
8335
+ *
8336
+ * @param expectedUid - The UID we expect to see in auth.currentUser
8337
+ * @param timeoutMs - Maximum time to wait (default 5 seconds)
8338
+ * @returns Promise that resolves when auth state is ready and stable
8339
+ */
8340
+ private waitForAuthStateToSettle;
8324
8341
  /**
8325
8342
  * Registruje novog korisnika sa email-om i lozinkom
8326
8343
  */
package/dist/index.d.ts CHANGED
@@ -8321,6 +8321,23 @@ declare class AuthService extends BaseService {
8321
8321
  private googleProvider;
8322
8322
  private userService;
8323
8323
  constructor(db: Firestore, auth: Auth, app: FirebaseApp, userService: UserService);
8324
+ /**
8325
+ * Waits for Firebase Auth state to settle after sign-in.
8326
+ *
8327
+ * In React Native with AsyncStorage persistence, there's a critical issue:
8328
+ * 1. signInWithCredential() sets auth.currentUser in memory immediately
8329
+ * 2. But AsyncStorage persistence happens asynchronously
8330
+ * 3. If AsyncStorage reads an old NULL value, it can OVERWRITE the current auth state
8331
+ * 4. This causes auth.currentUser to become NULL even after it was set
8332
+ *
8333
+ * This method uses onAuthStateChanged to wait for the auth state to be SET and STABLE.
8334
+ * It ensures the auth state persists through AsyncStorage operations.
8335
+ *
8336
+ * @param expectedUid - The UID we expect to see in auth.currentUser
8337
+ * @param timeoutMs - Maximum time to wait (default 5 seconds)
8338
+ * @returns Promise that resolves when auth state is ready and stable
8339
+ */
8340
+ private waitForAuthStateToSettle;
8324
8341
  /**
8325
8342
  * Registruje novog korisnika sa email-om i lozinkom
8326
8343
  */
package/dist/index.js CHANGED
@@ -15402,6 +15402,73 @@ ${stackTrace}`);
15402
15402
  console.log("[AUTH] AuthService initialized");
15403
15403
  console.log("[AUTH] Initial auth.currentUser:", ((_a = this.auth.currentUser) == null ? void 0 : _a.uid) || "NULL");
15404
15404
  }
15405
+ /**
15406
+ * Waits for Firebase Auth state to settle after sign-in.
15407
+ *
15408
+ * In React Native with AsyncStorage persistence, there's a critical issue:
15409
+ * 1. signInWithCredential() sets auth.currentUser in memory immediately
15410
+ * 2. But AsyncStorage persistence happens asynchronously
15411
+ * 3. If AsyncStorage reads an old NULL value, it can OVERWRITE the current auth state
15412
+ * 4. This causes auth.currentUser to become NULL even after it was set
15413
+ *
15414
+ * This method uses onAuthStateChanged to wait for the auth state to be SET and STABLE.
15415
+ * It ensures the auth state persists through AsyncStorage operations.
15416
+ *
15417
+ * @param expectedUid - The UID we expect to see in auth.currentUser
15418
+ * @param timeoutMs - Maximum time to wait (default 5 seconds)
15419
+ * @returns Promise that resolves when auth state is ready and stable
15420
+ */
15421
+ async waitForAuthStateToSettle(expectedUid, timeoutMs = 5e3) {
15422
+ var _a, _b, _c;
15423
+ if (((_a = this.auth.currentUser) == null ? void 0 : _a.uid) === expectedUid) {
15424
+ console.log("[AUTH] Auth state appears set, waiting for stability...");
15425
+ await new Promise((resolve) => setTimeout(resolve, 200));
15426
+ if (((_b = this.auth.currentUser) == null ? void 0 : _b.uid) === expectedUid) {
15427
+ console.log("[AUTH] \u2705 Auth state stable for:", expectedUid);
15428
+ return;
15429
+ }
15430
+ }
15431
+ console.log("[AUTH] Waiting for auth state to settle for:", expectedUid);
15432
+ console.log("[AUTH] Current auth.currentUser:", ((_c = this.auth.currentUser) == null ? void 0 : _c.uid) || "NULL");
15433
+ return new Promise((resolve, reject) => {
15434
+ const startTime = Date.now();
15435
+ let resolved = false;
15436
+ const unsubscribe = (0, import_auth8.onAuthStateChanged)(this.auth, (user) => {
15437
+ if (resolved) return;
15438
+ const currentUid = (user == null ? void 0 : user.uid) || null;
15439
+ console.log("[AUTH] onAuthStateChanged fired:", currentUid || "NULL");
15440
+ if (currentUid === expectedUid) {
15441
+ setTimeout(() => {
15442
+ var _a2;
15443
+ if (resolved) return;
15444
+ if (((_a2 = this.auth.currentUser) == null ? void 0 : _a2.uid) === expectedUid) {
15445
+ resolved = true;
15446
+ unsubscribe();
15447
+ clearTimeout(timeout);
15448
+ const elapsed = Date.now() - startTime;
15449
+ console.log(`[AUTH] \u2705 Auth state settled and stable after ${elapsed}ms for:`, expectedUid);
15450
+ resolve();
15451
+ } else {
15452
+ console.warn("[AUTH] \u26A0\uFE0F Auth state became NULL after being set, waiting more...");
15453
+ }
15454
+ }, 300);
15455
+ } else if (currentUid === null && Date.now() - startTime > 1e3) {
15456
+ console.error("[AUTH] \u274C Auth state became NULL after being set!");
15457
+ console.error("[AUTH] This indicates AsyncStorage persistence issue");
15458
+ }
15459
+ });
15460
+ const timeout = setTimeout(() => {
15461
+ var _a2, _b2;
15462
+ if (resolved) return;
15463
+ resolved = true;
15464
+ unsubscribe();
15465
+ console.error("[AUTH] \u274C Timeout waiting for auth state to settle");
15466
+ console.error("[AUTH] Expected UID:", expectedUid);
15467
+ console.error("[AUTH] Actual auth.currentUser:", ((_a2 = this.auth.currentUser) == null ? void 0 : _a2.uid) || "NULL");
15468
+ reject(new Error(`Timeout waiting for auth state to settle. Expected: ${expectedUid}, Got: ${((_b2 = this.auth.currentUser) == null ? void 0 : _b2.uid) || "NULL"}`));
15469
+ }, timeoutMs);
15470
+ });
15471
+ }
15405
15472
  /**
15406
15473
  * Registruje novog korisnika sa email-om i lozinkom
15407
15474
  */
@@ -16154,6 +16221,9 @@ ${stackTrace}`);
16154
16221
  const credential = import_auth8.GoogleAuthProvider.credential(idToken);
16155
16222
  const { user: firebaseUser } = await (0, import_auth8.signInWithCredential)(this.auth, credential);
16156
16223
  console.log("[AUTH] Firebase user signed in:", firebaseUser.uid);
16224
+ console.log("[AUTH] Waiting for auth state to settle after sign-in...");
16225
+ await this.waitForAuthStateToSettle(firebaseUser.uid);
16226
+ console.log("[AUTH] \u2705 Auth state settled, proceeding with Firestore queries");
16157
16227
  const existingUser = await this.userService.getUserById(firebaseUser.uid);
16158
16228
  if (existingUser) {
16159
16229
  console.log("[AUTH] Existing user found, returning profile:", existingUser.uid);
@@ -16179,7 +16249,7 @@ ${stackTrace}`);
16179
16249
  * @returns Object containing user, practitioner (if exists), and draft profiles (if any)
16180
16250
  */
16181
16251
  async signUpPractitionerWithGoogle(idToken) {
16182
- var _a, _b, _c;
16252
+ var _a, _b, _c, _d;
16183
16253
  try {
16184
16254
  console.log("[AUTH] Starting practitioner Google Sign-In/Sign-Up");
16185
16255
  let email;
@@ -16213,6 +16283,9 @@ ${stackTrace}`);
16213
16283
  console.log("[AUTH] User exists with Google provider, signing in");
16214
16284
  const credential2 = import_auth8.GoogleAuthProvider.credential(idToken);
16215
16285
  const { user: firebaseUser2 } = await (0, import_auth8.signInWithCredential)(this.auth, credential2);
16286
+ console.log("[AUTH] Waiting for auth state to settle after sign-in...");
16287
+ await this.waitForAuthStateToSettle(firebaseUser2.uid);
16288
+ console.log("[AUTH] \u2705 Auth state settled, proceeding with Firestore queries");
16216
16289
  let existingUser2 = null;
16217
16290
  try {
16218
16291
  existingUser2 = await this.userService.getUserById(firebaseUser2.uid);
@@ -16224,6 +16297,16 @@ ${stackTrace}`);
16224
16297
  errorType: (_a = userError == null ? void 0 : userError.constructor) == null ? void 0 : _a.name,
16225
16298
  isAuthError: userError instanceof AuthError
16226
16299
  });
16300
+ if (!this.auth.currentUser || this.auth.currentUser.uid !== firebaseUser2.uid) {
16301
+ console.error("[AUTH] \u274C auth.currentUser became NULL before draft profile query!");
16302
+ console.error("[AUTH] Expected UID:", firebaseUser2.uid);
16303
+ console.error("[AUTH] Actual auth.currentUser:", ((_b = this.auth.currentUser) == null ? void 0 : _b.uid) || "NULL");
16304
+ console.log("[AUTH] Re-signing in to restore auth state before query...");
16305
+ const credential3 = import_auth8.GoogleAuthProvider.credential(idToken);
16306
+ await (0, import_auth8.signInWithCredential)(this.auth, credential3);
16307
+ await this.waitForAuthStateToSettle(firebaseUser2.uid, 2e3);
16308
+ console.log("[AUTH] \u2705 Auth state restored, proceeding with query");
16309
+ }
16227
16310
  const practitionerService2 = new PractitionerService(this.db, this.auth, this.app);
16228
16311
  const draftProfiles3 = await practitionerService2.getDraftProfilesByEmail(normalizedEmail);
16229
16312
  console.log("[AUTH] Draft profiles check result:", {
@@ -16245,7 +16328,7 @@ ${stackTrace}`);
16245
16328
  );
16246
16329
  }
16247
16330
  console.log("[AUTH] Draft profiles found, creating User document IMMEDIATELY after sign-in");
16248
- console.log("[AUTH] auth.currentUser at User creation time:", ((_b = this.auth.currentUser) == null ? void 0 : _b.uid) || "NULL");
16331
+ console.log("[AUTH] auth.currentUser at User creation time:", ((_c = this.auth.currentUser) == null ? void 0 : _c.uid) || "NULL");
16249
16332
  try {
16250
16333
  const newUser = await this.userService.createUser(firebaseUser2, ["practitioner" /* PRACTITIONER */], {
16251
16334
  skipProfileCreation: true
@@ -16313,6 +16396,9 @@ ${stackTrace}`);
16313
16396
  }
16314
16397
  throw error;
16315
16398
  }
16399
+ console.log("[AUTH] Waiting for auth state to settle after sign-in...");
16400
+ await this.waitForAuthStateToSettle(firebaseUser.uid);
16401
+ console.log("[AUTH] \u2705 Auth state settled, proceeding with Firestore queries");
16316
16402
  let existingUser = null;
16317
16403
  try {
16318
16404
  const existingUserDoc = await this.userService.getUserById(firebaseUser.uid);
@@ -16382,7 +16468,7 @@ ${stackTrace}`);
16382
16468
  };
16383
16469
  } catch (error) {
16384
16470
  console.error("[AUTH] Error in signUpPractitionerWithGoogle:", error);
16385
- console.error("[AUTH] Error type:", (_c = error == null ? void 0 : error.constructor) == null ? void 0 : _c.name);
16471
+ console.error("[AUTH] Error type:", (_d = error == null ? void 0 : error.constructor) == null ? void 0 : _d.name);
16386
16472
  console.error("[AUTH] Error instanceof AuthError:", error instanceof AuthError);
16387
16473
  console.error("[AUTH] Error code:", error == null ? void 0 : error.code);
16388
16474
  console.error("[AUTH] Error message:", error == null ? void 0 : error.message);
package/dist/index.mjs CHANGED
@@ -15489,6 +15489,73 @@ ${stackTrace}`);
15489
15489
  console.log("[AUTH] AuthService initialized");
15490
15490
  console.log("[AUTH] Initial auth.currentUser:", ((_a = this.auth.currentUser) == null ? void 0 : _a.uid) || "NULL");
15491
15491
  }
15492
+ /**
15493
+ * Waits for Firebase Auth state to settle after sign-in.
15494
+ *
15495
+ * In React Native with AsyncStorage persistence, there's a critical issue:
15496
+ * 1. signInWithCredential() sets auth.currentUser in memory immediately
15497
+ * 2. But AsyncStorage persistence happens asynchronously
15498
+ * 3. If AsyncStorage reads an old NULL value, it can OVERWRITE the current auth state
15499
+ * 4. This causes auth.currentUser to become NULL even after it was set
15500
+ *
15501
+ * This method uses onAuthStateChanged to wait for the auth state to be SET and STABLE.
15502
+ * It ensures the auth state persists through AsyncStorage operations.
15503
+ *
15504
+ * @param expectedUid - The UID we expect to see in auth.currentUser
15505
+ * @param timeoutMs - Maximum time to wait (default 5 seconds)
15506
+ * @returns Promise that resolves when auth state is ready and stable
15507
+ */
15508
+ async waitForAuthStateToSettle(expectedUid, timeoutMs = 5e3) {
15509
+ var _a, _b, _c;
15510
+ if (((_a = this.auth.currentUser) == null ? void 0 : _a.uid) === expectedUid) {
15511
+ console.log("[AUTH] Auth state appears set, waiting for stability...");
15512
+ await new Promise((resolve) => setTimeout(resolve, 200));
15513
+ if (((_b = this.auth.currentUser) == null ? void 0 : _b.uid) === expectedUid) {
15514
+ console.log("[AUTH] \u2705 Auth state stable for:", expectedUid);
15515
+ return;
15516
+ }
15517
+ }
15518
+ console.log("[AUTH] Waiting for auth state to settle for:", expectedUid);
15519
+ console.log("[AUTH] Current auth.currentUser:", ((_c = this.auth.currentUser) == null ? void 0 : _c.uid) || "NULL");
15520
+ return new Promise((resolve, reject) => {
15521
+ const startTime = Date.now();
15522
+ let resolved = false;
15523
+ const unsubscribe = onAuthStateChanged(this.auth, (user) => {
15524
+ if (resolved) return;
15525
+ const currentUid = (user == null ? void 0 : user.uid) || null;
15526
+ console.log("[AUTH] onAuthStateChanged fired:", currentUid || "NULL");
15527
+ if (currentUid === expectedUid) {
15528
+ setTimeout(() => {
15529
+ var _a2;
15530
+ if (resolved) return;
15531
+ if (((_a2 = this.auth.currentUser) == null ? void 0 : _a2.uid) === expectedUid) {
15532
+ resolved = true;
15533
+ unsubscribe();
15534
+ clearTimeout(timeout);
15535
+ const elapsed = Date.now() - startTime;
15536
+ console.log(`[AUTH] \u2705 Auth state settled and stable after ${elapsed}ms for:`, expectedUid);
15537
+ resolve();
15538
+ } else {
15539
+ console.warn("[AUTH] \u26A0\uFE0F Auth state became NULL after being set, waiting more...");
15540
+ }
15541
+ }, 300);
15542
+ } else if (currentUid === null && Date.now() - startTime > 1e3) {
15543
+ console.error("[AUTH] \u274C Auth state became NULL after being set!");
15544
+ console.error("[AUTH] This indicates AsyncStorage persistence issue");
15545
+ }
15546
+ });
15547
+ const timeout = setTimeout(() => {
15548
+ var _a2, _b2;
15549
+ if (resolved) return;
15550
+ resolved = true;
15551
+ unsubscribe();
15552
+ console.error("[AUTH] \u274C Timeout waiting for auth state to settle");
15553
+ console.error("[AUTH] Expected UID:", expectedUid);
15554
+ console.error("[AUTH] Actual auth.currentUser:", ((_a2 = this.auth.currentUser) == null ? void 0 : _a2.uid) || "NULL");
15555
+ reject(new Error(`Timeout waiting for auth state to settle. Expected: ${expectedUid}, Got: ${((_b2 = this.auth.currentUser) == null ? void 0 : _b2.uid) || "NULL"}`));
15556
+ }, timeoutMs);
15557
+ });
15558
+ }
15492
15559
  /**
15493
15560
  * Registruje novog korisnika sa email-om i lozinkom
15494
15561
  */
@@ -16241,6 +16308,9 @@ ${stackTrace}`);
16241
16308
  const credential = GoogleAuthProvider.credential(idToken);
16242
16309
  const { user: firebaseUser } = await signInWithCredential(this.auth, credential);
16243
16310
  console.log("[AUTH] Firebase user signed in:", firebaseUser.uid);
16311
+ console.log("[AUTH] Waiting for auth state to settle after sign-in...");
16312
+ await this.waitForAuthStateToSettle(firebaseUser.uid);
16313
+ console.log("[AUTH] \u2705 Auth state settled, proceeding with Firestore queries");
16244
16314
  const existingUser = await this.userService.getUserById(firebaseUser.uid);
16245
16315
  if (existingUser) {
16246
16316
  console.log("[AUTH] Existing user found, returning profile:", existingUser.uid);
@@ -16266,7 +16336,7 @@ ${stackTrace}`);
16266
16336
  * @returns Object containing user, practitioner (if exists), and draft profiles (if any)
16267
16337
  */
16268
16338
  async signUpPractitionerWithGoogle(idToken) {
16269
- var _a, _b, _c;
16339
+ var _a, _b, _c, _d;
16270
16340
  try {
16271
16341
  console.log("[AUTH] Starting practitioner Google Sign-In/Sign-Up");
16272
16342
  let email;
@@ -16300,6 +16370,9 @@ ${stackTrace}`);
16300
16370
  console.log("[AUTH] User exists with Google provider, signing in");
16301
16371
  const credential2 = GoogleAuthProvider.credential(idToken);
16302
16372
  const { user: firebaseUser2 } = await signInWithCredential(this.auth, credential2);
16373
+ console.log("[AUTH] Waiting for auth state to settle after sign-in...");
16374
+ await this.waitForAuthStateToSettle(firebaseUser2.uid);
16375
+ console.log("[AUTH] \u2705 Auth state settled, proceeding with Firestore queries");
16303
16376
  let existingUser2 = null;
16304
16377
  try {
16305
16378
  existingUser2 = await this.userService.getUserById(firebaseUser2.uid);
@@ -16311,6 +16384,16 @@ ${stackTrace}`);
16311
16384
  errorType: (_a = userError == null ? void 0 : userError.constructor) == null ? void 0 : _a.name,
16312
16385
  isAuthError: userError instanceof AuthError
16313
16386
  });
16387
+ if (!this.auth.currentUser || this.auth.currentUser.uid !== firebaseUser2.uid) {
16388
+ console.error("[AUTH] \u274C auth.currentUser became NULL before draft profile query!");
16389
+ console.error("[AUTH] Expected UID:", firebaseUser2.uid);
16390
+ console.error("[AUTH] Actual auth.currentUser:", ((_b = this.auth.currentUser) == null ? void 0 : _b.uid) || "NULL");
16391
+ console.log("[AUTH] Re-signing in to restore auth state before query...");
16392
+ const credential3 = GoogleAuthProvider.credential(idToken);
16393
+ await signInWithCredential(this.auth, credential3);
16394
+ await this.waitForAuthStateToSettle(firebaseUser2.uid, 2e3);
16395
+ console.log("[AUTH] \u2705 Auth state restored, proceeding with query");
16396
+ }
16314
16397
  const practitionerService2 = new PractitionerService(this.db, this.auth, this.app);
16315
16398
  const draftProfiles3 = await practitionerService2.getDraftProfilesByEmail(normalizedEmail);
16316
16399
  console.log("[AUTH] Draft profiles check result:", {
@@ -16332,7 +16415,7 @@ ${stackTrace}`);
16332
16415
  );
16333
16416
  }
16334
16417
  console.log("[AUTH] Draft profiles found, creating User document IMMEDIATELY after sign-in");
16335
- console.log("[AUTH] auth.currentUser at User creation time:", ((_b = this.auth.currentUser) == null ? void 0 : _b.uid) || "NULL");
16418
+ console.log("[AUTH] auth.currentUser at User creation time:", ((_c = this.auth.currentUser) == null ? void 0 : _c.uid) || "NULL");
16336
16419
  try {
16337
16420
  const newUser = await this.userService.createUser(firebaseUser2, ["practitioner" /* PRACTITIONER */], {
16338
16421
  skipProfileCreation: true
@@ -16400,6 +16483,9 @@ ${stackTrace}`);
16400
16483
  }
16401
16484
  throw error;
16402
16485
  }
16486
+ console.log("[AUTH] Waiting for auth state to settle after sign-in...");
16487
+ await this.waitForAuthStateToSettle(firebaseUser.uid);
16488
+ console.log("[AUTH] \u2705 Auth state settled, proceeding with Firestore queries");
16403
16489
  let existingUser = null;
16404
16490
  try {
16405
16491
  const existingUserDoc = await this.userService.getUserById(firebaseUser.uid);
@@ -16469,7 +16555,7 @@ ${stackTrace}`);
16469
16555
  };
16470
16556
  } catch (error) {
16471
16557
  console.error("[AUTH] Error in signUpPractitionerWithGoogle:", error);
16472
- console.error("[AUTH] Error type:", (_c = error == null ? void 0 : error.constructor) == null ? void 0 : _c.name);
16558
+ console.error("[AUTH] Error type:", (_d = error == null ? void 0 : error.constructor) == null ? void 0 : _d.name);
16473
16559
  console.error("[AUTH] Error instanceof AuthError:", error instanceof AuthError);
16474
16560
  console.error("[AUTH] Error code:", error == null ? void 0 : error.code);
16475
16561
  console.error("[AUTH] Error message:", error == null ? void 0 : error.message);
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.16",
4
+ "version": "1.14.18",
5
5
  "description": "Firebase authentication service with anonymous upgrade support",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
@@ -110,6 +110,87 @@ export class AuthService extends BaseService {
110
110
  console.log('[AUTH] Initial auth.currentUser:', this.auth.currentUser?.uid || 'NULL');
111
111
  }
112
112
 
113
+ /**
114
+ * Waits for Firebase Auth state to settle after sign-in.
115
+ *
116
+ * In React Native with AsyncStorage persistence, there's a critical issue:
117
+ * 1. signInWithCredential() sets auth.currentUser in memory immediately
118
+ * 2. But AsyncStorage persistence happens asynchronously
119
+ * 3. If AsyncStorage reads an old NULL value, it can OVERWRITE the current auth state
120
+ * 4. This causes auth.currentUser to become NULL even after it was set
121
+ *
122
+ * This method uses onAuthStateChanged to wait for the auth state to be SET and STABLE.
123
+ * It ensures the auth state persists through AsyncStorage operations.
124
+ *
125
+ * @param expectedUid - The UID we expect to see in auth.currentUser
126
+ * @param timeoutMs - Maximum time to wait (default 5 seconds)
127
+ * @returns Promise that resolves when auth state is ready and stable
128
+ */
129
+ private async waitForAuthStateToSettle(expectedUid: string, timeoutMs: number = 5000): Promise<void> {
130
+ // If already correct, still wait a bit to ensure it's stable (not just set in memory)
131
+ if (this.auth.currentUser?.uid === expectedUid) {
132
+ console.log('[AUTH] Auth state appears set, waiting for stability...');
133
+ // Wait a small amount to ensure AsyncStorage persistence completes
134
+ await new Promise(resolve => setTimeout(resolve, 200));
135
+ // Check again after wait
136
+ if (this.auth.currentUser?.uid === expectedUid) {
137
+ console.log('[AUTH] ✅ Auth state stable for:', expectedUid);
138
+ return;
139
+ }
140
+ }
141
+
142
+ console.log('[AUTH] Waiting for auth state to settle for:', expectedUid);
143
+ console.log('[AUTH] Current auth.currentUser:', this.auth.currentUser?.uid || 'NULL');
144
+
145
+ return new Promise((resolve, reject) => {
146
+ const startTime = Date.now();
147
+ let resolved = false;
148
+
149
+ // Use onAuthStateChanged to wait for auth state to be SET
150
+ // This is more reliable than polling auth.currentUser
151
+ const unsubscribe = onAuthStateChanged(this.auth, (user) => {
152
+ if (resolved) return;
153
+
154
+ const currentUid = user?.uid || null;
155
+ console.log('[AUTH] onAuthStateChanged fired:', currentUid || 'NULL');
156
+
157
+ if (currentUid === expectedUid) {
158
+ // Auth state is set, but wait a bit more to ensure it's stable
159
+ // AsyncStorage might still be writing/reading
160
+ setTimeout(() => {
161
+ if (resolved) return;
162
+
163
+ // Final check - is it still set?
164
+ if (this.auth.currentUser?.uid === expectedUid) {
165
+ resolved = true;
166
+ unsubscribe();
167
+ clearTimeout(timeout);
168
+ const elapsed = Date.now() - startTime;
169
+ console.log(`[AUTH] ✅ Auth state settled and stable after ${elapsed}ms for:`, expectedUid);
170
+ resolve();
171
+ } else {
172
+ console.warn('[AUTH] ⚠️ Auth state became NULL after being set, waiting more...');
173
+ }
174
+ }, 300); // Wait 300ms for AsyncStorage to stabilize
175
+ } else if (currentUid === null && Date.now() - startTime > 1000) {
176
+ // Auth state became NULL after being set - this is the bug we're trying to fix
177
+ console.error('[AUTH] ❌ Auth state became NULL after being set!');
178
+ console.error('[AUTH] This indicates AsyncStorage persistence issue');
179
+ }
180
+ });
181
+
182
+ const timeout = setTimeout(() => {
183
+ if (resolved) return;
184
+ resolved = true;
185
+ unsubscribe();
186
+ console.error('[AUTH] ❌ Timeout waiting for auth state to settle');
187
+ console.error('[AUTH] Expected UID:', expectedUid);
188
+ console.error('[AUTH] Actual auth.currentUser:', this.auth.currentUser?.uid || 'NULL');
189
+ reject(new Error(`Timeout waiting for auth state to settle. Expected: ${expectedUid}, Got: ${this.auth.currentUser?.uid || 'NULL'}`));
190
+ }, timeoutMs);
191
+ });
192
+ }
193
+
113
194
  /**
114
195
  * Registruje novog korisnika sa email-om i lozinkom
115
196
  */
@@ -1099,6 +1180,13 @@ export class AuthService extends BaseService {
1099
1180
  const { user: firebaseUser } = await signInWithCredential(this.auth, credential);
1100
1181
  console.log('[AUTH] Firebase user signed in:', firebaseUser.uid);
1101
1182
 
1183
+ // CRITICAL: Wait for auth state to settle before making Firestore queries
1184
+ // In React Native with AsyncStorage persistence, auth.currentUser can be NULL
1185
+ // immediately after signInWithCredential due to async persistence race condition
1186
+ console.log('[AUTH] Waiting for auth state to settle after sign-in...');
1187
+ await this.waitForAuthStateToSettle(firebaseUser.uid);
1188
+ console.log('[AUTH] ✅ Auth state settled, proceeding with Firestore queries');
1189
+
1102
1190
  // 4) Load our domain user document.
1103
1191
  const existingUser = await this.userService.getUserById(firebaseUser.uid);
1104
1192
  if (existingUser) {
@@ -1179,6 +1267,13 @@ export class AuthService extends BaseService {
1179
1267
  const credential = GoogleAuthProvider.credential(idToken);
1180
1268
  const { user: firebaseUser } = await signInWithCredential(this.auth, credential);
1181
1269
 
1270
+ // CRITICAL: Wait for auth state to settle before making Firestore queries
1271
+ // In React Native with AsyncStorage persistence, auth.currentUser can be NULL
1272
+ // immediately after signInWithCredential due to async persistence race condition
1273
+ console.log('[AUTH] Waiting for auth state to settle after sign-in...');
1274
+ await this.waitForAuthStateToSettle(firebaseUser.uid);
1275
+ console.log('[AUTH] ✅ Auth state settled, proceeding with Firestore queries');
1276
+
1182
1277
  let existingUser: User | null = null;
1183
1278
  try {
1184
1279
  existingUser = await this.userService.getUserById(firebaseUser.uid);
@@ -1193,6 +1288,25 @@ export class AuthService extends BaseService {
1193
1288
  });
1194
1289
 
1195
1290
  // Check for draft profiles before signing out
1291
+ // CRITICAL: Firestore queries can trigger AsyncStorage reads which overwrite auth.currentUser
1292
+ // If auth.currentUser is NULL, re-sign in immediately to restore it before the query
1293
+ if (!this.auth.currentUser || this.auth.currentUser.uid !== firebaseUser.uid) {
1294
+ console.error('[AUTH] ❌ auth.currentUser became NULL before draft profile query!');
1295
+ console.error('[AUTH] Expected UID:', firebaseUser.uid);
1296
+ console.error('[AUTH] Actual auth.currentUser:', this.auth.currentUser?.uid || 'NULL');
1297
+ console.log('[AUTH] Re-signing in to restore auth state before query...');
1298
+
1299
+ // Re-sign in with the credential to restore auth.currentUser
1300
+ // This is the most reliable way to ensure auth state is set before Firestore queries
1301
+ const credential = GoogleAuthProvider.credential(idToken);
1302
+ await signInWithCredential(this.auth, credential);
1303
+
1304
+ // Wait for auth state to settle after re-sign-in
1305
+ await this.waitForAuthStateToSettle(firebaseUser.uid, 2000);
1306
+
1307
+ console.log('[AUTH] ✅ Auth state restored, proceeding with query');
1308
+ }
1309
+
1196
1310
  const practitionerService = new PractitionerService(this.db, this.auth, this.app);
1197
1311
  const draftProfiles = await practitionerService.getDraftProfilesByEmail(normalizedEmail);
1198
1312
 
@@ -1309,6 +1423,13 @@ export class AuthService extends BaseService {
1309
1423
  throw error;
1310
1424
  }
1311
1425
 
1426
+ // CRITICAL: Wait for auth state to settle before making Firestore queries
1427
+ // In React Native with AsyncStorage persistence, auth.currentUser can be NULL
1428
+ // immediately after signInWithCredential due to async persistence race condition
1429
+ console.log('[AUTH] Waiting for auth state to settle after sign-in...');
1430
+ await this.waitForAuthStateToSettle(firebaseUser.uid);
1431
+ console.log('[AUTH] ✅ Auth state settled, proceeding with Firestore queries');
1432
+
1312
1433
  // Check for existing User document (in case user had email/password account that was just linked)
1313
1434
  let existingUser: User | null = null;
1314
1435
  try {