title: Piping/streaming file from memory to bucket in Firebase/GCS
body: <p>I'm trying to generate multiple documents and pack them together to a zip and upload it to Google Cloud Storage via Firebase (using default bucket).</p>
  <p>So far:</p>
  <ul>
  <li>generating multiple documents <strong>works</strong></li>
  <li>packing them together <strong>doesn't work</strong> (I get empty zip and I'm using <a href="https://www.archiverjs.com/" rel="nofollow noreferrer">ArchiverJS</a>)</li>
  <li>uploading to the bucket (it's just empty) <strong>works</strong></li>
  </ul>
  <p>Seems like to upload a file I need to save it to temporary folder within Firebase Function, but I can't find any solution how to empty it after using. So I wanted to use streams, but then I was warned that it's a bad idea because checksum and such.</p>
  <p>On the other hand <a href="https://googleapis.dev/nodejs/storage/latest/File.html#save" rel="nofollow noreferrer"><code>.save()</code> function</a> let's save arbitrary data. It was specifically requested <a href="https://github.com/googleapis/google-cloud-node/issues/1179#issuecomment-199801543" rel="nofollow noreferrer">here</a>, but really doesn't seem to work (at least for me).</p>
  <p>Also, ArchiverJS seems to also <a href="https://github.com/archiverjs/node-archiver/issues/216" rel="nofollow noreferrer">let use of streams</a>.</p>
  <p>So, theoretically, it should all work nicely. But it's not so I hope someone else knows better.</p>
  <pre><code>const express = require('express')
  var router = express.Router()
  var archiver = require('archiver')
  var admin = require(&quot;firebase-admin&quot;);
  var serviceAccount = require(&quot;../servicekey.json&quot;)
  admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: &quot;https://myName.firebaseio.com&quot;,
    storageBucket: &quot;myName.appspot.com&quot;
  })
  var bucket = admin.storage().bucket()
  
  const {
    convertCSVtoJSON,
    generateDocuments,
    generateDocx,
    isCorrectTemplateFileType
  } = require('./generateServices')
  
  router.post('/', async (req, res) =&gt; {
    try {
      if(!isCorrectTemplateFileType(req.files.template))
        return res.status(403).send({
          message: 'Wrong file type. Please provide .docx file.'
        })
  
      const template = req.files.template.data
      const data = await convertCSVtoJSON(req.files.data1)
  
      let zip = archiver('zip')
      
      zip.on('warning', function(err) {
        console.log(err)
      });
  
      zip.on('error', function(err) {
        res.status(500).send({error: err.message})
      });
  
      zip.on('entry', function(ars) {
        // console.log(ars)
      });
  
      zip.on('end', function() {
        console.log('Archive wrote %d bytes', zip.pointer())
      });
  
      // res.attachment('archive-name.zip')
    
      // zip.pipe(output)
      // zip.pipe(res)
      
      data.forEach((docData, index) =&gt; {
        let buff = generateDocx(template, docData, 'title')
        zip.append(buff, { name: `${index}.docx` })
      })
  
      zip.finalize()
  
      console.log(zip)
      const file = bucket.file(&quot;pliki.zip&quot;) // nazwa do zmiany
      file.save(zip, (err) =&gt; {
        if (!err) {
          console.log(&quot;cool&quot;);
        } else {
          console.log(&quot;error &quot; + err);
        }
      });
  
      res.sendStatus(201)
    } catch (error) {
      console.log(error)
      res.send(error)
    }
  })
  
  module.exports = router
  </code></pre>