strapi-plugin-firebase-authentication 1.1.0 → 1.1.8

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.
@@ -4,7 +4,7 @@ const jsxRuntime = require("react/jsx-runtime");
4
4
  const React = require("react");
5
5
  const designSystem = require("@strapi/design-system");
6
6
  const admin = require("@strapi/strapi/admin");
7
- const api = require("./api-BSejy8nn.js");
7
+ const api = require("./api-CxfueBVM.js");
8
8
  const reactRouterDom = require("react-router-dom");
9
9
  function SettingsPage() {
10
10
  const { toggleNotification } = admin.useNotification();
@@ -738,7 +738,7 @@ const index = {
738
738
  id: `${PLUGIN_ID}.page.title`,
739
739
  defaultMessage: PLUGIN_ID
740
740
  },
741
- Component: () => import("./App-Bl6D4TFu.mjs").then((mod) => ({
741
+ Component: () => import("./App-Dt8F60Rl.mjs").then((mod) => ({
742
742
  default: mod.App
743
743
  })),
744
744
  permissions: PERMISSIONS["menu-link"]
@@ -760,7 +760,7 @@ const index = {
760
760
  id: "settings",
761
761
  to: `/settings/${PLUGIN_ID}`,
762
762
  async Component() {
763
- const component = await import("./index-BqF9RRVF.mjs");
763
+ const component = await import("./index-BzSU0Li9.mjs");
764
764
  return component.default;
765
765
  },
766
766
  permissions: PERMISSIONS["menu-link"]
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const index = require("../_chunks/index-DgfRCyyQ.js");
2
+ const index = require("../_chunks/index-BIHS9XB4.js");
3
3
  require("react/jsx-runtime");
4
4
  require("@strapi/strapi/admin");
5
5
  require("@strapi/design-system");
@@ -1,4 +1,4 @@
1
- import { p } from "../_chunks/index-4hUrKd7Y.mjs";
1
+ import { p } from "../_chunks/index-Do9Y0scX.mjs";
2
2
  import "react/jsx-runtime";
3
3
  import "@strapi/strapi/admin";
4
4
  import "@strapi/design-system";
@@ -442,7 +442,7 @@ const firebaseController = {
442
442
  const result = await strapi.plugin(pluginName).service("firebaseService").validateFirebaseToken(idToken, profileMetaData, populate2);
443
443
  ctx.body = result;
444
444
  } catch (error2) {
445
- strapi.log.error("validateToken controller error:", error2);
445
+ strapi.log.error("validateToken controller error:", error2.message);
446
446
  if (error2.name === "ValidationError") {
447
447
  return ctx.badRequest(error2.message);
448
448
  }
@@ -532,9 +532,11 @@ const firebaseController = {
532
532
  }
533
533
  },
534
534
  /**
535
- * Reset password - authenticated with 1hr JWT
535
+ * Reset password - authenticated password change
536
536
  * POST /api/firebase-authentication/resetPassword
537
- * Public endpoint - uses JWT from Authorization header
537
+ * Public endpoint - requires valid JWT in Authorization header
538
+ * Used for admin-initiated resets or user self-service password changes
539
+ * NOT used for forgot password email flow (which uses Firebase's hosted UI)
538
540
  */
539
541
  async resetPassword(ctx) {
540
542
  strapi.log.debug("resetPassword endpoint called");
@@ -5218,13 +5220,13 @@ lodash.exports;
5218
5220
  return string2.slice(position, position + target.length) == target;
5219
5221
  }
5220
5222
  function template(string2, options2, guard) {
5221
- var settings2 = lodash2.templateSettings;
5223
+ var settings = lodash2.templateSettings;
5222
5224
  if (guard && isIterateeCall(string2, options2, guard)) {
5223
5225
  options2 = undefined$1;
5224
5226
  }
5225
5227
  string2 = toString4(string2);
5226
- options2 = assignInWith({}, options2, settings2, customDefaultsAssignIn);
5227
- var imports = assignInWith({}, options2.imports, settings2.imports, customDefaultsAssignIn), importsKeys = keys2(imports), importsValues = baseValues(imports, importsKeys);
5228
+ options2 = assignInWith({}, options2, settings, customDefaultsAssignIn);
5229
+ var imports = assignInWith({}, options2.imports, settings.imports, customDefaultsAssignIn), importsKeys = keys2(imports), importsValues = baseValues(imports, importsKeys);
5228
5230
  var isEscaping, isEvaluating, index2 = 0, interpolate = options2.interpolate || reNoMatch, source = "__p += '";
5229
5231
  var reDelimiters = RegExp2(
5230
5232
  (options2.escape || reNoMatch).source + "|" + interpolate.source + "|" + (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + "|" + (options2.evaluate || reNoMatch).source + "|$",
@@ -28934,9 +28936,6 @@ const userController = {
28934
28936
  }
28935
28937
  };
28936
28938
  const settingsController = {
28937
- setToken: async (ctx) => {
28938
- ctx.body = await strapi.plugin("firebase-authentication").service("settingsService").setToken(ctx);
28939
- },
28940
28939
  setFirebaseConfigJson: async (ctx) => {
28941
28940
  ctx.body = await strapi.plugin("firebase-authentication").service("settingsService").setFirebaseConfigJson(ctx);
28942
28941
  },
@@ -29091,13 +29090,7 @@ const controllers = {
29091
29090
  };
29092
29091
  const middlewares = {};
29093
29092
  const policies = {};
29094
- const settings = [
29095
- {
29096
- method: "POST",
29097
- path: "/settings/token",
29098
- handler: "settingsController.setToken",
29099
- config: { policies: ["admin::isAuthenticatedAdmin"] }
29100
- },
29093
+ const settingsRoute = [
29101
29094
  {
29102
29095
  method: "POST",
29103
29096
  path: "/settings/firebase-config",
@@ -29131,75 +29124,9 @@ const settings = [
29131
29124
  ];
29132
29125
  const admin = {
29133
29126
  type: "admin",
29134
- routes: [...settings]
29135
- };
29136
- const contentApi = {
29137
- type: "content-api",
29138
- routes: [
29139
- {
29140
- method: "POST",
29141
- path: "/",
29142
- handler: "firebaseController.validateToken",
29143
- config: {
29144
- auth: false,
29145
- // Public endpoint - this IS the authentication endpoint
29146
- policies: []
29147
- }
29148
- },
29149
- {
29150
- method: "POST",
29151
- path: "/emailLogin",
29152
- handler: "firebaseController.emailLogin",
29153
- config: {
29154
- auth: false,
29155
- // Public endpoint - email/password login
29156
- policies: []
29157
- }
29158
- },
29159
- {
29160
- method: "POST",
29161
- path: "/forgotPassword",
29162
- handler: "firebaseController.forgotPassword",
29163
- config: {
29164
- auth: false,
29165
- // Public endpoint - no authentication required
29166
- policies: []
29167
- }
29168
- },
29169
- {
29170
- method: "POST",
29171
- path: "/resetPassword",
29172
- handler: "firebaseController.resetPassword",
29173
- config: {
29174
- auth: false,
29175
- // Public endpoint - uses JWT from Authorization header
29176
- policies: []
29177
- }
29178
- },
29179
- {
29180
- method: "GET",
29181
- path: "/config",
29182
- handler: "settingsController.getPublicConfig",
29183
- config: {
29184
- auth: false,
29185
- // Public endpoint - frontend needs this for validation
29186
- policies: []
29187
- }
29188
- },
29189
- {
29190
- method: "POST",
29191
- path: "/requestMagicLink",
29192
- handler: "firebaseController.requestMagicLink",
29193
- config: {
29194
- auth: false,
29195
- // Public endpoint - passwordless authentication
29196
- policies: []
29197
- }
29198
- }
29199
- ]
29200
- };
29201
- const contentInternalApi = {
29202
29127
  routes: [
29128
+ ...settingsRoute,
29129
+ // User management routes
29203
29130
  {
29204
29131
  method: "GET",
29205
29132
  path: "/users",
@@ -29263,23 +29190,77 @@ const contentInternalApi = {
29263
29190
  config: {
29264
29191
  policies: ["admin::isAuthenticatedAdmin"]
29265
29192
  }
29193
+ }
29194
+ ]
29195
+ };
29196
+ const contentApi = {
29197
+ type: "content-api",
29198
+ routes: [
29199
+ {
29200
+ method: "POST",
29201
+ path: "/",
29202
+ handler: "firebaseController.validateToken",
29203
+ config: {
29204
+ auth: false,
29205
+ // Public endpoint - this IS the authentication endpoint
29206
+ policies: []
29207
+ }
29208
+ },
29209
+ {
29210
+ method: "POST",
29211
+ path: "/emailLogin",
29212
+ handler: "firebaseController.emailLogin",
29213
+ config: {
29214
+ auth: false,
29215
+ // Public endpoint - email/password login
29216
+ policies: []
29217
+ }
29218
+ },
29219
+ {
29220
+ method: "POST",
29221
+ path: "/forgotPassword",
29222
+ handler: "firebaseController.forgotPassword",
29223
+ config: {
29224
+ auth: false,
29225
+ // Public endpoint - no authentication required
29226
+ policies: []
29227
+ }
29228
+ },
29229
+ {
29230
+ method: "POST",
29231
+ path: "/resetPassword",
29232
+ handler: "firebaseController.resetPassword",
29233
+ config: {
29234
+ auth: false,
29235
+ // Public endpoint - authenticated password change, requires valid JWT in Authorization header
29236
+ policies: []
29237
+ }
29266
29238
  },
29267
29239
  {
29268
29240
  method: "GET",
29269
29241
  path: "/config",
29270
29242
  handler: "settingsController.getPublicConfig",
29271
29243
  config: {
29244
+ auth: false,
29245
+ // Public endpoint - frontend needs this for validation
29272
29246
  policies: []
29273
- // This is intentionally public for frontend config
29274
29247
  }
29275
29248
  },
29276
- ...settings
29249
+ {
29250
+ method: "POST",
29251
+ path: "/requestMagicLink",
29252
+ handler: "firebaseController.requestMagicLink",
29253
+ config: {
29254
+ auth: false,
29255
+ // Public endpoint - passwordless authentication
29256
+ policies: []
29257
+ }
29258
+ }
29277
29259
  ]
29278
29260
  };
29279
29261
  const routes = {
29280
29262
  admin,
29281
- "content-api": contentApi,
29282
- "content-internal-api": contentInternalApi
29263
+ "content-api": contentApi
29283
29264
  };
29284
29265
  const checkValidJson = (jsonString) => {
29285
29266
  try {
@@ -29571,7 +29552,7 @@ const settingsService = ({ strapi: strapi2 }) => {
29571
29552
  /**
29572
29553
  * Updates only the magic link settings without affecting other configuration
29573
29554
  */
29574
- async updateMagicLinkSettings(settings2) {
29555
+ async updateMagicLinkSettings(settings) {
29575
29556
  try {
29576
29557
  const foundConfig = await strapi2.db.query(CONFIG_CONTENT_TYPE).findOne({ where: {} });
29577
29558
  if (!foundConfig) {
@@ -29580,10 +29561,10 @@ const settingsService = ({ strapi: strapi2 }) => {
29580
29561
  const result = await strapi2.db.query(CONFIG_CONTENT_TYPE).update({
29581
29562
  where: { id: foundConfig.id },
29582
29563
  data: {
29583
- enableMagicLink: settings2.enableMagicLink,
29584
- magicLinkUrl: settings2.magicLinkUrl,
29585
- magicLinkEmailSubject: settings2.magicLinkEmailSubject,
29586
- magicLinkExpiryHours: settings2.magicLinkExpiryHours
29564
+ enableMagicLink: settings.enableMagicLink,
29565
+ magicLinkUrl: settings.magicLinkUrl,
29566
+ magicLinkEmailSubject: settings.magicLinkEmailSubject,
29567
+ magicLinkExpiryHours: settings.magicLinkExpiryHours
29587
29568
  }
29588
29569
  });
29589
29570
  return {
@@ -29999,7 +29980,7 @@ const userService = ({ strapi: strapi2 }) => {
29999
29980
  try {
30000
29981
  const actionCodeSettings = {
30001
29982
  url: passwordResetUrl,
30002
- handleCodeInApp: true
29983
+ handleCodeInApp: false
30003
29984
  };
30004
29985
  const timeoutPromise = new Promise((_2, reject) => {
30005
29986
  setTimeout(
@@ -30220,17 +30201,13 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30220
30201
  });
30221
30202
  if (userByEmail) {
30222
30203
  validateUserNotBlocked(userByEmail);
30223
- try {
30224
- await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByEmail.documentId, {
30225
- firebaseUserID: firebaseUID
30226
- });
30227
- strapi2.log.info(`Auto-linked user ${userByEmail.username} to Firebase UID ${firebaseUID}`);
30228
- } catch (error2) {
30229
- if (error2.code !== "23505") {
30230
- throw error2;
30231
- }
30232
- strapi2.log.info(`User ${userByEmail.username} already linked to Firebase (race condition handled)`);
30204
+ const existingLink = await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").getByFirebaseUID(firebaseUID);
30205
+ if (existingLink && existingLink.user) {
30206
+ validateUserNotBlocked(existingLink.user);
30207
+ return existingLink.user;
30233
30208
  }
30209
+ await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByEmail.documentId, { firebaseUserID: firebaseUID });
30210
+ strapi2.log.info(`Auto-linked user ${userByEmail.username} to Firebase UID ${firebaseUID}`);
30234
30211
  return userByEmail;
30235
30212
  }
30236
30213
  const firebaseDataByApple = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findMany({
@@ -30244,21 +30221,13 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30244
30221
  const userByAppleEmail = firebaseDataByApple?.[0]?.user || null;
30245
30222
  if (userByAppleEmail) {
30246
30223
  validateUserNotBlocked(userByAppleEmail);
30247
- try {
30248
- await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByAppleEmail.documentId, {
30249
- firebaseUserID: firebaseUID
30250
- });
30251
- strapi2.log.info(
30252
- `Auto-linked Apple user ${userByAppleEmail.username} to Firebase UID ${firebaseUID}`
30253
- );
30254
- } catch (error2) {
30255
- if (error2.code !== "23505") {
30256
- throw error2;
30257
- }
30258
- strapi2.log.info(
30259
- `User ${userByAppleEmail.username} already linked to Firebase (race condition handled)`
30260
- );
30224
+ const existingLink = await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").getByFirebaseUID(firebaseUID);
30225
+ if (existingLink && existingLink.user) {
30226
+ validateUserNotBlocked(existingLink.user);
30227
+ return existingLink.user;
30261
30228
  }
30229
+ await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByAppleEmail.documentId, { firebaseUserID: firebaseUID });
30230
+ strapi2.log.info(`Auto-linked Apple user ${userByAppleEmail.username} to Firebase UID ${firebaseUID}`);
30262
30231
  return userByAppleEmail;
30263
30232
  }
30264
30233
  }
@@ -30269,17 +30238,13 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30269
30238
  });
30270
30239
  if (userByPhone) {
30271
30240
  validateUserNotBlocked(userByPhone);
30272
- try {
30273
- await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByPhone.documentId, {
30274
- firebaseUserID: firebaseUID
30275
- });
30276
- strapi2.log.info(`Auto-linked phone user ${userByPhone.username} to Firebase UID ${firebaseUID}`);
30277
- } catch (error2) {
30278
- if (error2.code !== "23505") {
30279
- throw error2;
30280
- }
30281
- strapi2.log.info(`User ${userByPhone.username} already linked to Firebase (race condition handled)`);
30241
+ const existingLink = await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").getByFirebaseUID(firebaseUID);
30242
+ if (existingLink && existingLink.user) {
30243
+ validateUserNotBlocked(existingLink.user);
30244
+ return existingLink.user;
30282
30245
  }
30246
+ await strapi2.plugin("firebase-authentication").service("firebaseUserDataService").updateForUser(userByPhone.documentId, { firebaseUserID: firebaseUID });
30247
+ strapi2.log.info(`Auto-linked phone user ${userByPhone.username} to Firebase UID ${firebaseUID}`);
30283
30248
  return userByPhone;
30284
30249
  }
30285
30250
  }
@@ -30306,12 +30271,13 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30306
30271
  type: "plugin",
30307
30272
  name: "users-permissions"
30308
30273
  });
30309
- const settings2 = await pluginStore.get({
30274
+ const settings = await pluginStore.get({
30310
30275
  key: "advanced"
30311
30276
  });
30312
- const role = await strapi2.db.query("plugin::users-permissions.role").findOne({ where: { type: settings2.default_role } });
30277
+ const role = await strapi2.db.query("plugin::users-permissions.role").findOne({ where: { type: settings.default_role } });
30313
30278
  userPayload.role = role.id;
30314
30279
  userPayload.confirmed = true;
30280
+ userPayload.provider = "firebase";
30315
30281
  userPayload.email = decodedToken.email;
30316
30282
  userPayload.phoneNumber = decodedToken.phone_number;
30317
30283
  if (profileMetaData) {
@@ -30347,7 +30313,22 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30347
30313
  strapi2.log.info(`Created user ${newUser.username} and linked to Firebase UID ${decodedToken.uid}`);
30348
30314
  return newUser;
30349
30315
  } catch (error2) {
30350
- if (newUser) {
30316
+ if (error2.code === "23505") {
30317
+ strapi2.log.warn(
30318
+ `[Race Condition] User creation conflict for Firebase UID ${decodedToken.uid}. Another concurrent request created the user first. Retrying lookup...`
30319
+ );
30320
+ const existingUser = await strapi2.plugin("firebase-authentication").service("firebaseService").checkIfUserExists(decodedToken);
30321
+ if (existingUser) {
30322
+ strapi2.log.info(
30323
+ `[Race Condition] Successfully found user ${existingUser.username} created by concurrent request`
30324
+ );
30325
+ return existingUser;
30326
+ }
30327
+ strapi2.log.error(
30328
+ `[Race Condition] Failed to find user after race condition retry for Firebase UID ${decodedToken.uid}`
30329
+ );
30330
+ }
30331
+ if (error2.code !== "23505" && newUser) {
30351
30332
  try {
30352
30333
  await strapi2.db.query("plugin::users-permissions.user").delete({
30353
30334
  where: { documentId: newUser.documentId }
@@ -30483,7 +30464,7 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30483
30464
  },
30484
30465
  /**
30485
30466
  * Forgot password flow - sends reset email
30486
- * Public endpoint that generates a JWT token and sends a password reset email
30467
+ * Public endpoint that sends a Firebase-hosted password reset email using Firebase's secure hosted UI
30487
30468
  */
30488
30469
  forgotPassword: async (ctx) => {
30489
30470
  const { email: email2 } = ctx.request.body;
@@ -30529,13 +30510,30 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30529
30510
  if (!strapiUser) {
30530
30511
  return { message: "If an account with that email exists, a password reset link has been sent." };
30531
30512
  }
30532
- const jwtService = strapi2.plugin("users-permissions").service("jwt");
30533
- const token = jwtService.issue(
30534
- { id: strapiUser.id },
30535
- // Use numeric id, not documentId
30536
- { expiresIn: "1h" }
30537
- );
30538
- const resetLink = `${resetUrl}?token=${token}`;
30513
+ const actionCodeSettings = {
30514
+ url: resetUrl,
30515
+ // Continue URL after reset completes on Firebase's page
30516
+ handleCodeInApp: false
30517
+ };
30518
+ const timeoutPromise = new Promise((_2, reject) => {
30519
+ setTimeout(
30520
+ () => reject(new Error("Firebase generatePasswordResetLink timeout after 10 seconds")),
30521
+ 1e4
30522
+ );
30523
+ });
30524
+ let resetLink;
30525
+ try {
30526
+ resetLink = await Promise.race([
30527
+ strapi2.firebase.auth().generatePasswordResetLink(strapiUser.email, actionCodeSettings),
30528
+ timeoutPromise
30529
+ ]);
30530
+ strapi2.log.info(
30531
+ `✅ Password reset link generated successfully for ${strapiUser.email}: ${resetLink}`
30532
+ );
30533
+ } catch (error2) {
30534
+ strapi2.log.error(`❌ Failed to generate password reset link for ${strapiUser.email}:`, error2);
30535
+ throw error2;
30536
+ }
30539
30537
  await strapi2.plugin("firebase-authentication").service("emailService").sendPasswordResetEmail(strapiUser, resetLink);
30540
30538
  return {
30541
30539
  message: "If an account with that email exists, a password reset link has been sent."
@@ -30549,7 +30547,17 @@ const firebaseService = ({ strapi: strapi2 }) => ({
30549
30547
  },
30550
30548
  /**
30551
30549
  * Reset password with authenticated JWT
30552
- * Public endpoint that validates a JWT token and resets the user's password
30550
+ * Allows authenticated users (or admins) to change a user's Firebase password
30551
+ *
30552
+ * @param ctx - Koa context with JWT in Authorization header and new password in body
30553
+ * @returns User object and fresh JWT for auto-login
30554
+ *
30555
+ * @remarks
30556
+ * Use cases:
30557
+ * 1. Admin-initiated password reset (via admin panel)
30558
+ * 2. User-initiated password change (when already authenticated)
30559
+ *
30560
+ * NOT used for forgot password email flow - that now uses Firebase's hosted UI
30553
30561
  */
30554
30562
  resetPassword: async (ctx) => {
30555
30563
  const { password } = ctx.request.body;
@@ -31284,7 +31292,7 @@ const firebaseUserDataService = ({ strapi: strapi2 }) => ({
31284
31292
  if (!userId || typeof userId !== "string") {
31285
31293
  throw new Error("Invalid user documentId");
31286
31294
  }
31287
- let firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findOne({
31295
+ let firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findFirst({
31288
31296
  filters: { user: { documentId: { $eq: userId } } },
31289
31297
  populate: ["user"]
31290
31298
  });
@@ -31299,7 +31307,7 @@ const firebaseUserDataService = ({ strapi: strapi2 }) => ({
31299
31307
  * @returns Firebase user data with populated user
31300
31308
  */
31301
31309
  async getByFirebaseUID(firebaseUID) {
31302
- return await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findOne({
31310
+ return await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findFirst({
31303
31311
  filters: { firebaseUserID: { $eq: firebaseUID } },
31304
31312
  populate: ["user"]
31305
31313
  });
@@ -31310,7 +31318,7 @@ const firebaseUserDataService = ({ strapi: strapi2 }) => ({
31310
31318
  * @param data - Fields to update
31311
31319
  */
31312
31320
  async updateForUser(userId, data) {
31313
- let firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findOne({
31321
+ let firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findFirst({
31314
31322
  filters: { user: { documentId: { $eq: userId } } }
31315
31323
  });
31316
31324
  if (!firebaseData) {
@@ -31326,8 +31334,8 @@ const firebaseUserDataService = ({ strapi: strapi2 }) => ({
31326
31334
  });
31327
31335
  } catch (error2) {
31328
31336
  if (error2.code === "23505") {
31329
- strapi2.log.warn(`Race condition detected for user ${userId}, retrying findOne`);
31330
- firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findOne({
31337
+ strapi2.log.warn(`Race condition detected for user ${userId}, retrying findFirst`);
31338
+ firebaseData = await strapi2.documents("plugin::firebase-authentication.firebase-user-data").findFirst({
31331
31339
  filters: { user: { documentId: { $eq: userId } } }
31332
31340
  });
31333
31341
  if (firebaseData) {