React native cloud functions logs empty - firebase

I was trying cloud functions today, followed the docs and got it to deploy successfully but the logs will always be empty.
I am using RN firebase client SDK from this website
https://rnfirebase.io/docs/v5.x.x/functions/reference/functions
"dependencies": {
"firebase-admin": "^7.0.0",
"firebase-functions": "^2.2.0",
}
This is my function code :
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
exports.helloWorld = functions.https.onRequest((request, response) => {
console.log('hello world');
response.send("Hello from Firebase yo!");
});
this is my dashboard screen shot:
this is my logs screen shot:
Did i miss anything ?

Related

How To Access Cloud Storage In Cloud Functions

Am trying to access Firebase Cloud Storage in my Cloud functions but i keep getting the following error in the cloud functions log:
Error: Failed to import the Cloud Storage client library for Node.js. Make sure to install the "#google-cloud/storage" npm package. Original error: SyntaxError: Unexpected token {
at new FirebaseError (/srv/node_modules/firebase-admin/lib/utils/error.js:43:28)
at new Storage (/srv/node_modules/firebase-admin/lib/storage/storage.js:65:19)
at /srv/node_modules/firebase-admin/lib/firebase-app.js:255:20
at FirebaseApp.ensureService_ (/srv/node_modules/firebase-admin/lib/firebase-app.js:376:23)
at FirebaseApp.storage (/srv/node_modules/firebase-admin/lib/firebase-app.js:253:21)
at FirebaseNamespace.fn (/srv/node_modules/firebase-admin/lib/firebase-namespace.js:292:45)
at exports.initializeNewVideoUpload.functions.firestore.document.onCreate (/srv/index.js:383:24)
at cloudFunction (/srv/node_modules/firebase-functions/lib/cloud-functions.js:134:23)
at /worker/worker.js:825:24
at <anonymous>
Below is my code:
const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp();
const db = admin.firestore();
exports.initializeNewVideoUpload = functions.firestore.document('new-videos-uploads/{id}').onCreate(async (snapshot, context) => {
const data = snapshot.data();
const fileNames = data.file_names;
const bucket = admin.storage().bucket('trumateappdev.appspot.com');
fileNames.forEach(async fileName => {
const actualFile = bucket.file(fileName);
const resumableUpload = await actualFile.createResumableUpload();
const uploadEndpointUrl = resumableUpload[0];
data.resumable_urls.push(uploadEndpointUrl);
});
await admin.firestore().collection('new-videos-uploads').doc(context.params.id).update(data);
});
Below are the dependencies in my package.json:
"#google-cloud/storage": "^5.5.0",
"firebase-admin": "^9.2.0",
"firebase-functions": "^3.11.0"
PS: Am on the Spark Plan
I found this solution here. Add this to your package.json:
"engines": {"node": "8"}
Apparently this problem occurs because your node.js version is too old

How do I wire up the firestore emulator with my firebase functions tests?

Currently we are using 'firebase-functions-test' in online mode to test our firebase functions (as described here https://firebase.google.com/docs/functions/unit-testing), which we setup like so:
//setupTests.ts
import * as admin from 'firebase-admin';
const serviceAccount = require('./../test-service-account.json');
export const testEnv = require('firebase-functions-test')({
projectId: 'projectId',
credential: admin.credential.cert(serviceAccount),
storageBucket: 'projectId.appspot.com'
});
const testConfig = {
dropbox: {
token: 'dropboxToken',
working_dir: 'someFolder'
}
};
testEnv.mockConfig(testConfig);
// ensure default firebase app exists:
try {
admin.initializeApp();
} catch (e) {}
We would like to move away from testing against an actual firestore instance in our tests, and use the emulator instead.
The docs, issues, and examples I've been able to find on the net are either outdated, or describe how to set up the emulator for testing security rules, or the web frontend.
Attempts using firebase.initializeAdminApp({ projectId: "my-test-project" }); did not do the trick.
I also tried setting FIRESTORE_EMULATOR_HOST=[::1]:8080,127.0.0.1:8080
So the question is: How can I initialise the firebaseApp in my tests, so that my functions are wired up to the firestore emulator?
I had another crack at it today, more than a year later, so some things have changed, which I can't all list out. Here is what worked for me:
1. Install and run the most recent version of firebase-tools and emulators:
$ npm i -g firebase-tools // v9.2.0 as of now
$ firebase init emulators
# You will be asked which emulators you want to install.
# For my purposes, I found the firestore and auth emulators to be sufficient
$ firebase -P <project-id> emulators:start --only firestore,auth
Take note of the ports at which your emulators are available:
2. Testsetup
The purpose of this file is to serve as a setup for tests which rely on emulators. This is where we let our app know where to find the emulators.
// setupFunctions.ts
import * as admin from 'firebase-admin';
// firebase automatically picks up on these environment variables:
process.env.FIRESTORE_EMULATOR_HOST = 'localhost:8080';
process.env.FIREBASE_AUTH_EMULATOR_HOST = 'localhost:9099';
admin.initializeApp({
projectId: 'project-id',
credential: admin.credential.applicationDefault()
});
export const testEnv = require('firebase-functions-test')();
3. Testing a simple function
For this, we setup a simple script which writes a document to firestore. In the test, we assert that the document exists within the emulator, only after we have run the function.
// myFunction.ts
import * as functions from 'firebase-functions';
import {firestore} from 'firebase-admin';
export const myFunction = functions
.region('europe-west1')
.runWith({timeoutSeconds: 540, memory: '2GB'})
.https.onCall(async () => {
await firestore()
.collection('myCollection')
.doc('someDoc')
.set({hello: 'world'});
return {result: 'success'};
});
// myTest.ts
// import testEnv first, to ensure that emulators are wired up
import {testEnv} from './setupFunctions';
import {myFunction} from './myFunction';
import * as admin from 'firebase-admin';
// wrap the function
const testee = testEnv.wrap(myFunction);
describe('myFunction', () => {
it('should add hello world doc', async () => {
// ensure doc does not exist before test
await admin
.firestore()
.doc('myCollection/someDoc')
.delete()
// run the function under test
const result = await testee();
// assertions
expect(result).toEqual({result: 'success'});
const doc = await admin
.firestore()
.doc('myCollection/someDoc')
.get();
expect(doc.data()).toEqual({hello: 'world'});
});
});
And sure enough, after running the tests, I can observe that the data is present in the firestore emulator. Visit http://localhost:4000/firestore while the emulator is running to get this view.

How to write to a cloud storage bucket with a firebase cloud function triggered from firestore?

To make sure this is as clean and isolated as possible, I created a new test project with nothing in it other than these steps.
I then enabled cloud firestore in the console. I created a new collection called "blarg" (great name, eh!). I added a document to it, and used the auto-id, then added a field named "humpty" with the string dumpty. It looks like this in the console:
I created a directory called signatures in the storage section of the firebase console. I want to write a file into this directory when my function (below) triggers.
I then added a cloud function with the following code. It shows up (I assume) correctly in the functions section, with the name testItOut and triggering on the event document.update for /blarg/{eventId}.:
const functions = require('firebase-functions');
const os = require('os');
const fs = require('fs');
const path = require('path');
require('firebase-admin').initializeApp();
exports.testItOut = functions.firestore
.document('blarg/{docId}')
.onUpdate((change, context) => {
console.log( "Inside #testItOut" );
const projectId = 'testing-60477';
const Storage = require('#google-cloud/storage');
const storage = new Storage({
projectId,
});
let bucketName = 'signatures';
let fileName = 'temp.txt';
const tempFilePath = path.join(os.tmpdir(), fileName);
console.log( `Writing out to ${tempFilePath}` );
fs.writeFileSync(tempFilePath, "something!" );
return storage
.bucket( bucketName )
.upload( tempFilePath )
.then( () => fs.unlinkSync(tempFilePath) )
.catch(err => console.error('ERROR inside upload: ', err) );
});
The package.json looks like this:
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"lint": "eslint .",
"serve": "firebase serve --only functions",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"dependencies": {
"#google-cloud/storage": "^1.7.0",
"firebase-admin": "~5.12.1",
"firebase-functions": "^1.0.3"
},
"devDependencies": {
"eslint": "^4.12.0",
"eslint-plugin-promise": "^3.6.0"
},
"private": true
}
If I change the value of the key "humpty" I see the function invocation. But, I get the error inside the logs.
ERROR inside upload: { ApiError: testing-60477#appspot.gserviceaccount.com does not have storage.objects.create access to signatures/temp.txt.
at Object.parseHttpRespBody (/user_code/node_modules/#google-cloud/storage/node_modules/#google-cloud/common/src/util.js:193:30)
at Object.handleResp (/user_code/node_modules/#google-cloud/storage/node_modules/#google-cloud/common/src/util.js:131:18)
...
This is as simple as it can get, I'd assume. What am I doing wrong? I thought calling initializeApp() gave my function rights to write to the storage bucket for the account automatically?
The only strange error I see is that billing is not setup. I thought this was necessary only if you use external APIs. Is Google Storage an "external API?" The log message does not indicate that's the issue.
The issue was that I mistakenly thought the call to bucket was to set the subdirectory inside the bucket. Instead of bucket('signatures') I should have made it an empty call like bucket() and then provided an options parameter (like { destination: '/signatures/temp.txt' }) for the upload call:
const functions = require('firebase-functions');
const os = require('os');
const fs = require('fs');
const path = require('path');
const admin = require('firebase-admin');
admin.initializeApp();
exports.testItOut = functions.firestore
.document('blarg/{docId}')
.onUpdate((change, context) => {
console.log( "Inside #testItOut" );
const storage = admin.storage()
let fileName = 'temp.txt';
let destination = '/signatures/temp.txt';
const tempFilePath = path.join(os.tmpdir(), fileName);
console.log( `Writing out to ${tempFilePath}` );
fs.writeFileSync(tempFilePath, "something!" );
return storage
.bucket()
.upload( tempFilePath, { destination } )
.then( () => fs.unlinkSync(tempFilePath) )
.catch(err => console.error('ERROR inside upload: ', err) );
});
I got confused because I saw lots of examples in firebase docs where there are calls to bucket("albums") (like this: https://cloud.google.com/nodejs/docs/reference/storage/1.6.x/Bucket#getFiles) and assumed this meant the bucket can be used to set a subdirectory for uploads. It's obvious to me now the difference, but I was thrown off because the calls to bucket did not look like bucketname-12345.appspot.com as I see in the firebase storage console.
Don't bother trying to use the Google Cloud Storage SDK like this:
const Storage = require('#google-cloud/storage');
const storage = new Storage({
projectId,
});
Instead, just use the Admin SDK after you initialize it. The Admin SDK wraps the Google Cloud Storage SDK. When you initialize admin, you are also implicitly initializing all of the components it wraps.
const admin = require('firebase-admin')
admin.initializeApp()
const storage = admin.storage()
// Now use storage just like you would use #google-cloud/storage
The default service account that's used when you init admin with no args like this should have write access to your project's default storage bucket.

Firebase app not accessing functions (e.g. firebase.auth())

I'm having this problem that I've spent hours looking into but can't seem to figure out. I'm trying to use Firebase with Node.js, but am unable to access the different Firebase functions (e.g. firebase.auth() and firebase.firestore()). However, when I initialize via the admin SDK, those end up working. Below is my simple code as well as the error:
const functions = require('firebase-functions');
const firebase = require('firebase');
const app = express();
firebase.initializeApp(functions.config().firebase);
const auth = firebase.auth();
const db = firebase.firestore();
And the resulting error: TypeError: firebase.auth is not a function
Note I also had a few lines initializing express and handlebars but doubt those would have had any impact.
I've also tried including "require("firebase/auth")" but that hasn't worked. Below is also my package.json, specifically the modules I have installed:
"dependencies": {
"consolidate": "^0.15.1",
"express": "^4.16.3",
"firebase": "^5.0.4",
"firebase-admin": "~5.12.1",
"firebase-functions": "^1.0.4",
"firebase-tools": "^3.18.6",
"firebaseauth": "^1.0.0",
"handlebars": "^4.0.11"
},
Any help please? I'm a bit of a novice web developer so any advice would be much appreciated. Thank you!
Cloud Functions triggers have a format like this:
exports.myFunctionName = functions.firestore
.document('users/marie').onWrite((change, context) => {
// ... Your code here
});
You cannot access the client-side SDKs from inside a Cloud Function. Instead, if there are features you want to access inside a Cloud Function, you can use the Admin SDKs.
var admin = require('firebase-admin');
var app = admin.initializeApp();
Short answer: Use the admin SDK, that's what it's for - Cloud Functions to interact with the rest of your backend.
Longer answer:
To help you along, here is an example of a working index.js file for a Firebase Cloud Function that accesses both the database (not firestore) and the auth portion of Firebase... with some comments to provide context. It's an API endpoint that accepts a user's token, verifies that the user is an 'admin' in my system, and then creates a new user account before responding with the new UID.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.createUser = functions.https.onRequest( (req, res) => {
// Look at the accessToken provided in the request, and have Firebase verify whether it's valid or not
admin.auth().verifyIdToken(req.body.accessToken).then(decodedIdToken => {
// Token was valid, pull the UID out of the token for the user making this request
let requestorUid = decodedIdToken.uid;
// Make a query to the database to see what that user's role is
admin.database().ref(`userBasicInfo/${requestorUid}/role`).once('value').then( dataSnapshot => {
if (dataSnapshot.val() === 'admin') {
// If their role is "admin" then let's create a user!
let userEmail = `${req.body.newuserid}#company.org`;
admin.auth().createUser({
email: userEmail,
password: req.body.password
}).then(userRecord => {
// See the UserRecord reference doc for the contents of userRecord.
res.send({uid: userRecord.uid});
}).catch( error => {
console.log("Error creating user:");
console.log(error)
res.send(false);
});
} else {
console.log('Checked the database for the UID provided in the access token, role was not "admin".');
res.send(false);
}
}).catch( err => {
console.log('Error finding user in database:');
console.log(err);
res.send(false);
})
}).catch( error => {
console.error('Error while verifying Firebase ID token:');
console.log(error);
res.send(false);
});
});
And the package.json would be:
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"serve": "firebase serve --only functions",
"shell": "firebase experimental:functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"dependencies": {
"firebase-admin": "^5.11.0",
"firebase-functions": "^1.0.2"
},
"private": true
}

Firebase database is not a function

I am trying to run isomorphic react app, using Firebase functions-samples.
But can't get the firebase database and I get the error "firebase.database is not a function"
const firebase = require('firebase')
// Load the Firebase database module.
require('firebase/database')
// Initialize Firebase using a client-side config.
const firebaseConfig = require('./client/firebase-config.json')
firebase.initializeApp(firebaseConfig)
const getDb = (ref) => firebase.database().ref(ref)
// Error firebase.database is not a function
Modules versions:
"firebase": "^4.13.0",
"firebase-admin": "~5.12.0",
"firebase-functions": "^1.0.2",
It works well with firebase-admin
const firebase = require('firebase-admin')
const firebaseConfig = require('./client/firebase-config.json')
firebase.initializeApp(firebaseConfig)
const getDb = (ref) => firebase.database().ref(ref)

Resources