Skip to content

Instantly share code, notes, and snippets.

@mbleigh
Last active April 29, 2026 08:37
Show Gist options
  • Select an option

  • Save mbleigh/9c8680cf319ace2f506f57380da66e7d to your computer and use it in GitHub Desktop.

Select an option

Save mbleigh/9c8680cf319ace2f506f57380da66e7d to your computer and use it in GitHub Desktop.

Revisions

  1. mbleigh revised this gist Nov 6, 2019. No changes.
  2. mbleigh revised this gist Nov 6, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion fetchFiles.js
    Original file line number Diff line number Diff line change
    @@ -74,7 +74,7 @@ const MAX_FETCHES = 100;

    fetch();
    } catch (e) {
    console.error("ERROR:", e.message);
    console.error("ERROR:", e.stack);
    process.exit(1);
    }
    })();
  3. mbleigh revised this gist Oct 4, 2019. 1 changed file with 34 additions and 29 deletions.
    63 changes: 34 additions & 29 deletions fetchFiles.js
    Original file line number Diff line number Diff line change
    @@ -40,36 +40,41 @@ async function listFiles(versionName, existing = [], pageToken = null) {
    const MAX_FETCHES = 100;

    (async function() {
    await requireAuth({}, ['https://www.googleapis.com/auth/cloud-platform']);
    const v = await getLatestVersionName();
    const vid = v.split('/')[v.split('/').length - 1];
    const toFetch = await listFiles(v);
    const dirName = `${site}_${vid}`;
    let fetchesOutstanding = 0;
    let fetchCount = 0;
    function fetch() {
    if (fetchesOutstanding >= MAX_FETCHES) {
    return;
    } else if (toFetch.length === 0) {
    console.log();
    console.log("Complete. Fetched", fetchCount, "files.");
    return;
    try {
    await requireAuth({}, ['https://www.googleapis.com/auth/cloud-platform']);
    const v = await getLatestVersionName();
    const vid = v.split('/')[v.split('/').length - 1];
    const toFetch = await listFiles(v);
    const dirName = `${site}_${vid}`;
    let fetchesOutstanding = 0;
    let fetchCount = 0;
    function fetch() {
    if (fetchesOutstanding >= MAX_FETCHES) {
    return;
    } else if (toFetch.length === 0) {
    console.log();
    console.log("Complete. Fetched", fetchCount, "files.");
    return;
    }

    const f = toFetch.shift();
    console.log('Fetching', f);
    fetchesOutstanding++;
    fetchCount++;
    fs.ensureFileSync(dirName + f);
    const q = request(`https://${site}.firebaseapp.com${f}`)
    const ws = fs.createWriteStream(dirName + f);
    q.pipe(ws);
    ws.on('finish', () => {
    console.log('Fetched ', f);
    fetchesOutstanding--;
    fetch();
    });
    }

    const f = toFetch.shift();
    console.log('Fetching', f);
    fetchesOutstanding++;
    fetchCount++;
    fs.ensureFileSync(dirName + f);
    const q = request(`https://${site}.firebaseapp.com${f}`)
    const ws = fs.createWriteStream(dirName + f);
    q.pipe(ws);
    ws.on('finish', () => {
    console.log('Fetched ', f);
    fetchesOutstanding--;
    fetch();
    });
    fetch();
    } catch (e) {
    console.error("ERROR:", e.message);
    process.exit(1);
    }

    fetch();
    })();
  4. mbleigh revised this gist Oct 4, 2019. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,6 @@
    {
    "name": "firebase-hosting-fetch-version",
    "version": "0.1.0",
    "bin": "./fetchFiles.js",
    "dependencies": {
    "firebase-tools": "^7.4.0",
  5. mbleigh revised this gist Oct 4, 2019. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -6,6 +6,8 @@ to be able to properly run the script.

    ## Running via NPX

    npx https://gist.github.com/mbleigh/TODO <site_name>
    npx https://gist.github.com/mbleigh/9c8680cf319ace2f506f57380da66e7d <site_name>

    Where `<site_name>` is your Firebase Hosting site (e.g. `my-site` from `my-site.firebaseapp.com`).
    Where `<site_name>` is your Firebase Hosting site (e.g. `my-site` from `my-site.firebaseapp.com`).
    The files will be downloaded into a folder `<site_name>_<version_id>` where the version ID is the
    current version of your site.
  6. mbleigh created this gist Oct 4, 2019.
    11 changes: 11 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    # Fetch All Files from Firebase Hosting

    This script fetches all of the files from the currently deployed version of a Firebase Hosting site.
    You must be signed in via the Firebase CLI and have "Site Viewer" permission on the site in question
    to be able to properly run the script.

    ## Running via NPX

    npx https://gist.github.com/mbleigh/TODO <site_name>

    Where `<site_name>` is your Firebase Hosting site (e.g. `my-site` from `my-site.firebaseapp.com`).
    75 changes: 75 additions & 0 deletions fetchFiles.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,75 @@
    #!/usr/bin/env node

    const requireAuth = require('firebase-tools/lib/requireAuth');
    const api = require('firebase-tools/lib/api');
    const fs = require('fs-extra');
    const request = require('request');

    if (!process.argv[2]) {
    console.error(`
    ERROR: Must supply a site name. Usage:
    node fetchFiles.js <site_name>`);
    process.exit(1);
    }

    const site = process.argv[2];

    async function getLatestVersionName() {
    const result = await api.request('GET', `/v1beta1/sites/${site}/releases?pageSize=1`, {
    auth: true,
    origin: api.hostingApiOrigin,
    });
    const release = (result.body.releases || [])[0];
    if (release) {
    return release.version.name;
    }
    return null;
    }

    const LIST_PAGE_SIZE = 1000;
    async function listFiles(versionName, existing = [], pageToken = null) {
    const result = await api.request('GET', `/v1beta1/${versionName}/files?pageSize=${LIST_PAGE_SIZE}${pageToken ? `&pageToken=${pageToken}` : ''}`, {auth: true, origin: api.hostingApiOrigin});
    result.body.files.forEach(file => existing.push(file.path));
    if (result.body.nextPageToken) {
    return await listFiles(versionName, existing, result.body.nextPageToken);
    }
    return existing;
    }

    const MAX_FETCHES = 100;

    (async function() {
    await requireAuth({}, ['https://www.googleapis.com/auth/cloud-platform']);
    const v = await getLatestVersionName();
    const vid = v.split('/')[v.split('/').length - 1];
    const toFetch = await listFiles(v);
    const dirName = `${site}_${vid}`;
    let fetchesOutstanding = 0;
    let fetchCount = 0;
    function fetch() {
    if (fetchesOutstanding >= MAX_FETCHES) {
    return;
    } else if (toFetch.length === 0) {
    console.log();
    console.log("Complete. Fetched", fetchCount, "files.");
    return;
    }

    const f = toFetch.shift();
    console.log('Fetching', f);
    fetchesOutstanding++;
    fetchCount++;
    fs.ensureFileSync(dirName + f);
    const q = request(`https://${site}.firebaseapp.com${f}`)
    const ws = fs.createWriteStream(dirName + f);
    q.pipe(ws);
    ws.on('finish', () => {
    console.log('Fetched ', f);
    fetchesOutstanding--;
    fetch();
    });
    }

    fetch();
    })();
    9 changes: 9 additions & 0 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    {
    "name": "firebase-hosting-fetch-version",
    "bin": "./fetchFiles.js",
    "dependencies": {
    "firebase-tools": "^7.4.0",
    "fs-extra": "^8.1.0",
    "request": "^2.88.0"
    }
    }