Source: src/js/models/dataONEServices/ViewService.js

define([
  "models/dataONEServices/DataONEService",
  "models/viewService/ViewServiceDoc",
  "common/ValueUtilities",
], (DataONEService, ViewServiceDoc, ValueUtilities) => {
  const DEFAULT_THEME = "metacatui";
  const DEFAULT_ACCEPT = "text/html, application/xhtml+xml, */*;q=0.8";

  /**
   * Service for fetching rendered views from the DataONE MNView API.
   * @class ViewService
   * @augments DataONEService
   * @classcategory Models/DataONEServices
   * @since 2.39.0
   */
  class ViewService extends DataONEService {
    /**
     * @param {object} [options] Options for the ViewService. See
     * {@link DataONEService.optionsFromDescriptor} for the shared option shape.
     * @param {string} [options.baseUrl] Theme-qualified view-service base URL,
     * e.g. `/views/metacatui/`.
     * @param {string} [options.theme] Theme name requested by this service
     * Stored for callers; `baseUrl` is still expected to be theme-qualified in
     * this slice.
     */
    constructor(options = {}) {
      super(ViewService.optionsFromDescriptor(options));
      this.theme = ValueUtilities.normalizeText(options.theme) || DEFAULT_THEME;
      this.baseUrl = ViewService.resolveBaseUrl(options.baseUrl);
    }

    /**
     * Fetch rendered HTML and return the full normalized HTTP response.
     * @param {string} pid PID or SID to render
     * @param {object} [options] Request options for
     * {@link DataONEService#request}.
     * @returns {Promise<DataONEHttpResponse>} Normalized response
     */
    async fetch(pid, options = {}) {
      const normalizedPid = this.constructor.normalizePid(
        pid,
        "pid",
        "ViewService.fetch requires a PID",
      );

      return this.request(
        this.constructor.buildRequestOptions({
          options,
          path: this.constructor.buildPidPath(normalizedPid),
          method: "GET",
          accept: DEFAULT_ACCEPT,
        }),
      );
    }

    /**
     * Download rendered HTML and return a parsed rendered metadata document.
     * This method intentionally bypasses DataONEService.download so rendered
     * HTML is not persistently cached by default.
     * @param {string} pid PID or SID to render
     * @param {object} [options] Request and document options
     * @param {string} [options.resolveBaseUrl] Resolve URL for ecogrid rewrites
     * @returns {Promise<ViewServiceDoc>} Parsed rendered document
     */
    async download(pid, options = {}) {
      const { resolveBaseUrl, ...requestOptions } = options;
      const normalizedPid = this.constructor.normalizePid(
        pid,
        "pid",
        "ViewService.download requires a PID",
      );

      const response = await this.fetch(normalizedPid, requestOptions);
      const contentType =
        response.headers?.get?.("Content-Type") ||
        response.headers?.get?.("content-type") ||
        null;

      return ViewServiceDoc.fromHtml(response.data, {
        pid: normalizedPid,
        url: response.url,
        contentType,
        resolveBaseUrl,
      });
    }

    /**
     * Remove an explicitly cached rendered document, if a caller opted into
     * cache use in the future.
     * @param {string} pid PID to invalidate
     * @returns {Promise<void>} Promise resolving when invalidation completes
     */
    async invalidate(pid) {
      const normalizedPid = ValueUtilities.normalizeText(pid);
      if (!normalizedPid) return;
      await this.removeCached(normalizedPid);
    }
  }

  /** @type {DataONEService#DataONEServiceConfig} */
  ViewService.config = {
    endpoint: "views",
    appModelKeys: ["viewServiceUrl"],
    client: {
      timeoutMs: 2 * 60 * 1000, // 2 minutes
      methods: ["GET"],
      responseTypes: ["text"],
      dedupeHeaders: ["Authorization", "Accept"],
    },
    persistPrivate: false,
    defaultAuth: true,
  };
  ViewService.theme = DEFAULT_THEME;
  ViewService.ViewServiceDoc = ViewServiceDoc;

  return ViewService;
});