I have a set of cli scripts that users inside our company use to maintain our application. The scripts run in node and use user logins (the client sdk) and not the admin sdk, so that users of the script don't have full access to the application. I previously had this working with node v12 and the firebase sdk version 7. For a bunch of reasons we have updated everything to run in node v18 and firebase version 9. The only snag I have is that I can't get firebase storage upload to work.
It seems uploadBytes() never completes.
The JS SDK says that node.js is supported for firebase storage. Here's a minimal example that shows the problem:
import fs from 'node:fs';
import { initializeApp } from 'firebase/app';
import { getAuth, signInWithEmailAndPassword, signOut } from 'firebase/auth';
import { getStorage, ref, uploadBytesResumable } from 'firebase/storage';
const firebaseConfig = (await import('./config.mjs')).default;
const userCredentials = JSON.parse(fs.readFileSync('./credentials.json').toString());
initializeApp(firebaseConfig);
(async () => {
const auth = getAuth();
const storage = getStorage();
let { user } = await signInWithEmailAndPassword(auth, userCredentials.email, userCredentials.password);
// valid path in storage rules
let storageRef = ref(storage, `users/${user.uid}/test.jpg`);
// invalid path in storage rules
// let storageRef = ref(storage, 'invalid');
// trying with different types of buffers, same result
const uploadTask = uploadBytesResumable(storageRef, fs.createReadStream('./test.jpg'));
// const uploadTask = uploadBytesResumable(storageRef, fs.readFileSync('./test.jpg'));
// const uploadTask = uploadBytesResumable(storageRef, Uint8Array.from(fs.readFileSync('./test.jpg')));
// I have tried with uploadBytes() but this doesn't have an on() method to capture events.
// Using uploadBytes() has the same result.
uploadTask.on('state_changed', x => console.log('progress:', x), console.error, console.log);
await uploadTask;
console.log('this is never printed');
await signOut(auth);
console.log('done');
})();
Interesting observations:
- It works just fine to download a file (see snippet below)
- I'm not seeing the allows and denies show up in the rules monitoring tool in the Firebase Console when I run this with a valid or invalid storage path, so it's as if the request is never made
- When I use
uploadBytesResumable()and pass in callback functions for progress, error, and complete, I get one immediate firing of the progress function with astate: "running"but nothing else ever fires. - I get the same behavior with various types of buffers and streams
- I get the same behavior with
uploadBytes()except that the returned promise doesn't seem to have the capability to add event handlers.
This code works for downloading the file in the body of the above function:
let stream = getStream(storageRef);
stream.pipe(fs.createWriteStream('./test-write.jpg'));
stream.on('end', console.log);
I'm using firebase@9.9.4 installed by npm and nodejs 18.1.