Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Refactor common parsing logic
  • Loading branch information
raymondlam committed Aug 22, 2025
commit 7b3ddd609b7bce9ecbd6d6ce1d7218fa914dd686
15 changes: 2 additions & 13 deletions src/crashlytics/addNote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Client } from "../apiv2";
import { logger } from "../logger";
import { FirebaseError } from "../error";
import { crashlyticsApiOrigin } from "../api";
import { parseProjectNumber } from "./utils";

const TIMEOUT = 10000;

Expand All @@ -15,12 +16,8 @@ type NoteRequest = {
};

export async function addNote(appId: string, issueId: string, note: string): Promise<string> {
const requestProjectId = parseProjectNumber(appId);
try {
const requestProjectId = parseProjectId(appId);
if (requestProjectId === undefined) {
throw new FirebaseError("Unable to get the projectId from the AppId.");
}

const response = await apiClient.request<NoteRequest, string>({
method: "POST",
headers: {
Expand All @@ -40,11 +37,3 @@ export async function addNote(appId: string, issueId: string, note: string): Pro
);
}
}

function parseProjectId(appId: string): string | undefined {
const appIdParts = appId.split(":");
if (appIdParts.length > 1) {
return appIdParts[1];
}
return undefined;
}
15 changes: 2 additions & 13 deletions src/crashlytics/deleteNote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Client } from "../apiv2";
import { logger } from "../logger";
import { FirebaseError } from "../error";
import { crashlyticsApiOrigin } from "../api";
import { parseProjectNumber } from "./utils";

const TIMEOUT = 10000;

Expand All @@ -11,12 +12,8 @@ const apiClient = new Client({
});

export async function deleteNote(appId: string, issueId: string, noteId: string): Promise<void> {
const requestProjectId = parseProjectNumber(appId);
try {
const requestProjectId = parseProjectId(appId);
if (requestProjectId === undefined) {
throw new FirebaseError("Unable to get the projectId from the AppId.");
}

await apiClient.request<void, void>({
method: "DELETE",
path: `/projects/${requestProjectId}/apps/${appId}/issues/${issueId}/notes/${noteId}`,
Expand All @@ -30,11 +27,3 @@ export async function deleteNote(appId: string, issueId: string, noteId: string)
);
}
}

function parseProjectId(appId: string): string | undefined {
const appIdParts = appId.split(":");
if (appIdParts.length > 1) {
return appIdParts[1];
}
return undefined;
}
17 changes: 3 additions & 14 deletions src/crashlytics/getIssueDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Client } from "../apiv2";
import { logger } from "../logger";
import { FirebaseError } from "../error";
import { crashlyticsApiOrigin } from "../api";
import { parseProjectNumber } from "./utils";

const TIMEOUT = 10000;

Expand All @@ -11,18 +12,14 @@ const apiClient = new Client({
});

export async function getIssueDetails(appId: string, issueId: string): Promise<string> {
const requestProjectId = parseProjectNumber(appId);
try {
const requestProjectNumber = parseProjectNumber(appId);
if (requestProjectNumber === undefined) {
throw new FirebaseError("Unable to get the projectId from the AppId.");
}

const response = await apiClient.request<void, string>({
method: "GET",
headers: {
"Content-Type": "application/json",
},
path: `/projects/${requestProjectNumber}/apps/${appId}/issues/${issueId}`,
path: `/projects/${requestProjectId}/apps/${appId}/issues/${issueId}`,
timeout: TIMEOUT,
});

Expand All @@ -35,11 +32,3 @@ export async function getIssueDetails(appId: string, issueId: string): Promise<s
);
}
}

function parseProjectNumber(appId: string): string | undefined {
const appIdParts = appId.split(":");
if (appIdParts.length > 1) {
return appIdParts[1];
}
return undefined;
}
17 changes: 3 additions & 14 deletions src/crashlytics/getSampleCrash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Client } from "../apiv2";
import { logger } from "../logger";
import { FirebaseError } from "../error";
import { crashlyticsApiOrigin } from "../api";
import { parseProjectNumber } from "./utils";

const TIMEOUT = 10000;

