From 8e8036a878b5202569391db20df7b69975ff1cb7 Mon Sep 17 00:00:00 2001 From: Joanna Wang Date: Wed, 26 Nov 2025 22:52:19 +0000 Subject: [PATCH 1/2] Allow TAR uploads to storage. --- src/gcp/storage.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/gcp/storage.ts b/src/gcp/storage.ts index 3e7bd825988..8a576ceea6d 100644 --- a/src/gcp/storage.ts +++ b/src/gcp/storage.ts @@ -11,6 +11,12 @@ import { ensure } from "../ensureApiEnabled"; import * as utils from "../utils"; import { fieldMasks } from "./proto"; +/** Content Type **/ +export enum ContentType { + ZIP = "ZIP", + TAR = "TAR", +} + /** Bucket Interface */ interface BucketResponse { kind: string; @@ -252,6 +258,7 @@ export async function upload( }; } + /** * Uploads a zip file to the specified bucket using the firebasestorage api. */ @@ -260,21 +267,27 @@ export async function uploadObject( source: { file: string; stream: Readable }, /** Bucket to upload to. */ bucketName: string, + contentType?: ContentType, ): Promise<{ bucket: string; object: string; generation: string | null; }> { - if (path.extname(source.file) !== ".zip") { + if (contentType == ContentType.TAR) { + if (path.extname(source.file) !== ".tar.gz") { + throw new FirebaseError(`Expected a file name ending in .tar.gz, got ${source.file}`); + } + } else if (path.extname(source.file) !== ".zip") { throw new FirebaseError(`Expected a file name ending in .zip, got ${source.file}`); } + const localAPIClient = new Client({ urlPrefix: storageOrigin() }); const location = `/${bucketName}/${path.basename(source.file)}`; const res = await localAPIClient.request({ method: "PUT", path: location, headers: { - "Content-Type": "application/zip", + "Content-Type": contentType == ContentType.TAR ? "application/octet-stream" : "application/zip", "x-goog-content-length-range": "0,123289600", }, body: source.stream, From 7d3c1be852a91bf59edbf8e69e6588f47af15c1f Mon Sep 17 00:00:00 2001 From: Joanna Wang Date: Wed, 26 Nov 2025 23:00:22 +0000 Subject: [PATCH 2/2] clean --- src/gcp/storage.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/gcp/storage.ts b/src/gcp/storage.ts index 8a576ceea6d..87754b807b2 100644 --- a/src/gcp/storage.ts +++ b/src/gcp/storage.ts @@ -258,9 +258,8 @@ export async function upload( }; } - /** - * Uploads a zip file to the specified bucket using the firebasestorage api. + * Uploads a zip or tar file to the specified bucket using the firebasestorage api. */ export async function uploadObject( /** Source with file (name) to upload, and stream of file. */ @@ -273,12 +272,16 @@ export async function uploadObject( object: string; generation: string | null; }> { - if (contentType == ContentType.TAR) { - if (path.extname(source.file) !== ".tar.gz") { - throw new FirebaseError(`Expected a file name ending in .tar.gz, got ${source.file}`); - } - } else if (path.extname(source.file) !== ".zip") { - throw new FirebaseError(`Expected a file name ending in .zip, got ${source.file}`); + switch (contentType) { + case ContentType.TAR: + if (!source.file.endsWith(".tar.gz")) { + throw new FirebaseError(`Expected a file name ending in .tar.gz, got ${source.file}`); + } + break; + default: + if (path.extname(source.file) !== ".zip") { + throw new FirebaseError(`Expected a file name ending in .zip, got ${source.file}`); + } } const localAPIClient = new Client({ urlPrefix: storageOrigin() }); @@ -287,7 +290,8 @@ export async function uploadObject( method: "PUT", path: location, headers: { - "Content-Type": contentType == ContentType.TAR ? "application/octet-stream" : "application/zip", + "Content-Type": + contentType === ContentType.TAR ? "application/octet-stream" : "application/zip", "x-goog-content-length-range": "0,123289600", }, body: source.stream,