deploying cloud functions on firebase - firebase

I need to deploy a cloud function on firebase to set admin role:
this is my code:
typescript
"use strict";
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
admin.initializeApp();
exports.adAddminRole = functions.https.onCall((data) => {
return admin.auth().getUserByEmail(data.email).then((user) => {
return admin.auth().setCustomUserClaims(user.uid, {
admin: true,
}).then(() => {
return {
message: ` Success! ${data.email} as been made an admin`,
};
}).catch((err) => {
return err;
});
});
});
when I do firebase deploy --only functions, I get a lot of error messages:
../node_modules/#types/google.maps/index.d.ts:19:1 - error
TS6200: Definitions of the following identifiers conflict with
those in another file: DEFAULT, HORIZONTAL_BAR, DROPDOWN_MENU,
BOTTOM_CENTER, BOTTOM_LEFT, BOTTOM_RIGHT, LEFT_BOTTOM,
LEFT_CENTER, LEFT_TOP, RIGHT_BOTTOM, RIGHT_CENTER, RIGHT_TOP,
TOP_CENTER, TOP_LEFT, TOP_RIGHT
19 declare namespace google.maps {
~~~~~~~
../node_modules/#types/googlemaps/reference/control.d.ts:1:1
1 declare namespace google.maps {
~~~~~~~
Conflicts are in this file.
it looks to me that they are not related directly to the cloud
function's code, I do not understand what is wrong

Related

Firebase functions deploy failed: illegal operation on a directory, read [duplicate]

I'm trying to download an image from an url and then uploading it to my firebase cloud storage.
This is the code i'm using.
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
const download = require('image-downloader');
const tmp = require('tmp');
export const downloadFunction = functions.https.onCall(async (data, context) => {
var bucket = admin.storage().bucket();
await tmp.dir(async function _tempDirCreated(err: any, path: any) {
if (err) throw err;
const options = {
url: 'theUrlIWantToPutInTheStorage',
dest: path,
}
console.log('Dir: ', path);
await download.image(options)
.then(async () => {
console.log('Saved');
await bucket.upload(path, {
destination: "testfolder/test.jpg",
metadata: "metadata",
});
})
.catch((err2: any) => console.error(err2))
});
});
But from the firebase console (logs) I get this error:
{ Error: EISDIR: illegal operation on a directory, read errno: -21, code: 'EISDIR', syscall: 'read' }
What am I doing wrong?
Thanks in advance!
The path that you provide to the method upload should be a file and not a directory.
upload(pathString, optionsopt, callbackopt) → {Promise.<UploadResponse>}
Upload a file to the bucket. This is a convenience method that wraps File#createWriteStream.
Example :
const options = {
destination: 'new-image.png',
resumable: true,
validation: 'crc32c',
metadata: {
metadata: {
event: 'Fall trip to the zoo'
}
}
};
bucket.upload('local-image.png', options, function(err, file) {
// Your bucket now contains:
// - "new-image.png" (with the contents of `local-image.png')
// `file` is an instance of a File object that refers to your new file.
});
https://googleapis.dev/nodejs/storage/latest/Bucket.html

Cannot find module 'firebase-functions/lib/encoder' from 'node_modules/firebase-functions-test/lib/providers/firestore.js'

Hey I am trying to unit test this cloud function right here:
import { logger, region, https } from "firebase-functions/v1";
import Message from "../types/message";
const helloWorldHandler = region("europe-west1").https.onCall((_, context) => {
if (context.app == undefined) {
throw new https.HttpsError("failed-precondition", "The function must be called from an App Check verified app.");
}
logger.info("Hello logs!", { structuredData: true });
const message: Message = {
text: "Hello from Firebase!",
code: 200,
};
return message;
});
export default helloWorldHandler;
with the following test:
import * as functions from "firebase-functions-test";
import * as path from "path";
const projectConfig = {
projectId: "myproject-id",
};
const testEnv = functions(projectConfig, path.resolve("./flowus-app-dev-fb-admin-sdk-key"));
// has to be after initializing functions
import helloWorldHandler from "../src/functions/helloworld";
import Message from "../src/types/message";
describe('Testing "helloWorld"', () => {
const helloWorld = testEnv.wrap(helloWorldHandler);
it("helloWorld does work", async () => {
const data = {};
const success: Message = await helloWorld(data);
expect(success.code).toBe(200);
});
});
When I run it with yarn test I receive the following error
Cannot find module 'firebase-functions/lib/encoder' from 'node_modules/firebase-functions-test/lib/providers/firestore.js'
Even though my function does not even use firestore in the first place?
Any ideas ?
I was facing a similar issue while trying to set up a unit testing environment for firebase cloud functions.
Mainly, after following all the steps on Firebase's docs, and running npm test
I would get the following error
Error [ERR_PACKAGE_PATH_NOT_EXPORTED] Package subpath './lib/encoder'
is not defined by "exports"
After stumbling on Farid's suggestion for this problem, I realized that, for some reason, npm i firebase-functions-test does not install the latest version of the module.
Try npm i firebase-functions-test#latest.

Firebase Cloud Function unit test HTTP onCall

I would like to write some unit tests for a bunch of cloud functions. Now I'm facing the following issue. Using the firebase-functions-test I'm somehow not able to test HTTP triggered cloud functions. Here are some of my cloud functions that i'd like to test using jest:
export cloudFunctions = {
createUserByAdmin: functions.runWith({ timeoutSeconds: 30, memory: '256MB' }).https.onCall(UserService.createUserByAdmin),
updateUserByAdmin: functions.runWith({ timeoutSeconds: 30, memory: '256MB' }).https.onCall(UserService.updateUserByAdmin),
deleteUserByAdmin: functions.runWith({ timeoutSeconds: 30, memory: '256MB' }).https.onCall(UserService.deleteUserByAdmin)
}
They are all deployed on Firebase and they work without problems. But I couldn't find a way to call the using the firebase-functions-test package. Also, there are a few examples of how to write unit tests using that package but none of them test http triggered functions.
This is my test file:
import * as functions from 'firebase-functions-test'
import * as admin from 'firebase-admin'
import * as path from 'path'
const projectConfig = {
projectId: 'test-fb',
}
const testEnv = functions(
projectConfig,
path.resolve('DO-NOT-EDIT.dev.fb-admin-sdk-key.json'),
)
describe('[Cloud Functions] User Service', () => {
let cloudFunctions
beforeAll(() => {
cloudFunctions = require('../index')
})
afterAll(() => {
// delete made accounts/entrys
})
describe('Testing "createUserByAdmin"', () => {
it('Creating User does work', () => {
expect(1).toBe(0)
})
})
})
Does someone know how to test http cloud functions? I would really appreciate an example.
Thanks!
I actually found a way on how to test HTTP Cloud Functions using firebase-functions-test it all works with a wrapper function. Take a look at this reference page. Here is some code to make things a bit more clear.
this is a snippet from one of my tests
import * as functions from 'firebase-functions-test'
import * as admin from 'firebase-admin'
import * as path from 'path'
const projectConfig = {
projectId: 'myproject-id',
}
const testEnv = functions(
projectConfig,
path.resolve('fb-admin-sdk-key.json'),
)
// has to be after initializing functions
import * as cloudFunctions from '../index'
describe('Testing "createUserByAdmin"', () => {
const createUserByAdmin = testEnv.wrap(cloudFunctions.createUserByAdmin)
it('Creating User does work', async (done) => {
const data = {
displayName: 'Jest Unit Test',
email: 'unit#domain.com',
password: 'password',
uid: null,
}
const context = {
auth: {
token: {
access: 'somestring,
},
uid: 'mockuiddddd',
},
}
await createUserByAdmin(data, context)
.then(async (createdUser: any) => {
expect(createdUser.status).toBe('OK')
done()
})
.catch((error: any) => {
fail('createUserByAdmin failed with the following ' + error)
})
})
})
You'll see that after initializing our test environment using our projectConfig and our service account key file.
const testEnv = functions(
projectConfig,
path.resolve('fb-admin-sdk-key.json'),
)
you'll just have to wrap the appropriate cloud function with the .wrap() function.
const createUserByAdmin = testEnv.wrap(cloudFunctions.createUserByAdmin)
And you can call it like every other function (keep in mind that cloud functions usually expect a data parameter (with the variables you use in your cloud function) as well as a context parameter, depending on how you handle authentication/authorization you'll have to try and error to find the right context properties your function requests.
if your writing tests for your production cloud functions make sure to clean up after running tests - such as deleting created accounts or deleting data in either firestore or realtime-database

GatsbyJS with Firebase - WebpackError: ReferenceError: IDBIndex is not defined

I'm received error with gatsby develop. It's very similar to this one: https://github.com/firebase/firebase-js-sdk/issues/2222, but I'm received error with gatsby develop, not with gatsby build. I did a lot of research but I can't find working solution.
At first I had a problem with gatsby build, like in this post: https://github.com/firebase/firebase-js-sdk/issues/2222, but I resolved it with custom onCreateWebpackConfig(you can find it below).
Stack:
- Gatsby
- Firebase(error probably with that)
- Redux
I'm also delete .cache and node_modules and install everything again, but it didn't work.
Error:
There was an error compiling the html.js component for the development server.
See our docs page on debugging HTML builds for help https://gatsby.dev/debug-html ReferenceError: IDBIndex is not defined
]);
86 |
> 87 | proxyRequestMethods(Index, '_index', IDBIndex, [
| ^
88 | 'get',
89 | 'getKey',
90 | 'getAll',
WebpackError: ReferenceError: IDBIndex is not defined
- idb.mjs:87 Module../node_modules/idb/lib/idb.mjs
node_modules/idb/lib/idb.mjs:87:1
- index.esm.js:1 Module../node_modules/#firebase/installations/dist/index.esm.js
node_modules/#firebase/installations/dist/index.esm.js:1:1
- index.esm.js:1 Module../node_modules/#firebase/analytics/dist/index.esm.js
node_modules/#firebase/analytics/dist/index.esm.js:1:1
- index.esm.js:1 Module../node_modules/firebase/analytics/dist/index.esm.js
node_modules/firebase/analytics/dist/index.esm.js:1:1
- index.ts:1 Module../src/firebase/index.ts
src/firebase/index.ts:1:1
- index.esm.js:32 emit
node_modules/#firebase/analytics/dist/index.esm.js:32:1
My gatsby-node file:
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
if (stage === 'build-html') {
actions.setWebpackConfig({
externals: getConfig().externals.concat(function(context, request, callback) {
const regex = /^#?firebase(\/(.+))?/;
if (regex.test(request)) {
return callback(null, `umd ${request}`);
}
callback();
}),
});
}
};
My firebase dependencies:
"#firebase/firestore-types": "^1.10.1",
"firebase": "^7.13.1",
"firebase-admin": "^8.10.0",
"firebase-functions": "^3.5.0",
"firebase-tools": "^7.16.1",
Firebase index file:
import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';
import 'firebase/storage';
import 'firebase/analytics';
const firebaseConfig = {...};
firebase.initializeApp(firebaseConfig);
export const firestore = firebase.firestore();
export const auth = firebase.auth();
export const storage = firebase.storage();
Project repo: https://github.com/olafsulich/Projecty
Post on Github issues: https://github.com/firebase/firebase-js-sdk/issues/2946
Thanks in advance.
The following snippet will only work on build environment because of your condition (stage === 'build-html'):
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
if (stage === 'build-html') {
actions.setWebpackConfig({
externals: getConfig().externals.concat(function(context, request, callback) {
const regex = /^#?firebase(\/(.+))?/;
if (regex.test(request)) {
return callback(null, `umd ${request}`);
}
callback();
}),
});
}
};
Remove it and use it like this:
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
actions.setWebpackConfig({
externals: getConfig().externals.concat(function(context, request, callback) {
const regex = /^#?firebase(\/(.+))?/;
if (regex.test(request)) {
return callback(null, `umd ${request}`);
}
callback();
}),
});
};
Thank's a lot! It's working only on gatbsy develop, but now when I
want to build project, I get an error - TypeError: Cannot read
property 'concat' of undefined. You know how to solve it?
Regarding the new issue, you can follow a workaround in this topic, This is a common error in third-party modules in Gatsby when they try to reach a DOM element (usually window) that is not already defined when the app builds. So, you need to wait until window is defined. You can achieve this in two ways:
Instancing your firebase with a condition like this:
import firebase from '#firebase/app';
import '#firebase/auth';
import '#firebase/firestore';
import '#firebase/functions';
const config = {
... firebase config here
};
let instance;
export default function getFirebase() {
if (typeof window !== 'undefined') {
if (instance) return instance;
instance = firebase.initializeApp(config);
return instance;
}
return null;
}
Note the if (typeof window !== 'undefined') statement
By ignoring firebase module in you webpack configuration like shows their docs. In your gatsby-node.js:
exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
if (stage === "build-html") {
actions.setWebpackConfig({
module: {
rules: [
{
test: /bad-module/,
use: loaders.null(),
},
],
},
})
}
}
Replace bad module for firebase (or the package/folder name in node_modules). Leave the slashes since test is a regular expression rule
This snippet replaces your previous one that seems to throw an error in concat() function.
For those who wants to try the concat() resolution, this will be helpful too:
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
if (stage === 'build-html') {
actions.setWebpackConfig({
externals: getConfig().externals.concat((context, request, callback) => {
const regex = /^#?firebase(\/(.+))?/
// exclude firebase products from being bundled, so they will be loaded using require() at runtime.
if (regex.test(request)) {
return callback(null, `commonjs ${request}`) // <- use commonjs!
}
callback()
}),
})
}
}
Solved this problem!!
I'm using "gatsby": "^3.10.2", "firebase": "9.0.0-beta.6".
firebase needs to be set externals as commonjs.
gatsby-node.js:
exports.onCreateWebpackConfig = ({ stage, actions, getConfig }) => {
if (stage === 'build-html') {
actions.setWebpackConfig({
externals: getConfig().externals.concat((context, request, callback) => {
const regex = /^#?firebase(\/(.+))?/
// exclude firebase products from being bundled, so they will be loaded using require() at runtime.
if (regex.test(request)) {
return callback(null, `commonjs ${request}`) // <- use commonjs!
}
callback()
}),
})
}
}
Please try this setting.

Error when using Firebase Auth on a cloud function with Zeit Now

I'm using Nextjs and deploying it with Zeit now.
I'm trying to implement session management using Firebase auth and what I'm trying to do is to set cookies on the user's request. I have the following function:
import { NextApiRequest, NextApiResponse } from 'next';
// Initializing firebase admin
import admin from '../../helpers/firebase/init';
const db = admin.firestore();
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
try {
// ...
const sessionCookieRxpiresIn = 60 * 60 * 24 * 5 * 1000;
const sessionCookie = await admin
.auth()
.createSessionCookie(idToken, { expiresIn: sessionCookieRxpiresIn });
res.setHeader(
'Set-Cookie',
`session=${sessionCookie};Max-Age=${sessionCookieRxpiresIn};HttpOnly;Path=/`,
);
res.status(200).json({
success: true,
});
} catch (error) {
// ...
}
};
export default handler;
This function works just fine locally with now dev, but when I'm deploying it to now, I see the following error after invoking this function ENOENT: no such file or directory, open 'google/protobuf/api.proto'.
I didn't find any valuable advice on the internet to help me deal with this issue. Any advice?

Resources