export async function fetchJson()

in src/https.ts [78:147]


export async function fetchJson<ResultType extends Json>(
  uri: string,
  requestOptions?: FetchRequestOptions,
  data?: Buffer
): Promise<ResultType> {
  let responseTimeout: NodeJS.Timeout;
  return new Promise<ResultType>((resolve, reject) => {
    const req = request(
      uri,
      {
        method: "GET",
        ...requestOptions,
      },
      (response) => {
        // Capture response data
        // @types/node is incomplete so cast to any
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        (pipeline as any)(
          [
            response,
            getJsonDestination(uri, response.statusCode, response.headers),
          ],
          done
        );
      }
    );

    if (requestOptions?.responseTimeout) {
      responseTimeout = setTimeout(
        () =>
          done(
            new FetchError(
              uri,
              `Response time-out (after ${requestOptions.responseTimeout} ms.)`
            )
          ),
        requestOptions.responseTimeout
      );
      responseTimeout.unref(); // Don't block Node from exiting
    }

    function done(...args: [Error] | [null, ResultType]) {
      if (responseTimeout) clearTimeout(responseTimeout);
      if (args[0] == null) {
        resolve(args[1]);
        return;
      }

      // In case of errors, let the Agent (if any) know to abandon the socket
      // This is probably best, because the socket may have become stale
      /* istanbul ignore next */
      req.socket?.emit("agentRemove");

      // Turn error into FetchError so the URI is nicely captured in the message
      let error = args[0];
      if (!(error instanceof FetchError)) {
        error = new FetchError(uri, error.message);
      }

      req.destroy();
      reject(error);
    }

    // Handle errors while sending request
    req.on("error", done);

    // Signal end of request (include optional data)
    req.end(data);
  });
}