React / Stripe / createPortalLink() with firebase v9 - javascript

I'm using Stripe extension for Firebase with firebase functions.
Since I refactored a bit my code for firebase v9 modular SDK, I'm getting the following console error with my Stripe createPortalLink() function:
Uncaught (in promise) TypeError: _firebase__WEBPACK_IMPORTED_MODULE_2__.default.functions is not a function
at createPortalLink (Subscription.js:99:1)
Here is my function:
async function createPortalLink() {
const functionRef = app
.functions("europe-west1")
.httpsCallable("ext-firestore-stripe-payments-createPortalLink");
const { data } = await functionRef({
returnUrl: `${window.location.origin}/dashboard-pro/abonnement/`,
locale: "auto",
});
window.location.assign(data.url);
}
Can anyone please advise?
Thanks

You need to use the getFunctions() and httpsCallable() functions in the new Modular SDK as shown below:
import { getFunctions, httpsCallable } from "firebase/functions";
// after initializing Firebase
const functions = getFunctions();
const functionRef = httpsCallable(functions, 'ext-firestore-stripe-payments-createPortalLink');
functionRef({
returnUrl: `${window.location.origin}/dashboard-pro/abonnement/`,
locale: "auto",
})
.then((result) => {
const data = result.data;
});
Checkout the documentation for more details.

Related

Twilio Conversations push notifications with Firebase Cloud Messaging