Expand All @@ -16,6 +17,7 @@ export async function getSampleCrash(
sampleCount: number,
variantId?: string,
): Promise<string> {
const requestProjectId = parseProjectNumber(appId);
try {
const queryParams = new URLSearchParams();
queryParams.set("filter.issue.id", issueId);
Expand All @@ -24,18 +26,13 @@ export async function getSampleCrash(
queryParams.set("filter.issue.variant_id", variantId);
}

const requestProjectNumber = parseProjectNumber(appId);
if (requestProjectNumber === undefined) {
throw new FirebaseError("Unable to get the projectId from the AppId.");
}

logger.debug(`[mcp][crashlytics] getSampleCrash query paramaters: ${queryParams}`);
const response = await apiClient.request<void, string>({
method: "GET",
headers: {
"Content-Type": "application/json",
},
path: `/projects/${requestProjectNumber}/apps/${appId}/events`,
path: `/projects/${requestProjectId}/apps/${appId}/events`,
queryParams: queryParams,
timeout: TIMEOUT,
});
Expand All @@ -49,11 +46,3 @@ export async function getSampleCrash(
);
}
}

function parseProjectNumber(appId: string): string | undefined {
const appIdParts = appId.split(":");
if (appIdParts.length > 1) {
return appIdParts[1];
}
return undefined;
}
15 changes: 2 additions & 13 deletions src/crashlytics/listNotes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Client } from "../apiv2";
import { logger } from "../logger";
import { FirebaseError } from "../error";
import { crashlyticsApiOrigin } from "../api";
import { parseProjectNumber } from "./utils";

const TIMEOUT = 10000;

