admin.messaging(...).send is not a function - firebase

I am using firebase-admin to send a push notification via Cloud Functions, but I keep getting this error:
TypeError: admin.messaging(...).send is not a function
at exports.sendNotification.functions.database.ref.onWrite (/user_code/index.js:43:27)
at Object.<anonymous> (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:59:27)
at next (native)
at /user_code/node_modules/firebase-functions/lib/cloud-functions.js:28:71
at __awaiter (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:24:12)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:53:36)
at /var/tmp/worker/worker.js:700:26
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
Any idea why it's not working? I am using firebase-admin version 5.9.1, so it is the latest version. It should include the .send function but it's still not working. I have uninstalled the plugin and re-installed it, but still, it did not work.
This is the code I am using:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.cert({
projectId: "xxx",
clientEmail: 'xxx#xxx.iam.gserviceaccount.com',
privateKey: '-----BEGIN PRIVATE KEY-----<KEY>-----END PRIVATE KEY-----\n'
}),
databaseURL: "https://xxx.firebaseio.com"
});
exports.sendNotification = functions.database.ref("xxx").onWrite((event) => {
console.log("notify");
const registrationToken = "xxx";
// See documentation on defining a message payload.
var message = {
notification: {
title: "You have a new service request",
body: "this is the main body"
},
data: {
score: '850',
time: '2:45'
},
token: registrationToken
};
return admin.messaging().send(message)
.then(function (response) {
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
});
});
What am I doing wrong?

It should be sendToDevice not send, maybe something like this :
var message = {
notification: {
title: "You have a new service request",
body: "this is the main body"
},
data: {
score: '850',
time: '2:45'
}
};
return admin.messaging().sendToDevice(registrationToken, message)
.then(function (response) {
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
});

Related

Unimplemented API error when running admin.storage().bucket(..).file(..).move() in an emulated Firebase function

"firebase": "9.0.1" - local
"firebase-tools": 9.17.0 - global
"node": v14.17.4
I'm calling .move() using the Firebase admin SDK in an emulated function. Firebase returns the following error:
ApiError: file#copy failed with an error - Not Implemented
at new ApiError (.../functions/node_modules/#google-cloud/common/build/src/util.js:73:15)
statusCode: 501
request: {
agent: [Agent],
headers: [Object],
href: 'http://localhost:9199/b/public-8s9ch/o/91ff38b1-b521-4a23-8844-b12cffa0ee98%2Fscreenshot.png/rewriteTo/b/private-8s9ch/o/91ff38b1-b521-4a23-8844-b12cffa0ee98%2Fcd665e29-edc8-4832-9bc7-110c21f1e560?'
},
body: 'Not Implemented',
The exact same code, with the same tests and installed packages, work perfectly when deployed to Firebase instead of being used in the emulator.
The same issue occurs with any call to the storage API regardless of using the Admin SDK or using the client SDK e.g. .copy, .move, .delete, etc.
Here's some code to help with reproducing the error:
export const firebaseFunction = functions
.runWith({ memory: "128MB" })
.region("us-central1")
.firestore.document("documents/{docId}")
.onCreate(async (snap, context) => {
try {
const { srcId } = snap.data();
const [files] = await admin
.storage()
.bucket('public')
.getFiles({
prefix: `${srcId}/`,
delimiter: "/",
autoPaginate: false,
});
const promises = files.map((file) => {
return new Promise<void>(async (resolve, reject) => {
try {
const dst = admin
.storage()
.bucket('private')
.file(`${srcId}/${uuidv4()}`);
await file.move(dst);
resolve();
} catch (err) {
reject(err);
}
});
});
await Promise.all(promises);
} catch (error) {
return console.log(error);
}
});

FirebaseAppError: Error while making request: read ECONNRESET. Error code: ECONNRESET

I follow this link https://pragli.com/blog/how-to-authenticate-with-google-in-electron/ to authenticate-with-google-in-electron.
here are my codes:
var express = require('express');
var router = express.Router();
const admin = require('firebase-admin');
var firebaseConfig = {
apiKey: "***",
authDomain: "podium-***.firebaseapp.com",
databaseURL: "https://podium-***.firebaseio.com",
projectId: "podium-***",
storageBucket: "podium-***.appspot.com",
messagingSenderId: "***",
appId: "1:***:web:***",
measurementId: "G-***"
};
admin.initializeApp(firebaseConfig);
router.post('/createCustomToken', async (req, res) => {
try {
// const query = request.query
const idToken = req.body.idToken;
// console.log(idToken);
admin.auth().verifyIdToken(idToken)
.then(function (decodedToken) {
let uid = decodedToken.uid;
console.log(uid);
}).catch(function (error) {
// Handle error
console.log(error);
});
const decodedToken = await admin.auth().verifyIdToken(idToken)
// console.log(decodedToken);
const uid = decodedToken.uid
const authToken = await admin.auth().createCustomToken(uid)
console.log('Authentication token', authToken)
// await admin.database().ref(`ot-auth-codes/${oneTimeCode}`).set(authToken)
res.status(200).json({
token: authToken
})
} catch (error) {
// console.log(error);
}
});
module.exports = router;
console error:
FirebaseAppError: Error while making request: read ECONNRESET. Error code: ECONNRESET
at FirebaseAppError.FirebaseError [as constructor] (E:\User\Documents\Work\Angular-demo\podium-server\node_modules\firebase-admin\lib\utils\error.js:42:28)
at FirebaseAppError.PrefixedFirebaseError [as constructor] (E:\User\Documents\Work\Angular-demo\podium-server\node_modules\firebase-admin\lib\utils\error.js:88:28)
at new FirebaseAppError (E:\User\Documents\Work\Angular-demo\podium-server\node_modules\firebase-admin\lib\utils\error.js:123:28)
at E:\User\Documents\Work\Angular-demo\podium-server\node_modules\firebase-admin\lib\utils\api-request.js:209:19
at processTicksAndRejections (internal/process/task_queues.js:97:5) {
errorInfo: {
code: 'app/network-error',
message: 'Error while making request: read ECONNRESET. Error code: ECONNRESET'
},
codePrefix: 'app'
}
any helps? thanks:)

