@blackcode_sa/metaestetics-api 1.14.15 → 1.14.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 +12 -5
- package/dist/index.d.ts +12 -5
- package/dist/index.js +87 -30
- package/dist/index.mjs +87 -30
- package/package.json +1 -1
- package/src/services/auth/auth.service.ts +113 -32
package/dist/index.d.mts
CHANGED
|
@@ -8323,14 +8323,21 @@ declare class AuthService extends BaseService {
|
|
|
8323
8323
|
constructor(db: Firestore, auth: Auth, app: FirebaseApp, userService: UserService);
|
|
8324
8324
|
/**
|
|
8325
8325
|
* Waits for Firebase Auth state to settle after sign-in.
|
|
8326
|
-
*
|
|
8327
|
-
*
|
|
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.
|
|
8328
8335
|
*
|
|
8329
8336
|
* @param expectedUid - The UID we expect to see in auth.currentUser
|
|
8330
|
-
* @param timeoutMs - Maximum time to wait (default
|
|
8331
|
-
* @returns Promise that resolves when auth state is ready
|
|
8337
|
+
* @param timeoutMs - Maximum time to wait (default 5 seconds)
|
|
8338
|
+
* @returns Promise that resolves when auth state is ready and stable
|
|
8332
8339
|
*/
|
|
8333
|
-
private
|
|
8340
|
+
private waitForAuthStateToSettle;
|
|
8334
8341
|
/**
|
|
8335
8342
|
* Registruje novog korisnika sa email-om i lozinkom
|
|
8336
8343
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -8323,14 +8323,21 @@ declare class AuthService extends BaseService {
|
|
|
8323
8323
|
constructor(db: Firestore, auth: Auth, app: FirebaseApp, userService: UserService);
|
|
8324
8324
|
/**
|
|
8325
8325
|
* Waits for Firebase Auth state to settle after sign-in.
|
|
8326
|
-
*
|
|
8327
|
-
*
|
|
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.
|
|
8328
8335
|
*
|
|
8329
8336
|
* @param expectedUid - The UID we expect to see in auth.currentUser
|
|
8330
|
-
* @param timeoutMs - Maximum time to wait (default
|
|
8331
|
-
* @returns Promise that resolves when auth state is ready
|
|
8337
|
+
* @param timeoutMs - Maximum time to wait (default 5 seconds)
|
|
8338
|
+
* @returns Promise that resolves when auth state is ready and stable
|
|
8332
8339
|
*/
|
|
8333
|
-
private
|
|
8340
|
+
private waitForAuthStateToSettle;
|
|
8334
8341
|
/**
|
|
8335
8342
|
* Registruje novog korisnika sa email-om i lozinkom
|
|
8336
8343
|
*/
|
package/dist/index.js
CHANGED
|
@@ -15388,44 +15388,85 @@ var AuthService = class extends BaseService {
|
|
|
15388
15388
|
super(db, auth, app);
|
|
15389
15389
|
this.googleProvider = new import_auth8.GoogleAuthProvider();
|
|
15390
15390
|
this.userService = userService || new UserService(db, auth, app);
|
|
15391
|
-
|
|
15392
|
-
|
|
15393
|
-
|
|
15394
|
-
|
|
15395
|
-
|
|
15391
|
+
(0, import_auth8.onAuthStateChanged)(this.auth, (user) => {
|
|
15392
|
+
var _a2, _b;
|
|
15393
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
15394
|
+
const stackTrace = ((_a2 = new Error().stack) == null ? void 0 : _a2.split("\n").slice(2, 5).join("\n")) || "N/A";
|
|
15395
|
+
console.log(`[AUTH STATE CHANGE] ${timestamp}`);
|
|
15396
|
+
console.log(`[AUTH STATE CHANGE] User: ${(user == null ? void 0 : user.uid) || "NULL"} (email: ${(user == null ? void 0 : user.email) || "N/A"})`);
|
|
15397
|
+
console.log(`[AUTH STATE CHANGE] auth.currentUser: ${((_b = this.auth.currentUser) == null ? void 0 : _b.uid) || "NULL"}`);
|
|
15398
|
+
console.log(`[AUTH STATE CHANGE] Stack trace (first 3 frames):
|
|
15399
|
+
${stackTrace}`);
|
|
15400
|
+
console.log("[AUTH STATE CHANGE] ---");
|
|
15401
|
+
});
|
|
15402
|
+
console.log("[AUTH] AuthService initialized");
|
|
15403
|
+
console.log("[AUTH] Initial auth.currentUser:", ((_a = this.auth.currentUser) == null ? void 0 : _a.uid) || "NULL");
|
|
15396
15404
|
}
|
|
15397
15405
|
/**
|
|
15398
15406
|
* Waits for Firebase Auth state to settle after sign-in.
|
|
15399
|
-
*
|
|
15400
|
-
*
|
|
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.
|
|
15401
15416
|
*
|
|
15402
15417
|
* @param expectedUid - The UID we expect to see in auth.currentUser
|
|
15403
|
-
* @param timeoutMs - Maximum time to wait (default
|
|
15404
|
-
* @returns Promise that resolves when auth state is ready
|
|
15418
|
+
* @param timeoutMs - Maximum time to wait (default 5 seconds)
|
|
15419
|
+
* @returns Promise that resolves when auth state is ready and stable
|
|
15405
15420
|
*/
|
|
15406
|
-
|
|
15407
|
-
|
|
15408
|
-
|
|
15409
|
-
|
|
15410
|
-
|
|
15411
|
-
|
|
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);
|
|
15412
15428
|
return;
|
|
15413
15429
|
}
|
|
15414
|
-
|
|
15415
|
-
|
|
15416
|
-
|
|
15417
|
-
|
|
15418
|
-
|
|
15419
|
-
|
|
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;
|
|
15420
15436
|
const unsubscribe = (0, import_auth8.onAuthStateChanged)(this.auth, (user) => {
|
|
15421
|
-
|
|
15422
|
-
|
|
15423
|
-
|
|
15424
|
-
|
|
15425
|
-
|
|
15426
|
-
|
|
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");
|
|
15427
15458
|
}
|
|
15428
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);
|
|
15429
15470
|
});
|
|
15430
15471
|
}
|
|
15431
15472
|
/**
|
|
@@ -16180,6 +16221,9 @@ var AuthService = class extends BaseService {
|
|
|
16180
16221
|
const credential = import_auth8.GoogleAuthProvider.credential(idToken);
|
|
16181
16222
|
const { user: firebaseUser } = await (0, import_auth8.signInWithCredential)(this.auth, credential);
|
|
16182
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");
|
|
16183
16227
|
const existingUser = await this.userService.getUserById(firebaseUser.uid);
|
|
16184
16228
|
if (existingUser) {
|
|
16185
16229
|
console.log("[AUTH] Existing user found, returning profile:", existingUser.uid);
|
|
@@ -16205,7 +16249,7 @@ var AuthService = class extends BaseService {
|
|
|
16205
16249
|
* @returns Object containing user, practitioner (if exists), and draft profiles (if any)
|
|
16206
16250
|
*/
|
|
16207
16251
|
async signUpPractitionerWithGoogle(idToken) {
|
|
16208
|
-
var _a, _b, _c;
|
|
16252
|
+
var _a, _b, _c, _d;
|
|
16209
16253
|
try {
|
|
16210
16254
|
console.log("[AUTH] Starting practitioner Google Sign-In/Sign-Up");
|
|
16211
16255
|
let email;
|
|
@@ -16239,6 +16283,9 @@ var AuthService = class extends BaseService {
|
|
|
16239
16283
|
console.log("[AUTH] User exists with Google provider, signing in");
|
|
16240
16284
|
const credential2 = import_auth8.GoogleAuthProvider.credential(idToken);
|
|
16241
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");
|
|
16242
16289
|
let existingUser2 = null;
|
|
16243
16290
|
try {
|
|
16244
16291
|
existingUser2 = await this.userService.getUserById(firebaseUser2.uid);
|
|
@@ -16250,6 +16297,13 @@ var AuthService = class extends BaseService {
|
|
|
16250
16297
|
errorType: (_a = userError == null ? void 0 : userError.constructor) == null ? void 0 : _a.name,
|
|
16251
16298
|
isAuthError: userError instanceof AuthError
|
|
16252
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] Waiting for auth state to recover...");
|
|
16305
|
+
await this.waitForAuthStateToSettle(firebaseUser2.uid, 2e3);
|
|
16306
|
+
}
|
|
16253
16307
|
const practitionerService2 = new PractitionerService(this.db, this.auth, this.app);
|
|
16254
16308
|
const draftProfiles3 = await practitionerService2.getDraftProfilesByEmail(normalizedEmail);
|
|
16255
16309
|
console.log("[AUTH] Draft profiles check result:", {
|
|
@@ -16271,7 +16325,7 @@ var AuthService = class extends BaseService {
|
|
|
16271
16325
|
);
|
|
16272
16326
|
}
|
|
16273
16327
|
console.log("[AUTH] Draft profiles found, creating User document IMMEDIATELY after sign-in");
|
|
16274
|
-
console.log("[AUTH] auth.currentUser at User creation time:", ((
|
|
16328
|
+
console.log("[AUTH] auth.currentUser at User creation time:", ((_c = this.auth.currentUser) == null ? void 0 : _c.uid) || "NULL");
|
|
16275
16329
|
try {
|
|
16276
16330
|
const newUser = await this.userService.createUser(firebaseUser2, ["practitioner" /* PRACTITIONER */], {
|
|
16277
16331
|
skipProfileCreation: true
|
|
@@ -16339,6 +16393,9 @@ var AuthService = class extends BaseService {
|
|
|
16339
16393
|
}
|
|
16340
16394
|
throw error;
|
|
16341
16395
|
}
|
|
16396
|
+
console.log("[AUTH] Waiting for auth state to settle after sign-in...");
|
|
16397
|
+
await this.waitForAuthStateToSettle(firebaseUser.uid);
|
|
16398
|
+
console.log("[AUTH] \u2705 Auth state settled, proceeding with Firestore queries");
|
|
16342
16399
|
let existingUser = null;
|
|
16343
16400
|
try {
|
|
16344
16401
|
const existingUserDoc = await this.userService.getUserById(firebaseUser.uid);
|
|
@@ -16408,7 +16465,7 @@ var AuthService = class extends BaseService {
|
|
|
16408
16465
|
};
|
|
16409
16466
|
} catch (error) {
|
|
16410
16467
|
console.error("[AUTH] Error in signUpPractitionerWithGoogle:", error);
|
|
16411
|
-
console.error("[AUTH] Error type:", (
|
|
16468
|
+
console.error("[AUTH] Error type:", (_d = error == null ? void 0 : error.constructor) == null ? void 0 : _d.name);
|
|
16412
16469
|
console.error("[AUTH] Error instanceof AuthError:", error instanceof AuthError);
|
|
16413
16470
|
console.error("[AUTH] Error code:", error == null ? void 0 : error.code);
|
|
16414
16471
|
console.error("[AUTH] Error message:", error == null ? void 0 : error.message);
|
package/dist/index.mjs
CHANGED
|
@@ -15475,44 +15475,85 @@ var AuthService = class extends BaseService {
|
|
|
15475
15475
|
super(db, auth, app);
|
|
15476
15476
|
this.googleProvider = new GoogleAuthProvider();
|
|
15477
15477
|
this.userService = userService || new UserService(db, auth, app);
|
|
15478
|
-
|
|
15479
|
-
|
|
15480
|
-
|
|
15481
|
-
|
|
15482
|
-
|
|
15478
|
+
onAuthStateChanged(this.auth, (user) => {
|
|
15479
|
+
var _a2, _b;
|
|
15480
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
15481
|
+
const stackTrace = ((_a2 = new Error().stack) == null ? void 0 : _a2.split("\n").slice(2, 5).join("\n")) || "N/A";
|
|
15482
|
+
console.log(`[AUTH STATE CHANGE] ${timestamp}`);
|
|
15483
|
+
console.log(`[AUTH STATE CHANGE] User: ${(user == null ? void 0 : user.uid) || "NULL"} (email: ${(user == null ? void 0 : user.email) || "N/A"})`);
|
|
15484
|
+
console.log(`[AUTH STATE CHANGE] auth.currentUser: ${((_b = this.auth.currentUser) == null ? void 0 : _b.uid) || "NULL"}`);
|
|
15485
|
+
console.log(`[AUTH STATE CHANGE] Stack trace (first 3 frames):
|
|
15486
|
+
${stackTrace}`);
|
|
15487
|
+
console.log("[AUTH STATE CHANGE] ---");
|
|
15488
|
+
});
|
|
15489
|
+
console.log("[AUTH] AuthService initialized");
|
|
15490
|
+
console.log("[AUTH] Initial auth.currentUser:", ((_a = this.auth.currentUser) == null ? void 0 : _a.uid) || "NULL");
|
|
15483
15491
|
}
|
|
15484
15492
|
/**
|
|
15485
15493
|
* Waits for Firebase Auth state to settle after sign-in.
|
|
15486
|
-
*
|
|
15487
|
-
*
|
|
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.
|
|
15488
15503
|
*
|
|
15489
15504
|
* @param expectedUid - The UID we expect to see in auth.currentUser
|
|
15490
|
-
* @param timeoutMs - Maximum time to wait (default
|
|
15491
|
-
* @returns Promise that resolves when auth state is ready
|
|
15505
|
+
* @param timeoutMs - Maximum time to wait (default 5 seconds)
|
|
15506
|
+
* @returns Promise that resolves when auth state is ready and stable
|
|
15492
15507
|
*/
|
|
15493
|
-
|
|
15494
|
-
|
|
15495
|
-
|
|
15496
|
-
|
|
15497
|
-
|
|
15498
|
-
|
|
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);
|
|
15499
15515
|
return;
|
|
15500
15516
|
}
|
|
15501
|
-
|
|
15502
|
-
|
|
15503
|
-
|
|
15504
|
-
|
|
15505
|
-
|
|
15506
|
-
|
|
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;
|
|
15507
15523
|
const unsubscribe = onAuthStateChanged(this.auth, (user) => {
|
|
15508
|
-
|
|
15509
|
-
|
|
15510
|
-
|
|
15511
|
-
|
|
15512
|
-
|
|
15513
|
-
|
|
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");
|
|
15514
15545
|
}
|
|
15515
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);
|
|
15516
15557
|
});
|
|
15517
15558
|
}
|
|
15518
15559
|
/**
|
|
@@ -16267,6 +16308,9 @@ var AuthService = class extends BaseService {
|
|
|
16267
16308
|
const credential = GoogleAuthProvider.credential(idToken);
|
|
16268
16309
|
const { user: firebaseUser } = await signInWithCredential(this.auth, credential);
|
|
16269
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");
|
|
16270
16314
|
const existingUser = await this.userService.getUserById(firebaseUser.uid);
|
|
16271
16315
|
if (existingUser) {
|
|
16272
16316
|
console.log("[AUTH] Existing user found, returning profile:", existingUser.uid);
|
|
@@ -16292,7 +16336,7 @@ var AuthService = class extends BaseService {
|
|
|
16292
16336
|
* @returns Object containing user, practitioner (if exists), and draft profiles (if any)
|
|
16293
16337
|
*/
|
|
16294
16338
|
async signUpPractitionerWithGoogle(idToken) {
|
|
16295
|
-
var _a, _b, _c;
|
|
16339
|
+
var _a, _b, _c, _d;
|
|
16296
16340
|
try {
|
|
16297
16341
|
console.log("[AUTH] Starting practitioner Google Sign-In/Sign-Up");
|
|
16298
16342
|
let email;
|
|
@@ -16326,6 +16370,9 @@ var AuthService = class extends BaseService {
|
|
|
16326
16370
|
console.log("[AUTH] User exists with Google provider, signing in");
|
|
16327
16371
|
const credential2 = GoogleAuthProvider.credential(idToken);
|
|
16328
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");
|
|
16329
16376
|
let existingUser2 = null;
|
|
16330
16377
|
try {
|
|
16331
16378
|
existingUser2 = await this.userService.getUserById(firebaseUser2.uid);
|
|
@@ -16337,6 +16384,13 @@ var AuthService = class extends BaseService {
|
|
|
16337
16384
|
errorType: (_a = userError == null ? void 0 : userError.constructor) == null ? void 0 : _a.name,
|
|
16338
16385
|
isAuthError: userError instanceof AuthError
|
|
16339
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] Waiting for auth state to recover...");
|
|
16392
|
+
await this.waitForAuthStateToSettle(firebaseUser2.uid, 2e3);
|
|
16393
|
+
}
|
|
16340
16394
|
const practitionerService2 = new PractitionerService(this.db, this.auth, this.app);
|
|
16341
16395
|
const draftProfiles3 = await practitionerService2.getDraftProfilesByEmail(normalizedEmail);
|
|
16342
16396
|
console.log("[AUTH] Draft profiles check result:", {
|
|
@@ -16358,7 +16412,7 @@ var AuthService = class extends BaseService {
|
|
|
16358
16412
|
);
|
|
16359
16413
|
}
|
|
16360
16414
|
console.log("[AUTH] Draft profiles found, creating User document IMMEDIATELY after sign-in");
|
|
16361
|
-
console.log("[AUTH] auth.currentUser at User creation time:", ((
|
|
16415
|
+
console.log("[AUTH] auth.currentUser at User creation time:", ((_c = this.auth.currentUser) == null ? void 0 : _c.uid) || "NULL");
|
|
16362
16416
|
try {
|
|
16363
16417
|
const newUser = await this.userService.createUser(firebaseUser2, ["practitioner" /* PRACTITIONER */], {
|
|
16364
16418
|
skipProfileCreation: true
|
|
@@ -16426,6 +16480,9 @@ var AuthService = class extends BaseService {
|
|
|
16426
16480
|
}
|
|
16427
16481
|
throw error;
|
|
16428
16482
|
}
|
|
16483
|
+
console.log("[AUTH] Waiting for auth state to settle after sign-in...");
|
|
16484
|
+
await this.waitForAuthStateToSettle(firebaseUser.uid);
|
|
16485
|
+
console.log("[AUTH] \u2705 Auth state settled, proceeding with Firestore queries");
|
|
16429
16486
|
let existingUser = null;
|
|
16430
16487
|
try {
|
|
16431
16488
|
const existingUserDoc = await this.userService.getUserById(firebaseUser.uid);
|
|
@@ -16495,7 +16552,7 @@ var AuthService = class extends BaseService {
|
|
|
16495
16552
|
};
|
|
16496
16553
|
} catch (error) {
|
|
16497
16554
|
console.error("[AUTH] Error in signUpPractitionerWithGoogle:", error);
|
|
16498
|
-
console.error("[AUTH] Error type:", (
|
|
16555
|
+
console.error("[AUTH] Error type:", (_d = error == null ? void 0 : error.constructor) == null ? void 0 : _d.name);
|
|
16499
16556
|
console.error("[AUTH] Error instanceof AuthError:", error instanceof AuthError);
|
|
16500
16557
|
console.error("[AUTH] Error code:", error == null ? void 0 : error.code);
|
|
16501
16558
|
console.error("[AUTH] Error message:", error == null ? void 0 : error.message);
|
package/package.json
CHANGED
|
@@ -92,53 +92,102 @@ export class AuthService extends BaseService {
|
|
|
92
92
|
super(db, auth, app);
|
|
93
93
|
this.userService = userService || new UserService(db, auth, app);
|
|
94
94
|
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
95
|
+
// Initialize auth state change listener for debugging
|
|
96
|
+
// This helps track when auth.currentUser changes, which is critical for debugging
|
|
97
|
+
// the permission-denied issue during user document creation
|
|
98
|
+
onAuthStateChanged(this.auth, (user) => {
|
|
99
|
+
const timestamp = new Date().toISOString();
|
|
100
|
+
const stackTrace = new Error().stack?.split('\n').slice(2, 5).join('\n') || 'N/A';
|
|
101
|
+
console.log(`[AUTH STATE CHANGE] ${timestamp}`);
|
|
102
|
+
console.log(`[AUTH STATE CHANGE] User: ${user?.uid || 'NULL'} (email: ${user?.email || 'N/A'})`);
|
|
103
|
+
console.log(`[AUTH STATE CHANGE] auth.currentUser: ${this.auth.currentUser?.uid || 'NULL'}`);
|
|
104
|
+
console.log(`[AUTH STATE CHANGE] Stack trace (first 3 frames):\n${stackTrace}`);
|
|
105
|
+
console.log('[AUTH STATE CHANGE] ---');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Log initial auth state
|
|
109
|
+
console.log('[AUTH] AuthService initialized');
|
|
110
|
+
console.log('[AUTH] Initial auth.currentUser:', this.auth.currentUser?.uid || 'NULL');
|
|
105
111
|
}
|
|
106
112
|
|
|
107
113
|
/**
|
|
108
114
|
* Waits for Firebase Auth state to settle after sign-in.
|
|
109
|
-
*
|
|
110
|
-
*
|
|
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.
|
|
111
124
|
*
|
|
112
125
|
* @param expectedUid - The UID we expect to see in auth.currentUser
|
|
113
|
-
* @param timeoutMs - Maximum time to wait (default
|
|
114
|
-
* @returns Promise that resolves when auth state is ready
|
|
126
|
+
* @param timeoutMs - Maximum time to wait (default 5 seconds)
|
|
127
|
+
* @returns Promise that resolves when auth state is ready and stable
|
|
115
128
|
*/
|
|
116
|
-
private
|
|
117
|
-
|
|
118
|
-
|
|
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
|
|
119
136
|
if (this.auth.currentUser?.uid === expectedUid) {
|
|
120
|
-
console.log('[AUTH] Auth state
|
|
121
|
-
resolve();
|
|
137
|
+
console.log('[AUTH] ✅ Auth state stable for:', expectedUid);
|
|
122
138
|
return;
|
|
123
139
|
}
|
|
140
|
+
}
|
|
124
141
|
|
|
125
|
-
|
|
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;
|
|
126
148
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
console.error('[AUTH] Timeout waiting for auth state');
|
|
130
|
-
reject(new Error('Timeout waiting for auth state to settle'));
|
|
131
|
-
}, timeoutMs);
|
|
132
|
-
|
|
149
|
+
// Use onAuthStateChanged to wait for auth state to be SET
|
|
150
|
+
// This is more reliable than polling auth.currentUser
|
|
133
151
|
const unsubscribe = onAuthStateChanged(this.auth, (user) => {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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');
|
|
140
179
|
}
|
|
141
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);
|
|
142
191
|
});
|
|
143
192
|
}
|
|
144
193
|
|
|
@@ -1131,6 +1180,13 @@ export class AuthService extends BaseService {
|
|
|
1131
1180
|
const { user: firebaseUser } = await signInWithCredential(this.auth, credential);
|
|
1132
1181
|
console.log('[AUTH] Firebase user signed in:', firebaseUser.uid);
|
|
1133
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
|
+
|
|
1134
1190
|
// 4) Load our domain user document.
|
|
1135
1191
|
const existingUser = await this.userService.getUserById(firebaseUser.uid);
|
|
1136
1192
|
if (existingUser) {
|
|
@@ -1211,6 +1267,13 @@ export class AuthService extends BaseService {
|
|
|
1211
1267
|
const credential = GoogleAuthProvider.credential(idToken);
|
|
1212
1268
|
const { user: firebaseUser } = await signInWithCredential(this.auth, credential);
|
|
1213
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
|
+
|
|
1214
1277
|
let existingUser: User | null = null;
|
|
1215
1278
|
try {
|
|
1216
1279
|
existingUser = await this.userService.getUserById(firebaseUser.uid);
|
|
@@ -1225,6 +1288,17 @@ export class AuthService extends BaseService {
|
|
|
1225
1288
|
});
|
|
1226
1289
|
|
|
1227
1290
|
// Check for draft profiles before signing out
|
|
1291
|
+
// CRITICAL: Verify auth.currentUser is still set before Firestore query
|
|
1292
|
+
// AsyncStorage persistence can cause it to become NULL even after being set
|
|
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] Waiting for auth state to recover...');
|
|
1298
|
+
// Try to wait for it to come back
|
|
1299
|
+
await this.waitForAuthStateToSettle(firebaseUser.uid, 2000);
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1228
1302
|
const practitionerService = new PractitionerService(this.db, this.auth, this.app);
|
|
1229
1303
|
const draftProfiles = await practitionerService.getDraftProfilesByEmail(normalizedEmail);
|
|
1230
1304
|
|
|
@@ -1341,6 +1415,13 @@ export class AuthService extends BaseService {
|
|
|
1341
1415
|
throw error;
|
|
1342
1416
|
}
|
|
1343
1417
|
|
|
1418
|
+
// CRITICAL: Wait for auth state to settle before making Firestore queries
|
|
1419
|
+
// In React Native with AsyncStorage persistence, auth.currentUser can be NULL
|
|
1420
|
+
// immediately after signInWithCredential due to async persistence race condition
|
|
1421
|
+
console.log('[AUTH] Waiting for auth state to settle after sign-in...');
|
|
1422
|
+
await this.waitForAuthStateToSettle(firebaseUser.uid);
|
|
1423
|
+
console.log('[AUTH] ✅ Auth state settled, proceeding with Firestore queries');
|
|
1424
|
+
|
|
1344
1425
|
// Check for existing User document (in case user had email/password account that was just linked)
|
|
1345
1426
|
let existingUser: User | null = null;
|
|
1346
1427
|
try {
|