{"version":3,"sources":["../src/testers.ts"],"sourcesContent":["import { FirebaseAppDistribution } from \".\";\r\nimport {\r\n  APP_DISTRIBUTION_ENDPOINT,\r\n  ENDPOINT_VERSION,\r\n  makeRequest,\r\n} from \"./utils\";\r\n\r\nexport interface Tester {\r\n  name: string;\r\n  displayName?: string;\r\n  groups?: string[];\r\n  lastActivityTime?: string;\r\n  email: string; // custom added field\r\n}\r\n\r\ninterface TestersListResponse {\r\n  testers: Tester[];\r\n  nextPageToken?: string;\r\n}\r\n\r\ninterface TestersRemoveResponse {\r\n  emails: string[];\r\n}\r\n\r\ninterface TestersAddResponse {\r\n  testers: Tester[];\r\n}\r\n\r\ninterface TesterListArgs {\r\n  pageSize?: number;\r\n  email?: string;\r\n  displayName?: string;\r\n  groups?: string;\r\n  maxPages?: number;\r\n}\r\n\r\ninterface TesterUpdateArgs {\r\n  displayName?: string;\r\n  groups?: string[];\r\n}\r\n\r\nfunction getEmailFromName(testerName: string) {\r\n  return testerName.split(\"/\").pop()!;\r\n}\r\n\r\nexport class Testers {\r\n  private parent: FirebaseAppDistribution;\r\n  constructor(parent: FirebaseAppDistribution) {\r\n    this.parent = parent;\r\n  }\r\n\r\n  async add(emails: string[]): Promise<Tester[]> {\r\n    const accessToken = await this.parent.getAccessToken();\r\n    const projectNumber = await this.parent.getProjectNumber();\r\n\r\n    const testers: Tester[] = [];\r\n\r\n    const url = new URL(\r\n      `${APP_DISTRIBUTION_ENDPOINT}/${ENDPOINT_VERSION}/projects/${projectNumber}/testers:batchAdd`,\r\n    );\r\n    const requestBody: string = JSON.stringify({\r\n      emails,\r\n    });\r\n    const response = await makeRequest<TestersAddResponse>(url.toString(), {\r\n      headers: {\r\n        authorization: `Bearer ${accessToken}`,\r\n      },\r\n      body: requestBody,\r\n      method: \"POST\",\r\n    });\r\n\r\n    for (let tester of response.testers) {\r\n      testers.push({\r\n        ...tester,\r\n        email: getEmailFromName(tester.name),\r\n      });\r\n    }\r\n\r\n    return testers;\r\n  }\r\n\r\n  async remove(emails: string[]): Promise<string[]> {\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}/testers:batchRemove`,\r\n    );\r\n    const requestBody: string = JSON.stringify({\r\n      emails,\r\n    });\r\n    const response = await makeRequest<TestersRemoveResponse>(url.toString(), {\r\n      headers: {\r\n        authorization: `Bearer ${accessToken}`,\r\n      },\r\n      body: requestBody,\r\n      method: \"POST\",\r\n    });\r\n\r\n    return response.emails || [];\r\n  }\r\n\r\n  async list({\r\n    pageSize = 50,\r\n    email,\r\n    displayName,\r\n    groups,\r\n    maxPages = 10,\r\n  }: TesterListArgs = {}): Promise<Tester[]> {\r\n    const accessToken = await this.parent.getAccessToken();\r\n    const projectNumber = await this.parent.getProjectNumber();\r\n\r\n    const testerList: Tester[] = [];\r\n\r\n    const url = new URL(\r\n      `${APP_DISTRIBUTION_ENDPOINT}/${ENDPOINT_VERSION}/projects/${projectNumber}/testers`,\r\n    );\r\n    url.searchParams.set(\"pageSize\", pageSize.toString());\r\n\r\n    let filterParts = [];\r\n    if (email) filterParts.push(`name=\"projects/-/testers/${email}\"`);\r\n    if (displayName) filterParts.push(`displayName=\"${displayName}\"`);\r\n    if (groups) filterParts.push(`groups=\"projects/*/groups/${groups}\"`);\r\n\r\n    if (filterParts.length > 0) {\r\n      url.searchParams.set(\"filter\", filterParts.join(\" \"));\r\n    }\r\n\r\n    let nextPageToken = \"\";\r\n    for (let page = 0; page < maxPages; page++) {\r\n      if (nextPageToken) {\r\n        url.searchParams.set(\"pageToken\", nextPageToken);\r\n      } else {\r\n        url.searchParams.delete(\"pageToken\");\r\n      }\r\n      const response = await makeRequest<TestersListResponse>(url.toString(), {\r\n        headers: {\r\n          authorization: `Bearer ${accessToken}`,\r\n        },\r\n        body: null,\r\n        method: \"GET\",\r\n      });\r\n\r\n      if (response.testers === undefined) {\r\n        break;\r\n      }\r\n\r\n      for (let tester of response.testers) {\r\n        testerList.push({\r\n          ...tester,\r\n          email: getEmailFromName(tester.name),\r\n        });\r\n      }\r\n\r\n      if (response.nextPageToken !== undefined) {\r\n        nextPageToken = response.nextPageToken;\r\n      } else {\r\n        break;\r\n      }\r\n    }\r\n\r\n    return testerList;\r\n  }\r\n\r\n  async get(email: string): Promise<Tester | null> {\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}/testers`,\r\n    );\r\n    url.searchParams.append(\"pageSize\", \"1\");\r\n    url.searchParams.append(\"filter\", `name=\"projects/-/testers/${email}\"`);\r\n    const response = await makeRequest<TestersListResponse>(url.toString(), {\r\n      headers: {\r\n        authorization: `Bearer ${accessToken}`,\r\n      },\r\n      body: null,\r\n      method: \"GET\",\r\n    });\r\n\r\n    return response.testers !== undefined\r\n      ? {\r\n          ...response.testers[0],\r\n          email: getEmailFromName(response.testers[0].name),\r\n        }\r\n      : null;\r\n  }\r\n\r\n  async update(\r\n    email: string,\r\n    { displayName, groups }: TesterUpdateArgs = {},\r\n  ): Promise<Tester> {\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}/testers/${email}`,\r\n    );\r\n\r\n    let updateMaskParts = [];\r\n    if (displayName !== undefined) {\r\n      updateMaskParts.push(\"displayName\");\r\n    }\r\n    if (groups !== undefined) {\r\n      updateMaskParts.push(\"groups\");\r\n    }\r\n    if (updateMaskParts.length > 0) {\r\n      url.searchParams.append(\"updateMask\", updateMaskParts.join(\",\"));\r\n    }\r\n\r\n    const formattedGroups = groups?.map(\r\n      (group) => `projects/${projectNumber}/groups/${group}`,\r\n    );\r\n\r\n    const response = await makeRequest<Tester>(url.toString(), {\r\n      headers: {\r\n        authorization: `Bearer ${accessToken}`,\r\n      },\r\n      body: JSON.stringify({\r\n        displayName: displayName || undefined,\r\n        groups: formattedGroups || undefined,\r\n      }),\r\n      method: \"PATCH\",\r\n    });\r\n\r\n    return { ...response, email: getEmailFromName(response.name) };\r\n  }\r\n}\r\n"],"mappings":"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","names":[]}