Send notification to all user who have a specific location using Firebase Cloud Functions

I have a trigger that fires when an item is creating. Therefore, i want to see that when the item is created, all users who have a location that was saved in the item will receive a notification
import functions = require('firebase-functions');
import admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotification = functions.firestore
.document('itens/{itenId}').onCreate((snap, context) => {
//You get the values of the newly created doc as follows:
const data = snap.data();
const name = data.name;
const location = data.location;
const payload = {
notification: {
title: "Avana - Está bater",
body: `Podes encontrar : ${name} em ${location}`, //Here we use value
sound: "default"
}
};
const options = {
priority: "high",
};
admin.messaging().sendToTopic("newItem", payload, options)
.then(function (response) {
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
});
console.log("Notification sent!");
return null;
});
your solution is Firebase Geofire:
https://firebase.googleblog.com/2013/09/geofire-location-queries-for-fun-and.html
https://medium.com/google-cloud/firebase-is-cool-geofire-is-just-awesome-b7f2be5e0f0f#.x78gjws28

Firebase Cloud Functions Error with CanonicalRegistrationTokenCount

I am trying to send a signup notification to my app after registration and user has been saved in db. I am using firebase cloud functions for this purpose.
I have gotten the device token from firebaseinstanceidservice and saved that in the user's db with the path users/userid/deviceToken and referenced this path in the function like below code:
exports.sendNotification = functions.database.ref("users/{userId}/{instanceId_token}")
I have tried logging the devicetoken just to be sure but in cloud console, I keep getting other attributes for that log like : sendNotification
deviceToken name, sendNotification
deviceToken userId instead of the alphanumeric value saved in db. Is this path wrong?
Here's my full code:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification =
functions.database.ref("users/{userId}/{instanceId_token}")
.onWrite((changes, context) => {
const userId = context.params.userId;
console.log("user-id", userId);
const notificationToken = context.params.instanceId_token;
console.log("deviceToken", notificationToken);
var payload = {
data: {
title: "Welcome to My Group",
message: "You may have new messages"
}
};
return admin.messaging().sendToDevice(notificationToken, payload)
.then(function (response) {
return console.log("Successfully sent message: ", response);
})
.catch(function (error) {
return console.log("Error sending message: ", error);
})
});
Also, the function shows this mildly positive message, after the admin.messaging callback:
Successfully sent message: { results: [ { error: [Object] } ],
canonicalRegistrationTokenCount: 0,
failureCount: 1,
successCount: 0,
multicastId: 8880906162831350000 }
How do I resolve this, I am using an android client?
Here's my db structure:
You should trigger you function on the upper node, as follows. And access the instanceId_token through changes.after.val().
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification =
functions.database.ref("users/{userId}")
.onWrite((changes, context) => {
const userId = context.params.userId;
console.log("user-id", userId);
const notificationToken = changes.after.val().instanceId_token;
console.log("deviceToken", notificationToken);
var payload = {
data: {
title: "Welcome to My Group",
message: "You may have new messages"
}
};
return admin.messaging().sendToDevice(notificationToken, payload)
.catch(function (error) {
console.log("Error sending message: ", error);
})
});
In case you add the instanceId_token ONLY AFTER having created the user, then you should trigger with onUpdate() (which "triggers when data is updated", while onWrite() "triggers when data is created, updated, or deleted").
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification =
functions.database.ref("users/{userId}")
.onUpdate((changes, context) => {
const userId = context.params.userId;
console.log("user-id", userId);
const notificationToken = changes.after.val().instanceId_token;
console.log("deviceToken", notificationToken);
if (notificationToken === undefined) {
console.log("notificationToken === undefined");
return false;
} else {
var payload = {
data: {
title: "Welcome to My Group",
message: "You may have new messages"
}
};
return admin.messaging().sendToDevice(notificationToken, payload)
.catch(function (error) {
console.log("Error sending message: ", error);
})
}
});
Also note that you should not do
return admin.messaging().sendToDevice(notificationToken, payload)
.then(function (response) {
return console.log("Successfully sent message: ", response);
})
.catch(function (error) {
return console.log("Error sending message: ", error);
});
because in this case you are not returning a promise "that resolves when all the async work is done in the function". (see the answer of this question)
So just return the promise returned by sendToDevice (see doc), as follows:
return admin.messaging().sendToDevice(notificationToken, payload)
.catch(function (error) {
console.log("Error sending message: ", error); // here no return
});

