UNPKG

firebase-app-distribution

Version:
1 lines 10.9 kB
{"version":3,"sources":["../src/releases/index.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\r\nimport {\r\n APP_DISTRIBUTION_ENDPOINT,\r\n ENDPOINT_VERSION,\r\n makeRequest,\r\n} from \"../utils\";\r\nimport { Operation, Operations, Release } from \"./operations\";\r\nimport { FirebaseAppDistribution } from \"../\";\r\n\r\ninterface ListReleasesOptions {\r\n pageSize?: number;\r\n orderBy?: string;\r\n filter?: string;\r\n maxPages?: number;\r\n}\r\n\r\ninterface ListReleasesResponse {\r\n releases: Release[];\r\n nextPageToken: string;\r\n}\r\n\r\ninterface DistributeReleaseOptions {\r\n testerEmails: string[];\r\n groupAliases: string[];\r\n}\r\n\r\ninterface UpdateReleaseOptions {\r\n releaseNotes?: string;\r\n}\r\n\r\nfunction isValidReleaseName(releaseName: string): boolean {\r\n const regex = /^projects\\/[^/]+\\/apps\\/[^/]+\\/releases\\/[^/]+$/;\r\n return regex.test(releaseName);\r\n}\r\n\r\nfunction validateReleaseName(releaseName: string) {\r\n if (!isValidReleaseName(releaseName)) {\r\n throw new Error(\r\n `Invalid release name: ${releaseName}. Expected 'projects/*/apps/*/releases/*'`,\r\n );\r\n }\r\n return;\r\n}\r\n\r\nexport class Releases {\r\n private parent: FirebaseAppDistribution;\r\n\r\n operations: Operations;\r\n\r\n constructor(parent: FirebaseAppDistribution) {\r\n this.parent = parent;\r\n this.operations = new Operations(this.parent);\r\n }\r\n\r\n public async upload(\r\n appId: string,\r\n binaryPath: string,\r\n fileName: string,\r\n ): Promise<Operation> {\r\n const accessToken = await this.parent.getAccessToken();\r\n const projectNumber = await this.parent.getProjectNumber();\r\n\r\n const url = new URL(\r\n `${APP_DISTRIBUTION_ENDPOINT}/upload/${ENDPOINT_VERSION}/projects/${projectNumber}/apps/${appId}/releases:upload`,\r\n );\r\n const fileBuffer = readFileSync(binaryPath);\r\n\r\n const response = await makeRequest<Operation>(url.toString(), {\r\n method: \"POST\",\r\n headers: {\r\n Authorization: `Bearer ${accessToken}`,\r\n \"X-Goog-Upload-File-Name\": encodeURIComponent(fileName),\r\n \"X-Goog-Upload-Protocol\": \"raw\",\r\n },\r\n body: new Uint8Array(fileBuffer),\r\n });\r\n\r\n return response;\r\n }\r\n\r\n public async delete(appId: string, releaseNames: string[]): Promise<{}> {\r\n for (let releaseName of releaseNames) {\r\n validateReleaseName(releaseName);\r\n }\r\n\r\n const accessToken = await this.parent.getAccessToken();\r\n const projectNumber = await this.parent.getProjectNumber();\r\n\r\n if (releaseNames.length > 100) {\r\n throw new Error(\"Cannot delete more than 100 releases at once\");\r\n }\r\n\r\n const url = new URL(\r\n `${APP_DISTRIBUTION_ENDPOINT}/${ENDPOINT_VERSION}/projects/${projectNumber}/apps/${appId}/releases:batchDelete`,\r\n );\r\n\r\n const response = await makeRequest<{}>(url.toString(), {\r\n method: \"POST\",\r\n headers: {\r\n Authorization: `Bearer ${accessToken}`,\r\n },\r\n body: JSON.stringify({\r\n names: releaseNames,\r\n }),\r\n });\r\n\r\n return response;\r\n }\r\n\r\n public async distribute(\r\n releaseName: string,\r\n { testerEmails = [], groupAliases = [] }: DistributeReleaseOptions,\r\n ) {\r\n validateReleaseName(releaseName);\r\n if (testerEmails.length === 0 && groupAliases.length === 0) {\r\n throw new Error(\"Must specify at least one tester or group\");\r\n }\r\n const accessToken = await this.parent.getAccessToken();\r\n\r\n const url = new URL(\r\n `${APP_DISTRIBUTION_ENDPOINT}/${ENDPOINT_VERSION}/${releaseName}:distribute`,\r\n );\r\n\r\n const response = await makeRequest<{}>(url.toString(), {\r\n method: \"POST\",\r\n headers: {\r\n Authorization: `Bearer ${accessToken}`,\r\n },\r\n body: JSON.stringify({\r\n testerEmails,\r\n groupAliases,\r\n }),\r\n });\r\n\r\n return response;\r\n }\r\n\r\n public async get(releaseName: string) {\r\n validateReleaseName(releaseName);\r\n const accessToken = await this.parent.getAccessToken();\r\n\r\n const url = new URL(\r\n `${APP_DISTRIBUTION_ENDPOINT}/${ENDPOINT_VERSION}/${releaseName}`,\r\n );\r\n\r\n const response = await makeRequest<Release>(url.toString(), {\r\n method: \"GET\",\r\n headers: {\r\n Authorization: `Bearer ${accessToken}`,\r\n },\r\n });\r\n\r\n return response;\r\n }\r\n\r\n public async list(\r\n appId: string,\r\n { pageSize, orderBy, filter, maxPages }: ListReleasesOptions = {},\r\n ): Promise<Release[]> {\r\n const accessToken = await this.parent.getAccessToken();\r\n const projectNumber = await this.parent.getProjectNumber();\r\n\r\n const url = new URL(\r\n `${APP_DISTRIBUTION_ENDPOINT}/${ENDPOINT_VERSION}/projects/${projectNumber}/apps/${appId}/releases`,\r\n );\r\n\r\n if (pageSize) {\r\n url.searchParams.set(\"pageSize\", pageSize?.toString() || \"100\");\r\n }\r\n if (orderBy) {\r\n url.searchParams.set(\"orderBy\", orderBy);\r\n }\r\n if (filter) {\r\n url.searchParams.set(\"filter\", filter);\r\n }\r\n\r\n let nextPageToken = \"\";\r\n let currentPage = 0;\r\n const releases: Release[] = [];\r\n do {\r\n if (nextPageToken) {\r\n url.searchParams.set(\"pageToken\", nextPageToken);\r\n } else {\r\n url.searchParams.delete(\"pageToken\");\r\n }\r\n\r\n const response = await makeRequest<ListReleasesResponse>(url.toString(), {\r\n method: \"GET\",\r\n headers: {\r\n Authorization: `Bearer ${accessToken}`,\r\n },\r\n });\r\n\r\n if (response.releases === undefined) {\r\n break;\r\n }\r\n\r\n releases.push(...response.releases);\r\n if (response.nextPageToken !== undefined) {\r\n nextPageToken = response.nextPageToken;\r\n } else {\r\n break;\r\n }\r\n\r\n currentPage++;\r\n if (maxPages && currentPage >= maxPages) {\r\n break;\r\n }\r\n } while (nextPageToken);\r\n\r\n return releases;\r\n }\r\n\r\n async #update(\r\n releaseName: string,\r\n { releaseNotes }: UpdateReleaseOptions = {},\r\n ) {\r\n validateReleaseName(releaseName);\r\n const accessToken = await this.parent.getAccessToken();\r\n\r\n const url = new URL(\r\n `${APP_DISTRIBUTION_ENDPOINT}/${ENDPOINT_VERSION}/${releaseName}`,\r\n );\r\n\r\n if (releaseNotes) {\r\n url.searchParams.set(\"updateMask\", \"releaseNotes.text\");\r\n }\r\n\r\n const response = await makeRequest<Release>(url.toString(), {\r\n method: \"PATCH\",\r\n headers: {\r\n Authorization: `Bearer ${accessToken}`,\r\n },\r\n body: JSON.stringify({\r\n releaseNotes: {\r\n text: releaseNotes,\r\n },\r\n }),\r\n });\r\n\r\n return response;\r\n }\r\n\r\n public async addReleaseNotes(releaseName: string, releaseNotes: string) {\r\n return this.#update(releaseName, { releaseNotes });\r\n }\r\n}\r\n"],"mappings":"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","names":[]}