private async getDownloadsRaw()

in src/backend/package-stats/npm-downloads.lambda-shared.ts [55:111]


  private async getDownloadsRaw(
    packages: readonly string[],
    period: NpmDownloadsPeriod,
    throwErrors: boolean,
  ): Promise<NpmDownloadsOutput> {
    if (packages.length > NpmDownloadsClient.MAX_PACKAGES_PER_QUERY) {
      throw new Error(`Too many packages were provided (max: ${NpmDownloadsClient.MAX_PACKAGES_PER_QUERY})`);
    }
    if (packages.some((pkg) => this.isScopedPackage(pkg)) && packages.length > 1) {
      throw new Error('Scoped packages aren\'t supported by the bulk query API.');
    }
    if (packages.length === 0) return new Map();

    console.log(`Querying NPM for ${packages.length} package(s): [${packages.join(', ')}]`);
    const result = await this.got(`${NpmDownloadsClient.NPM_DOWNLOADS_API_URL}/${period}/${packages.join(',')}`, {
      timeout: 5_000, // 5 seconds
    }).catch((err) => {
      if (throwErrors) {
        throw err;
      } else {
        return { body: JSON.stringify({ error: JSON.stringify(err) }) };
      }
    });

    const data: NpmApiResult = JSON.parse(result.body);

    // single package query error
    // ex. { "error": "package foo not found" }
    if ('error' in data) {
      if (throwErrors) {
        throw new Error(`Could not retrieve download metrics: ${data.error}`);
      } else {
        console.error(`Could not retrieve download metrics: ${data.error}`);
        return new Map();
      }
    }

    // only a single package was returned
    if (isSingleDownloadsEntry(data)) {
      return new Map([[packages[0], data]]);
    }

    // bulk query result
    for (const key of Object.keys(data)) {
      if (data[key] === null) {
        if (throwErrors) {
          throw new Error(`Could not retrieve download metrics for package ${key}`);
        } else {
          console.error(`Could not retrieve download metrics for package ${key}`);
          delete data[key];
        }
      }
    }

    // typescript can't figure out that we removed all null values
    return new Map(Object.entries(data as any));
  }