I'm attempting to set up push notifications using Twilio Conversations and Firebase Cloud Messaging on a Next.js 12 app. The documentation is written with the assumption of using Firebase 8 syntax, but I'm using Firebase 9 in this scenario. I've been struggling to get push notifications to work while the page is open. I have the service worker set up (per Firebase docs) but it doesn't seem to be recognizing that a new message is being received from Twilio in order to actually show the notification.
Docs I've followed:
https://www.twilio.com/docs/conversations/javascript/push-notifications-web
https://firebase.google.com/docs/cloud-messaging/js/client
What I've tried
On my backend, I pass the Push Credential SID when I construct a new ChatGrant:
const chatGrant = new ChatGrant({
pushCredentialSid: process.env.TWILIO_PUSH_CREDENTIAL_SID,
serviceSid: CONVERSATIONS_SID
});
In the frontend, I followed the Twilio documentation to set up Firebase:
init.ts
import { getMessaging, getToken, onMessage } from "firebase/messaging";
import { initializeApp } from "firebase/app";
import { Client } from "#twilio/conversations";
// Omitted
const firebaseConfig = {};
export function getPermission(client: Client) {
const app = initializeApp(firebaseConfig);
const messaging = getMessaging(app);
getToken(messaging, { vapidKey:"KEY" })
.then((data) => {
console.log({ data });
client.setPushRegistrationId("fcm", data).catch((error) => {
console.error({ error });
});
onMessage(messaging, (payload) => {
console.log({ payload });
client.handlePushNotification(payload).catch((error) => {
console.error(error);
// test
});
});
})
.catch((error) => {
console.error(error);
// test
});
}
I call getPermission from this file once when the conversation app loads.
// chatClient is stored in a ref so it doesn't recalculate/refetch/reauthorize all the time
const chatClient = useRef(null);
// [Other code]
chatClient.current = new ConversationClient(data.chatAccessToken);
chatClient.current.on("connectionStateChanged", async (state) => {
switch (state) {
case "connected": {
// Only get permission once the chat client is fully set up
getPermission(chatClient.current);
// ..........
And my service worker firebase-messaging-sw.js:
importScripts('https://www.gstatic.com/firebasejs/9.14.0/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/9.14.0/firebase-messaging-compat.js');
if (!firebase.apps.length) {
firebase.initializeApp({
// CONFIG GOES HERE
});
}
const messaging = firebase.messaging();
//background notifications will be received here
messaging.onBackgroundMessage(function(payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
// Customize notification here
const notificationTitle = 'Background Message Title';
const notificationOptions = {
body: 'Background Message body.',
icon: '/android-chrome-192x192.png'
};
self.registration.showNotification(notificationTitle, notificationOptions);
});
What's happening
In the service worker, messaging.onBackgroundMessage never appears to be invoked. I don't know where this issue is derived from - is Twilio not passing message info to Firebase? Or is Firebase not listening to when Twilio sends it the information? Has that changed from v8 to v9?
In init.ts, onMessage is never invoked. Same deal here, is Twilio not passing the right information to Firebase, or did I misconfigure something?
I'm not getting any console errors or warnings, and the network tab is not pointing out anything super helpful.
I got this to work by using the example code (from docs) and configuring my Next.js application to compile the TypeScript into JavaScript. This helped a lot: https://github.com/vercel/next.js/issues/33863#issuecomment-1140518693

Is there a way to use firebase secret environment variables in slack/bolt

We operate bots by combining Firebase and Slack/bolt.
I currently use functions.config()to manage my Slack tokens and secrets, but would like to migrate to using Secret Manager.
https://firebase.google.com/docs/functions/config-env#secret-manager
boltapp.js
const functions = require("firebase-functions");
const { App, ExpressReceiver, subtype } = require("#slack/bolt");
const config = functions.config();
const expressReceiver = new ExpressReceiver({
signingSecret: process.env.SLACK_SECRET,
endpoints: "/events",
processBeforeResponse: true,
});
const app = new App({
receiver: expressReceiver,
token: process.env.SLACK_TOKEN
});
app.error(error => { console.error(error) });
app.use(async ({ client, payload, context, next }) => {
console.info('It\'s payload', JSON.stringify(payload))
if (!context?.retryNum) {
await next();
} else {
console.debug('app.use.context', context);
}
});
//**bot processing**//
// https://{your domain}.cloudfunctions.net/slack/events
module.exports = functions
.runWith({ secrets: ["SLACK_TOKEN","SLACK_SECRET"] })
.https.onRequest(expressReceiver.app);
But when I rewrote it for migration, I got the following error.
Is there a way to rewrite the code while avoiding this error?
Failed to load function definition from source: FirebaseError: Failed to load function definition from source: Failed to generate manifest from function source: Error: Apps used in a single workspace can be initialized with a token. Apps used in many workspaces should be initialized with oauth installer options or authorize.
Since you have not provided a token or authorize, you might be missing one or more required oauth installer options. See https://slack.dev/bolt-js/concepts#authenticating-oauth for these required fields.

firebase admin sdk to create new user

**In my crud project the admin adds the user in the docs as well as in auth by normal sdk would replace the current user so i tried admin sdk but writing the cloud functions and calling is getting complex as im new to firebase. i got this got from fellow stackoverflow's thread modified it for my convenience but doesn't seems to be working. **
I deployed the function locally using "firebase serve"
cloud function
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.createUser = functions.firestore
.document('Teamchers/{userId}')
.onCreate(async (snap, context) => {
const userId = context.params.userId;
const newUser = await admin.auth().createUser({
disabled: false,
username: snap.get('UserName'),
email: snap.get('email'),
password: snap.get('password'),
subjectname: snap.get('subjectname')
});
return admin.firestore().collection('Teamchers').doc(userId).delete();
});
calling it
const createUser = firebase.functions().httpsCallable('createUser');
const handleadd = async (e) =>{
e.preventDefault();
try{
createUser({userData: data}).then(result => {
console.log(data);
});
addDoc(collection(db, "Courses" , "Teachers", data.subjectname ), {
...data,
timestamp: serverTimestamp(),
});
alert("Faculty added succesfully")
} catch (e){
console.log(e.message)
}
}
In addition to the potential typo mentioned by coderpolo and Frank, there are several other errors in your codes:
1. JS SDK versions mixing-up
It seems that you are mixing up JS SDK V9 syntax with JS SDK V8 syntax.
Defining the Callable Cloud Function in your front-end as follows is V8 syntax:
const createUser = firebase.functions().httpsCallable('createUser');
While doing addDoc(collection(...)) is V9 syntax.
You have to choose one version of the JS SDK and unify your code (see V9 example below, #3).
2. Wrong Cloud Function definition
Defining your function with:
exports.createUser = functions.firestore
.document('Teamchers/{userId}')
.onCreate(async (snap, context) => {..})
is not the way you should define a Callable Cloud function.
With onCreate() you are defining a background triggered Cloud Function that is to be triggered when a new doc is created in Firestore and not a Callable CF.
You need to adapt it as follows:
exports.createUser = functions.https.onCall((data, context) => {
try {
// ....
// Return data that can be JSON encoded
} catch (e) {
console.log(e.message)
// !!!! See the doc: https://firebase.google.com/docs/functions/callable#handle_errors
}
});
3. Use await since your handleadd() function is async
This is not stricto sensu an error but you should avoid using then() and async/await together.
I would refactor it as follows (V9 syntax):
import { getFunctions, httpsCallable } from "firebase/functions";
const functions = getFunctions();
const createUser = httpsCallable(functions, 'createUser');
const handleadd = async (e) => {
e.preventDefault();
try {
await createUser({ userData: data })
await addDoc(collection(db, "Courses", "Teachers", data.subjectname), {
...data,
timestamp: serverTimestamp(),
});
alert("Faculty added succesfully")
} catch (e) {
console.log(e.message)
}
}

Interacting with firebase firestore from firebase cloud functions

I am trying to interact with firebase firestore from my cloud function. The cloud functions looks like the following:
const admin = require("firebase-admin");
const functions = require("firebase-functions");
admin.initializeApp();
const db = admin.firestore();
exports.addVote = functions.https.onCall((data, context) => {
return db
.doc("sdd-enheter/enhet/votes/voteID")
.set({ user: "user", vote: 0 });
});
When calling the function from the client side I get a firebase internal error, indicating that the function has been called but throws an error. What should I do to fix this?
Your function needs to return a promise or otherwise terminate by throwing an https error. Throwing the https error will give the client back a relevant error that it can handle, so consider making that a habit. The function below covers both of those bases. If you still get an error then share that error with us as it appears in the console's function log.
exports.addVote = functions.https.onCall((_data, _context) => {
const db = admin.firestore();
try {
return db.doc("sdd-enheter/enhet/votes/voteID").set({user: "user", vote: 0});
} catch (error) {
throw new functions.https.HttpsError("unknown", "Failed to add vote.", error);
}
});

How to use setPersistence in Firebase Modular SDK V9?

i try firebase 9 version persistence for login:
setPersistence(auth, firebaseApp.auth.Persistence.LOCAL).then( async() => {
// login
}).catch((e) => {
this.error = e.message
})
show error:
Uncaught TypeError: Cannot read property 'Persistence' of undefined
any clue?
You need to import persistence states this way:
import {
getAuth,
setPersistence,
browserLocalPersistence,
browserSessionPersistence,
inMemoryPersistence
} from "firebase/auth";
const auth = getAuth()
await setPersistence(auth, browserLocalPersistence);
Namespaced Version V8
Modular Version V9
firebase.auth.Auth.Persistence.LOCAL
browserLocalPersistence
firebase.auth.Auth.Persistence.SESSION
browserSessionPersistence
firebase.auth.Auth.Persistence.NONE
inMemoryPersistence

Categories