Almost all Firebase functions return a promise; whether you use .then() or async/await doesn't matter (While the current "best practice" is to use async/await, the reality is that it is just "syntactic sugar" on top of promises).
As to waiting - you are right that there is often NOT a top-level async/await - it depends on your boot sequence. What you CAN do is something like this (obviously this example is for Stripe):
```
import { loadStripe } from "@stripe/stripe-js";
export let stripe = null;
export let stripe_started = false;
export let stripe_running = false;
(async () => {
try {
stripe = await loadStripe("pk_test_GDHxwe8K5eX0MvBUhnx5FtrY00mAd6B0IT");
stripe_running = true;
} catch (err) {
stripe_running = false;
} finally {
stripe_started = true;
}
})();
```
This uses a self-executing closure to asynchronously run the initialization, and simple "flags" to let other functions know if it's complete.
In my particular case, I am *essentially* doing:
```
firebase.InitializeApp(config).then(() => {...more code...});
```
...where the "more code" effectively sets an "enabled" flag (not really, but it amounts to the same thing).