"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var client_exports = {};
__export(client_exports, {
  MakeswiftClient: () => MakeswiftClient,
  SnippetLocation: () => import_types2.SnippetLocation,
  componentDocumentToRootEmbeddedDocument: () => componentDocumentToRootEmbeddedDocument,
  failedResponseBody: () => failedResponseBody,
  pageToRootDocument: () => pageToRootDocument,
  previewTokenPayloadSchema: () => previewTokenPayloadSchema
});
module.exports = __toCommonJS(client_exports);
var import_zod = require("zod");
var import_api = require("../api");
var import_client = require("../api/graphql/client");
var import_documents = require("../api/graphql/documents");
var import_react = require("../api/react");
var import_introspection = require("../prop-controllers/introspection");
var import_react_page = require("../state/react-page");
var import_pagination = require("../utils/pagination");
var import_deterministic_uuid = require("../utils/deterministic-uuid");
var import_controls = require("@makeswift/controls");
var import_read_only_documents = require("../state/modules/read-only-documents");
var import_merge = require("../state/translations/merge");
var import_get = require("../state/translations/get");
var import_types2 = require("../api/graphql/generated/types");
const makeswiftPageResultSchema = import_zod.z.object({
  id: import_zod.z.string(),
  path: import_zod.z.string(),
  title: import_zod.z.string().nullable(),
  description: import_zod.z.string().nullable(),
  canonicalUrl: import_zod.z.string().nullable(),
  socialImageUrl: import_zod.z.string().nullable(),
  sitemapPriority: import_zod.z.number().nullable(),
  sitemapFrequency: import_zod.z.enum(["always", "hourly", "daily", "weekly", "monthly", "yearly", "never"]).nullable(),
  createdAt: import_zod.z.string(),
  updatedAt: import_zod.z.string(),
  publishedAt: import_zod.z.string().nullable(),
  isOnline: import_zod.z.boolean().nullable(),
  excludedFromSearch: import_zod.z.boolean().nullable(),
  locale: import_zod.z.string(),
  localizedVariants: import_zod.z.array(
    import_zod.z.object({
      locale: import_zod.z.string(),
      path: import_zod.z.string()
    })
  )
});
const makeswiftGetPagesResultAPISchema = import_zod.z.object({
  data: import_zod.z.array(makeswiftPageResultSchema),
  hasMore: import_zod.z.boolean()
});
const makeswiftGetPagesParamsSchema = import_zod.z.object({
  limit: import_zod.z.number().optional(),
  after: import_zod.z.string().optional(),
  sortBy: import_zod.z.enum(["title", "path", "description", "createdAt", "updatedAt"]).optional(),
  sortDirection: import_zod.z.enum(["asc", "desc"]).optional(),
  includeOffline: import_zod.z.boolean().optional(),
  pathPrefix: import_zod.z.string().optional(),
  locale: import_zod.z.string().optional()
});
function getPagesQueryParams({
  limit = 100,
  after,
  sortBy,
  sortDirection,
  includeOffline,
  pathPrefix,
  locale
}) {
  const params = new URLSearchParams();
  if (limit != null)
    params.set("limit", limit.toString());
  if (after != null)
    params.set("after", after);
  if (sortBy != null)
    params.set("sortBy", sortBy);
  if (sortDirection != null)
    params.set("sortDirection", sortDirection);
  if (includeOffline != null)
    params.set("includeOffline", includeOffline.toString());
  if (pathPrefix != null)
    params.set("pathPrefix", pathPrefix);
  if (locale != null)
    params.set("locale", locale);
  return params;
}
function pageToRootDocument(pageDocument) {
  const { locale, localizedPages, id, data } = pageDocument;
  const localizedPage = localizedPages.find(({ parentId }) => parentId == null);
  return localizedPage ? { key: localizedPage.elementTreeId, rootElement: localizedPage.data, locale } : { key: id, rootElement: data, locale };
}
const makeswiftComponentDocumentSchema = import_zod.z.object({
  id: import_zod.z.string(),
  name: import_zod.z.string().nullable(),
  locale: import_zod.z.string().nullable(),
  data: import_controls.Schema.element,
  siteId: import_zod.z.string(),
  inheritsFromParent: import_zod.z.boolean()
});
const makeswiftComponentDocumentFallbackSchema = import_zod.z.object({
  id: import_zod.z.string(),
  locale: import_zod.z.string().nullable(),
  data: import_zod.z.null()
});
const previewTokenPayloadSchema = import_zod.z.object({
  payload: import_zod.z.object({
    version: import_zod.z.string()
  })
});
function componentDocumentToRootEmbeddedDocument({
  document,
  documentKey,
  name,
  type,
  description,
  meta
}) {
  const { data: rootElement, locale, id } = document;
  if (rootElement != null && rootElement.type !== type) {
    throw new Error(
      `Type "${rootElement.type}" does not match the expected type "${type}" from the snapshot`
    );
  }
  const rootDocument = {
    key: documentKey,
    rootElement: rootElement ?? {
      // Fallback rootElement
      // Create a stable uuid so two different clients will have the same empty element data.
      // This is needed to make presence feature work for an element that is not yet created.
      key: (0, import_deterministic_uuid.deterministicUUID)({ id, locale, seed: documentKey }),
      type,
      props: {}
    },
    locale,
    id,
    type,
    name,
    meta: { ...meta, description },
    __type: import_read_only_documents.EMBEDDED_DOCUMENT_TYPE
  };
  return rootDocument;
}
async function failedResponseBody(response) {
  try {
    const text = await response.text();
    try {
      return JSON.parse(text);
    } catch {
      return text;
    }
  } catch (e) {
    return `Failed to extract response body: ${e}`;
  }
}
function responseError(response) {
  return `${response.status} ${response.statusText}`;
}
const pagePathnameSlicesAPISchema = import_zod.z.array(
  import_zod.z.object({
    id: import_zod.z.string(),
    basePageId: import_zod.z.string(),
    pathname: import_zod.z.string(),
    localizedPathname: import_zod.z.string().optional(),
    __typename: import_zod.z.literal("PagePathnameSlice")
  }).nullable()
);
const getPageAPISchema = import_zod.z.object({
  pathname: import_zod.z.string(),
  locale: import_zod.z.string(),
  alternate: import_zod.z.array(
    import_zod.z.object({
      pathname: import_zod.z.string(),
      locale: import_zod.z.string()
    })
  )
});
class MakeswiftClient {
  graphqlClient;
  runtime;
  apiKey;
  apiOrigin;
  constructor(apiKey, { apiOrigin = "https://api.makeswift.com", runtime }) {
    if (typeof apiKey !== "string") {
      throw new Error(
        `The Makeswift client must be passed a valid Makeswift site API key: \`new Makeswift('<makeswift_site_api_key>')\`
Received "${apiKey}" instead.`
      );
    }
    this.apiKey = apiKey;
    try {
      this.apiOrigin = new URL(apiOrigin);
    } catch {
      throw new Error(
        `The Makeswift client received an invalid \`apiOrigin\` parameter: "${apiOrigin}".`
      );
    }
    this.graphqlClient = new import_client.GraphQLClient(new URL("graphql", apiOrigin).href, {
      "makeswift-runtime-version": "0.26.3"
    });
    this.runtime = runtime;
  }
  async fetch(path, siteVersion) {
    const requestUrl = new URL(path, this.apiOrigin);
    const requestHeaders = new Headers({
      "x-api-key": this.apiKey,
      "makeswift-site-api-key": this.apiKey,
      "makeswift-runtime-version": "0.26.3"
    });
    if (siteVersion?.token) {
      requestUrl.searchParams.set("version", siteVersion.version);
      requestHeaders.set("makeswift-preview-token", siteVersion.token);
    }
    const response = await fetch(requestUrl.toString(), {
      headers: requestHeaders,
      ...siteVersion != null ? { cache: "no-store" } : {},
      ...this.fetchOptions(siteVersion)
    });
    return response;
  }
  /**
   * Override this method to provide additional fetch options, e.g. revalidation, cache tags, etc.
   */
  fetchOptions(_siteVersion) {
    return {};
  }
  getPagesInternal = async ({
    siteVersion = null,
    ...params
  } = {}) => {
    const queryParams = getPagesQueryParams(params);
    const response = await this.fetch(`v5/pages?${queryParams.toString()}`, siteVersion);
    if (!response.ok) {
      console.error("Failed to get pages", {
        response: await failedResponseBody(response),
        siteVersion,
        params
      });
      throw new Error(`Failed to get pages: ${responseError(response)}`);
    }
    const result = await response.json();
    const parsedResponse = makeswiftGetPagesResultAPISchema.safeParse(result);
    if (!parsedResponse.success) {
      throw new Error(
        `Failed to parse 'getPages' response: ${parsedResponse.error.errors.map((e) => e.message).join("; ")}`
      );
    }
    return parsedResponse.data;
  };
  getPages = (0, import_pagination.toIterablePaginationResult)(this.getPagesInternal);
  async getPage(pathname, { siteVersion = null, locale } = {}) {
    const url = new URL(`v3/pages/${encodeURIComponent(pathname)}`, this.apiOrigin);
    if (locale)
      url.searchParams.set("locale", locale);
    const response = await this.fetch(url.pathname + url.search, siteVersion);
    if (!response.ok) {
      if (response.status === 404)
        return null;
      console.error(`Failed to get page snapshot for '${pathname}'`, {
        response: await failedResponseBody(response),
        siteVersion,
        locale
      });
      throw new Error(`Failed to get page snapshot for '${pathname}': ${responseError(response)}`);
    }
    const json = await response.json();
    return getPageAPISchema.parse(json);
  }
  async getTypographies(typographyIds, siteVersion) {
    if (typographyIds.length === 0)
      return [];
    const url = new URL(`v3/typographies/bulk`, this.apiOrigin);
    typographyIds.forEach((id) => {
      url.searchParams.append("ids", id);
    });
    const response = await this.fetch(url.pathname + url.search, siteVersion);
    if (!response.ok) {
      console.error(`Failed to get typographies for [${typographyIds.join(", ")}]`, {
        response: await failedResponseBody(response),
        siteVersion
      });
      return [];
    }
    const body = await response.json();
    return body;
  }
  async getSwatches(ids, siteVersion) {
    if (ids.length === 0)
      return [];
    const url = new URL(`v3/swatches/bulk`, this.apiOrigin);
    ids.forEach((id) => {
      url.searchParams.append("ids", id);
    });
    const response = await this.fetch(url.pathname + url.search, siteVersion);
    if (!response.ok) {
      console.error(`Failed to get swatches for ${ids.join(", ")}`, {
        response: await failedResponseBody(response),
        siteVersion
      });
      return [];
    }
    return await response.json();
  }
  async getIntrospectedResources({
    swatchIds,
    ...introspectedResourceIds
  }, siteVersion) {
    const result = await this.graphqlClient.request(import_documents.IntrospectedResourcesQuery, introspectedResourceIds);
    const swatches = await this.getSwatches(swatchIds, siteVersion);
    return { ...result, swatches };
  }
  async introspect(element, siteVersion, locale) {
    const runtime = this.runtime;
    const descriptors = (0, import_react_page.getPropControllerDescriptors)(runtime.store.getState());
    const swatchIds = /* @__PURE__ */ new Set();
    const fileIds = /* @__PURE__ */ new Set();
    const typographyIds = /* @__PURE__ */ new Set();
    const tableIds = /* @__PURE__ */ new Set();
    const pageIds = /* @__PURE__ */ new Set();
    const globalElements = /* @__PURE__ */ new Map();
    const localizedGlobalElements = /* @__PURE__ */ new Map();
    const localizedResourcesMap = /* @__PURE__ */ new Map();
    const remaining = [element];
    const seen = /* @__PURE__ */ new Set();
    let current;
    while (current = remaining.pop()) {
      let getResourcesFromElementDescriptors2 = function(elementDescriptors2, props) {
        Object.entries(elementDescriptors2).forEach(([propName, descriptor]) => {
          (0, import_introspection.getSwatchIds)(descriptor, props[propName]).forEach((swatchId) => {
            swatchIds.add(swatchId);
          });
          (0, import_introspection.getFileIds)(descriptor, props[propName]).forEach((fileId) => fileIds.add(fileId));
          (0, import_introspection.getTypographyIds)(descriptor, props[propName]).forEach(
            (typographyId) => typographyIds.add(typographyId)
          );
          (0, import_introspection.getTableIds)(descriptor, props[propName]).forEach((tableId) => tableIds.add(tableId));
          (0, import_introspection.getPageIds)(descriptor, props[propName]).forEach((pageId) => pageIds.add(pageId));
          (0, import_introspection.getElementChildren)(descriptor, props[propName]).forEach((child) => {
            if (!seen.has(child.key)) {
              seen.add(child.key);
              remaining.push(child);
            }
          });
        });
      };
      var getResourcesFromElementDescriptors = getResourcesFromElementDescriptors2;
      let element2;
      if ((0, import_react_page.isElementReference)(current)) {
        const globalElementId = current.value;
        const globalElement = await this.getGlobalElement(globalElementId, siteVersion);
        let elementData = globalElement?.data;
        if (locale) {
          const localizedGlobalElement = await this.getLocalizedGlobalElement(
            globalElementId,
            locale,
            siteVersion
          );
          if (localizedGlobalElement) {
            elementData = localizedGlobalElement.data;
            localizedResourcesMap.set(globalElementId, localizedGlobalElement.id);
            localizedGlobalElements.set(localizedGlobalElement.id, localizedGlobalElement);
          }
        }
        globalElements.set(globalElementId, globalElement);
        if (elementData == null)
          continue;
        element2 = elementData;
      } else {
        element2 = current;
      }
      const elementDescriptors = descriptors.get(element2.type);
      if (elementDescriptors == null)
        continue;
      getResourcesFromElementDescriptors2(elementDescriptors, element2.props);
    }
    const typographies = await this.getTypographies([...typographyIds], siteVersion);
    typographies.forEach((typography) => {
      typography?.style.forEach((style) => {
        const swatchId = style.value.color?.swatchId;
        if (swatchId != null)
          swatchIds.add(swatchId);
      });
    });
    const pagePathnames = await this.getPagePathnameSlices([...pageIds], siteVersion, { locale });
    const { swatches, files, tables } = await this.getIntrospectedResources(
      {
        swatchIds: [...swatchIds],
        fileIds: [...fileIds],
        tableIds: [...tableIds]
      },
      siteVersion
    );
    const apiResources = {
      [import_api.APIResourceType.Swatch]: [...swatchIds].map((id) => ({
        id,
        value: swatches.find((swatch) => swatch?.id === id) ?? null
      })),
      [import_api.APIResourceType.File]: [...fileIds].map((id) => ({
        id,
        value: files.find((file) => file?.id === id) ?? null
      })),
      [import_api.APIResourceType.Typography]: [...typographyIds].map((id) => ({
        id,
        value: typographies.find((typography) => typography?.id === id) ?? null
      })),
      [import_api.APIResourceType.Table]: [...tableIds].map((id) => ({
        id,
        value: tables.find((table) => table?.id === id) ?? null
      })),
      [import_api.APIResourceType.PagePathnameSlice]: [...pageIds].map((id) => ({
        id,
        value: pagePathnames.find((pagePathnameSlice) => pagePathnameSlice?.id === id) ?? null,
        locale
      })),
      [import_api.APIResourceType.GlobalElement]: [...globalElements.entries()].map(([id, value]) => ({
        id,
        value
      })),
      [import_api.APIResourceType.LocalizedGlobalElement]: [...localizedGlobalElements.entries()].map(
        ([id, value]) => ({
          id,
          value,
          locale
        })
      )
    };
    return {
      apiResources,
      localizedResourcesMap: locale != null ? { [locale]: Object.fromEntries(localizedResourcesMap.entries()) } : {}
    };
  }
  async getPageSnapshot(pathname, {
    siteVersion: siteVersionPromise,
    locale,
    allowLocaleFallback = true
  }) {
    const queryParams = () => {
      const params = new URLSearchParams();
      if (locale)
        params.set("locale", locale);
      if (allowLocaleFallback != null)
        params.set("allowLocaleFallback", `${allowLocaleFallback}`);
      return params.toString();
    };
    const siteVersion = await siteVersionPromise;
    const response = await this.fetch(
      `v4/pages/${encodeURIComponent(pathname)}/document?${queryParams()}`,
      siteVersion
    );
    if (!response.ok) {
      if (response.status === 404)
        return null;
      console.error(`Failed to get page snapshot for '${pathname}'`, {
        response: await failedResponseBody(response),
        siteVersion,
        locale
      });
      throw new Error(`Failed to get page snapshot for '${pathname}': ${responseError(response)}`);
    }
    const document = await response.json();
    const baseLocalizedPage = document.localizedPages.find(({ parentId }) => parentId == null);
    const cacheData = await this.introspect(
      baseLocalizedPage?.data ?? document.data,
      siteVersion,
      // The /v3/pages endpoint returns null for document.locale when the requested locale is the default.
      // This legacy behavior is set to change with the upcoming /v4/pages endpoint.
      // We rely on document.locale when reading from the API cache, so ensure the cache is built during
      // introspection using the same value.
      document.locale
    );
    return {
      document,
      cacheData
    };
  }
  async getComponentSnapshot(id, {
    siteVersion: siteVersionPromise,
    locale,
    allowLocaleFallback = true
  }) {
    const searchParams = new URLSearchParams();
    if (locale)
      searchParams.set("locale", locale);
    const siteVersion = await siteVersionPromise;
    const key = (0, import_deterministic_uuid.deterministicUUID)({ id, locale, seed: this.apiKey.split("-").at(0) });
    const baseLocaleWasRequested = locale == null;
    const canAttemptLocaleFallback = !baseLocaleWasRequested && allowLocaleFallback;
    let response;
    const responseForRequestedLocale = await this.fetch(
      `v2/element-trees/${encodeURIComponent(id)}?${searchParams.toString()}`,
      siteVersion
    );
    if (responseForRequestedLocale.status === 404 && canAttemptLocaleFallback) {
      response = await this.fetch(`v2/element-trees/${encodeURIComponent(id)}`, siteVersion);
    } else {
      response = responseForRequestedLocale;
    }
    if (!response.ok) {
      if (response.status === 404) {
        return {
          document: {
            id,
            locale: locale ?? null,
            data: null
          },
          key,
          cacheData: import_react.CacheData.empty(),
          meta: {
            allowLocaleFallback,
            requestedLocale: locale ?? null
          }
        };
      }
      console.error(`Failed to get component snapshot for '${id}':`, {
        response: await failedResponseBody(response),
        siteVersion,
        locale
      });
      throw new Error(`Failed to get component snapshot for '${id}': ${responseError(response)}`);
    }
    const document = makeswiftComponentDocumentSchema.parse(await response.json());
    const cacheData = await this.introspect(document.data, siteVersion, locale ?? null);
    return {
      document,
      cacheData,
      key,
      meta: {
        allowLocaleFallback,
        requestedLocale: locale ?? null
      }
    };
  }
  async getSwatch(swatchId, siteVersion) {
    const response = await this.fetch(`v3/swatches/${swatchId}`, siteVersion);
    if (!response.ok) {
      if (response.status !== 404) {
        console.error(`Failed to get swatch '${swatchId}'`, {
          response: await failedResponseBody(response),
          siteVersion
        });
      }
      return null;
    }
    const swatch = await response.json();
    return swatch;
  }
  async getFile(fileId) {
    const result = await this.graphqlClient.request(
      import_documents.FileQuery,
      { fileId }
    );
    return result.file;
  }
  async getTypography(typographyId, siteVersion) {
    const response = await this.fetch(`v3/typographies/${typographyId}`, siteVersion);
    if (!response.ok) {
      if (response.status !== 404) {
        console.error(`Failed to get typography '${typographyId}'`, {
          response: await failedResponseBody(response),
          siteVersion
        });
      }
      return null;
    }
    const typography = await response.json();
    return typography;
  }
  async getGlobalElement(globalElementId, siteVersion) {
    const response = await this.fetch(`v3/global-elements/${globalElementId}`, siteVersion);
    if (!response.ok) {
      if (response.status !== 404) {
        console.error(`Failed to get global element '${globalElementId}'`, {
          response: await failedResponseBody(response),
          siteVersion
        });
      }
      return null;
    }
    const globalElement = await response.json();
    return globalElement;
  }
  async getLocalizedGlobalElement(globalElementId, locale, siteVersion) {
    const response = await this.fetch(
      `v3/localized-global-elements/${globalElementId}?locale=${locale}`,
      siteVersion
    );
    if (!response.ok) {
      if (response.status !== 404) {
        console.error(`Failed to get localized global element '${globalElementId}'`, {
          response: await failedResponseBody(response),
          siteVersion,
          locale
        });
      }
      return null;
    }
    const localizedGlobalElement = await response.json();
    return localizedGlobalElement;
  }
  async getPagePathnameSlices(pageIds, siteVersion, { locale }) {
    if (pageIds.length === 0)
      return [];
    const url = new URL(`v3/page-pathname-slices/bulk`, this.apiOrigin);
    pageIds.forEach((id) => url.searchParams.append("ids", id));
    if (locale != null)
      url.searchParams.set("locale", locale);
    const response = await this.fetch(url.pathname + url.search, siteVersion);
    if (!response.ok) {
      console.error(`Failed to get page pathname slice(s) for ${pageIds.join(", ")}`, {
        response: await failedResponseBody(response),
        siteVersion,
        locale
      });
      return [];
    }
    const json = await response.json();
    const pagePathnameSlices = pagePathnameSlicesAPISchema.parse(json);
    return pagePathnameSlices.map((pagePathnameSlice) => {
      if (pagePathnameSlice == null)
        return null;
      return {
        ...pagePathnameSlice,
        id: pagePathnameSlice.basePageId,
        localizedPathname: pagePathnameSlice.localizedPathname ?? null
      };
    });
  }
  async getPagePathnameSlice(pageId, siteVersion, { locale } = {}) {
    const pagePathnameSlices = await this.getPagePathnameSlices([pageId], siteVersion, { locale });
    return pagePathnameSlices.at(0) ?? null;
  }
  async getTable(tableId) {
    const result = await this.graphqlClient.request(
      import_documents.TableQuery,
      { tableId }
    );
    return result.table;
  }
  getTranslatableData(elementTree) {
    return (0, import_get.getElementTreeTranslatableData)(this.runtime.store.getState(), elementTree);
  }
  mergeTranslatedData(elementTree, translatedData) {
    return (0, import_merge.mergeElementTreeTranslatedData)(
      this.runtime.store.getState(),
      elementTree,
      translatedData
    );
  }
  async readPreviewToken(token) {
    const response = await fetch(new URL("v1/preview-tokens/reads", this.apiOrigin).toString(), {
      method: "POST",
      headers: {
        "x-api-key": this.apiKey,
        "makeswift-site-api-key": this.apiKey,
        "makeswift-runtime-version": "0.26.3",
        "content-type": "application/json"
      },
      body: JSON.stringify({ token }),
      cache: "no-store"
    });
    if (!response.ok) {
      if (response.status === 401) {
        console.error(`Preview token is invalid or expired`, {
          response: await failedResponseBody(response)
        });
      } else if (response.status !== 404) {
        console.error(`Failed to verify preview token`, {
          response: await failedResponseBody(response)
        });
      }
      return null;
    }
    const json = await response.json();
    const parsed = previewTokenPayloadSchema.safeParse(json);
    if (!parsed.success) {
      throw new Error(
        `Failed to parse preview token payload: ${parsed.error.errors.map((e) => e.message).join("; ")}`
      );
    }
    return parsed.data;
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  MakeswiftClient,
  SnippetLocation,
  componentDocumentToRootEmbeddedDocument,
  failedResponseBody,
  pageToRootDocument,
  previewTokenPayloadSchema
});
//# sourceMappingURL=index.js.map