Expand All @@ -15,15 +16,11 @@ export async function listNotes(
issueId: string,
noteCount: number,
): Promise<string> {
const requestProjectId = parseProjectNumber(appId);
try {
const queryParams = new URLSearchParams();
queryParams.set("page_size", `${noteCount}`);

const requestProjectId = parseProjectId(appId);
if (requestProjectId === undefined) {
throw new FirebaseError("Unable to get the projectId from the AppId.");
}

logger.debug(`[mcp][crashlytics] listNotes query paramaters: ${queryParams}`);
const response = await apiClient.request<void, string>({
method: "GET",
Expand All @@ -44,11 +41,3 @@ export async function listNotes(
);
}
}

function parseProjectId(appId: string): string | undefined {
const appIdParts = appId.split(":");
if (appIdParts.length > 1) {
return appIdParts[1];
}
return undefined;
}
35 changes: 3 additions & 32 deletions src/crashlytics/listTopDevices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Client } from "../apiv2";
import { logger } from "../logger";
import { FirebaseError } from "../error";
import { crashlyticsApiOrigin } from "../api";
import { parsePlatform, parseProjectNumber } from "./utils";

const TIMEOUT = 10000;

Expand All @@ -10,30 +11,20 @@ const apiClient = new Client({
apiVersion: "v1alpha",
});

enum PLATFORM_PATH {
ANDROID = "topAndroidDevices",
IOS = "topAppleDevices",
}

export async function listTopDevices(
appId: string,
deviceCount: number,
issueId?: string,
): Promise<string> {
const requestProjectId = parseProjectNumber(appId);
const platformPath = parsePlatform(appId);
try {
const queryParams = new URLSearchParams();
queryParams.set("page_size", `${deviceCount}`);
if (issueId) {
queryParams.set("filter.issue.id", issueId);
}

const requestProjectId = parseProjectId(appId);
if (requestProjectId === undefined) {
throw new FirebaseError("Unable to get the projectId from the AppId.");
}

const platformPath = parsePlatform(appId);

logger.debug(`[mcp][crashlytics] listTopDevices query paramaters: ${queryParams}`);
const response = await apiClient.request<void, string>({
method: "GET",
Expand All @@ -54,23 +45,3 @@ export async function listTopDevices(
);
}
}

function parseProjectId(appId: string): string | undefined {
const appIdParts = appId.split(":");
if (appIdParts.length > 1) {
return appIdParts[1];
}
return undefined;
}

function parsePlatform(appId: string): PLATFORM_PATH {
const appIdParts = appId.split(":");
if (appIdParts.length < 3) {
throw new FirebaseError("Unable to get the platform from the AppId.");
}

if (appIdParts[2] === "android") {
return PLATFORM_PATH.ANDROID;
} else if (appIdParts[2] === "ios") return PLATFORM_PATH.IOS;
throw new FirebaseError(`Only android or ios apps are supported.`);
}
15 changes: 2 additions & 13 deletions src/crashlytics/listTopIssues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Client } from "../apiv2";
import { logger } from "../logger";
import { FirebaseError } from "../error";
import { crashlyticsApiOrigin } from "../api";
import { parseProjectNumber } from "./utils";

const TIMEOUT = 10000;

Expand All @@ -15,16 +16,12 @@ export async function listTopIssues(
issueType: string,
issueCount: number,
): Promise<string> {
const requestProjectId = parseProjectNumber(appId);
try {
const queryParams = new URLSearchParams();
queryParams.set("page_size", `${issueCount}`);
queryParams.set("filter.issue.error_types", `${issueType}`);

const requestProjectId = parseProjectId(appId);
if (requestProjectId === undefined) {
throw new FirebaseError("Unable to get the projectId from the AppId.");
}

logger.debug(`[mcp][crashlytics] listTopIssues query paramaters: ${queryParams}`);
const response = await apiClient.request<void, string>({
method: "GET",
Expand All @@ -45,11 +42,3 @@ export async function listTopIssues(
);
}
}

function parseProjectId(appId: string): string | undefined {
const appIdParts = appId.split(":");
if (appIdParts.length > 1) {
return appIdParts[1];
}
return undefined;
}
15 changes: 2 additions & 13 deletions src/crashlytics/listTopOperatingSystems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Client } from "../apiv2";
import { logger } from "../logger";
import { FirebaseError } from "../error";
import { crashlyticsApiOrigin } from "../api";
import { parseProjectNumber } from "./utils";

const TIMEOUT = 10000;

Expand All @@ -15,18 +16,14 @@ export async function listTopOperatingSystems(
osCount: number,
issueId?: string,
): Promise<string> {
const requestProjectId = parseProjectNumber(appId);
try {
const queryParams = new URLSearchParams();
queryParams.set("page_size", `${osCount}`);
if (issueId) {
queryParams.set("filter.issue.id", issueId);
}

const requestProjectId = parseProjectId(appId);
if (requestProjectId === undefined) {
throw new FirebaseError("Unable to get the projectId from the AppId.");
}

logger.debug(`[mcp][crashlytics] listTopOperatingSystems query paramaters: ${queryParams}`);
const response = await apiClient.request<void, string>({
method: "GET",
Expand All @@ -47,11 +44,3 @@ export async function listTopOperatingSystems(
);
}
}

function parseProjectId(appId: string): string | undefined {
const appIdParts = appId.split(":");
if (appIdParts.length > 1) {
return appIdParts[1];
}
return undefined;
}
15 changes: 2 additions & 13 deletions src/crashlytics/listTopVersions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Client } from "../apiv2";
import { logger } from "../logger";
import { FirebaseError } from "../error";
import { crashlyticsApiOrigin } from "../api";
import { parseProjectNumber } from "./utils";

const TIMEOUT = 10000;

Expand All @@ -15,18 +16,14 @@ export async function listTopVersions(
versionCount: number,
issueId?: string,
): Promise<string> {
const requestProjectId = parseProjectNumber(appId);
try {
const queryParams = new URLSearchParams();
queryParams.set("page_size", `${versionCount}`);
if (issueId) {
queryParams.set("filter.issue.id", issueId);
}

const requestProjectId = parseProjectId(appId);
if (requestProjectId === undefined) {
throw new FirebaseError("Unable to get the projectId from the AppId.");
}

logger.debug(`[mcp][crashlytics] listTopVersions query paramaters: ${queryParams}`);
const response = await apiClient.request<void, string>({
method: "GET",
Expand All @@ -47,11 +44,3 @@ export async function listTopVersions(
);
}
}

function parseProjectId(appId: string): string | undefined {
const appIdParts = appId.split(":");
if (appIdParts.length > 1) {
return appIdParts[1];
}
return undefined;
}
Loading