From bd3079c8971a9c76945c835c8c7fee1be27985b4 Mon Sep 17 00:00:00 2001 From: Anthony Barone Date: Wed, 4 Feb 2026 19:53:08 +0000 Subject: [PATCH] Add resource name and `allow_missing` param to source map registration --- npm-shrinkwrap.json | 13 ++++++++++ package.json | 1 + .../crashlytics-sourcemap-upload.spec.ts | 6 +++-- src/commands/crashlytics-sourcemap-upload.ts | 26 ++++++++++++------- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 5658875909d..69254e63b53 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -56,6 +56,7 @@ "mime": "^2.5.2", "minimatch": "^3.0.4", "morgan": "^1.10.0", + "murmurhash-es": "^0.1.1", "node-fetch": "^2.6.7", "open": "^6.3.0", "ora": "^5.4.1", @@ -15656,6 +15657,13 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "node_modules/murmurhash-es": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/murmurhash-es/-/murmurhash-es-0.1.1.tgz", + "integrity": "sha512-IfA8KVe9dxv28F9KSJ8EpJP2jgO1br6xInnFaPDjQKosEfpTMAx8v1eGCUzOvcZDstadm3mdP95JILrYs0mNsg==", + "deprecated": "Please switch to https://github.com/unjs/ohash", + "license": "MIT" + }, "node_modules/mute-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", @@ -33636,6 +33644,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "murmurhash-es": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/murmurhash-es/-/murmurhash-es-0.1.1.tgz", + "integrity": "sha512-IfA8KVe9dxv28F9KSJ8EpJP2jgO1br6xInnFaPDjQKosEfpTMAx8v1eGCUzOvcZDstadm3mdP95JILrYs0mNsg==" + }, "mute-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", diff --git a/package.json b/package.json index 2e8d2df9a68..8de20ea30be 100644 --- a/package.json +++ b/package.json @@ -151,6 +151,7 @@ "mime": "^2.5.2", "minimatch": "^3.0.4", "morgan": "^1.10.0", + "murmurhash-es": "^0.1.1", "node-fetch": "^2.6.7", "open": "^6.3.0", "ora": "^5.4.1", diff --git a/src/commands/crashlytics-sourcemap-upload.spec.ts b/src/commands/crashlytics-sourcemap-upload.spec.ts index a67bd80ef79..bf4bb186a59 100644 --- a/src/commands/crashlytics-sourcemap-upload.spec.ts +++ b/src/commands/crashlytics-sourcemap-upload.spec.ts @@ -195,13 +195,15 @@ describe("crashlytics:sourcemap:upload", () => { expect(clientPostStub).to.be.calledOnce; const args = clientPostStub.firstCall.args; expect(args[0]).to.match( - /\/projects\/test-project\/apps\/test-app\/locations\/global\/sourceMaps/, + /projects\/test-project\/apps\/test-app\/locations\/global\/sourceMaps/, ); expect(args[1].sourceMap).to.deep.equal({ + name: "projects/test-project/apps/test-app/locations/global/sourceMaps/759213742", version: "a".repeat(40), - obfuscatedFilePath: "src-test-fixtures-mapping-files-mock_mapping.js.map", + obfuscatedFilePath: "src/test/fixtures/mapping-files/mock_mapping.js.map", fileUri: `gs://${BUCKET_NAME}/test-object`, }); + expect(args[2].queryParams).to.deep.equal({ allowMissing: "true" }); }); it("should warn if registration fails", async () => { diff --git a/src/commands/crashlytics-sourcemap-upload.ts b/src/commands/crashlytics-sourcemap-upload.ts index 0eb350cca57..84b00ad980f 100644 --- a/src/commands/crashlytics-sourcemap-upload.ts +++ b/src/commands/crashlytics-sourcemap-upload.ts @@ -13,6 +13,7 @@ import { Options } from "../options"; import { archiveFile } from "../archiveFile"; import { execSync } from "node:child_process"; import { Client } from "../apiv2"; +import { murmurHashV3 } from "murmurhash-es"; interface CommandOptions extends Options { app?: string; @@ -22,6 +23,7 @@ interface CommandOptions extends Options { } interface SourceMap { + name: string; version: string; obfuscatedFilePath: string; fileUri: string; @@ -187,7 +189,10 @@ async function uploadMap( try { const filePath = path.relative(options.projectRoot ?? process.cwd(), mappingFile); const tmpArchive = await archiveFile(filePath, { archivedFileName: "mapping.js.map" }); - const gcsFile = `${options.app}-${appVersion}-${normalizeFileName(mappingFile)}.zip`; + const gcsFile = `${options.app}-${appVersion}-${normalizeFileName(filePath)}.zip`; + const uid = murmurHashV3(`${appVersion}-${filePath}`); + const parent = `projects/${projectId}/apps/${options.app}/locations/global/sourceMaps`; + const name = `${parent}/${uid}`; const { bucket, object } = await gcs.uploadObject( { @@ -200,11 +205,11 @@ async function uploadMap( logger.debug(`Uploaded mapping file ${mappingFile} to ${fileUri}`); await registerSourceMap( - projectId, - options.app!, + parent, { + name, version: appVersion, - obfuscatedFilePath: normalizeFileName(mappingFile), + obfuscatedFilePath: filePath, fileUri, }, options.telemetryServerUrl!, @@ -222,8 +227,7 @@ function normalizeFileName(fileName: string): string { } async function registerSourceMap( - projectId: string, - appId: string, + parent: string, sourceMap: SourceMap, telemetryServerUrl: string, ): Promise { @@ -234,9 +238,13 @@ async function registerSourceMap( }); try { - await client.post(`/projects/${projectId}/apps/${appId}/locations/global/sourceMaps`, { - sourceMap, - }); + await client.post( + parent, + { + sourceMap, + }, + { queryParams: { allowMissing: "true" } }, + ); logger.debug( `Registered source map ${sourceMap.obfuscatedFilePath} with Firebase Telemetry service`, );