Receiving notifications in Ionic mobile app in background and foreground through Node.js (firebase-admin)

I have an Ionic mobile application that receives notifications from the Firebase console. The application correctly receives notifications in background and foreground. However, when I send notifications from Node.js with firebase-admin plugin, only foreground notification arrives. Notifications do not arrive when the application is in the background.
What could be the problem? Does anyone know why the mobile app receive notifications in background with Firebase console but not with Node.js?
Thanks for any idea.
This is the code in the mobile application (app.component.ts):
this.fcm.subscribeToTopic('all');
platform.ready().then(() => {
this.fcm.getToken().then(token => {
console.log(token);
let alert = this.alertCtrl.create({
title: '¡new notification!',
message: token,
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: () => {
console.log('cancel button');
}
},
{
text: 'OK',
handler: () => {
console.log('ok button');
this.navCtrl.push('DetailPage');
}
}
]
});
alert.present();
});
this.fcm.onNotification().subscribe(data => {
alert('message received')
if(data.wasTapped) {
console.info("Received in background");
} else {
console.info("Received in foreground");
};
});
statusBar.styleDefault();
splashScreen.hide();
});
This is the code in Node.js:
var sys = require("util");
var admin = require('firebase-admin');
var serviceAccount = require('./xxxx.json');
var registrationToken ="xxxxxx";
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://xxxxx"
});
var message = {
data: {
score: '850',
time: '2:45'
},
token: registrationToken
};
admin.messaging().send(message)
.then(function(response) {
console.log("Successfully sent message:", response);
})
.catch(function(error){
console.log("Error sending message", error);
});

Resources