UNPKG

@prismicio/client

Version:

The official JavaScript + TypeScript client library for Prismic

926 lines (924 loc) 32.9 kB
import { filter } from "./filter.js"; import { devMsg } from "./lib/devMsg.js"; import { getPreviewCookie } from "./lib/getPreviewCookie.js"; import { request } from "./lib/request.js"; import { throttledWarn } from "./lib/throttledWarn.js"; import { ForbiddenError, NotFoundError, ParsingError, PreviewTokenExpiredError, PrismicError, RefExpiredError, RefNotFoundError, RepositoryNotFoundError } from "./errors.js"; import { asLink } from "./helpers/asLink.js"; import { buildQueryURL } from "./buildQueryURL.js"; import { getRepositoryEndpoint } from "./getRepositoryEndpoint.js"; import { getRepositoryName } from "./getRepositoryName.js"; import { isRepositoryEndpoint } from "./isRepositoryEndpoint.js"; //#region src/Client.ts const MAX_PAGE_SIZE = 100; const REPOSITORY_CACHE_TTL = 5e3; const GET_ALL_QUERY_DELAY = 500; const MAX_INVALID_REF_RETRY_ATTEMPTS = 3; /** * A client for fetching content from a Prismic repository. * * @see {@link https://prismic.io/docs/fetch-content} * @see {@link https://prismic.io/docs/technical-reference/prismicio-client} */ var Client = class { /** * The client's Content API endpoint. * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#config-options} */ documentAPIEndpoint; /** * The secure token used for the Content API. * * @see {@link https://prismic.io/docs/fetch-content#content-visibility} */ accessToken; /** * A list of route resolver objects that define how a document's `url` * property is resolved. * * @see {@link https://prismic.io/docs/routes} * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#config-options} */ routes; /** * The URL used for link or content relationship fields that point to an * archived or deleted page. * * @see {@link https://prismic.io/docs/routes} * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#config-options} */ brokenRoute; /** * Default parameters sent with each Content API request. These parameters can * be overridden on each method. * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#config-options} */ defaultParams; /** * The `fetch` function used to make network requests. * * @default The global `fetch` function. * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#config-options} */ fetchFn; /** * The default `fetch` options sent with each Content API request. These * parameters can be overriden on each method. * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#config-options} */ fetchOptions; #repositoryName; #getRef; #autoPreviews = true; #autoPreviewsRequest; #cachedRepository; #cachedRepositoryExpiration = 0; /** * @param repositoryNameOrEndpoint - The Prismic repository name or full * Content API endpoint for the repository. * @param config - Client configuration. */ constructor(repositoryNameOrEndpoint, config = {}) { var _globalThis$fetch; const { documentAPIEndpoint, accessToken, ref, routes, brokenRoute, defaultParams, fetchOptions = {}, fetch = (_globalThis$fetch = globalThis.fetch) === null || _globalThis$fetch === void 0 ? void 0 : _globalThis$fetch.bind(globalThis) } = config; if (isRepositoryEndpoint(repositoryNameOrEndpoint)) { try { this.repositoryName = getRepositoryName(repositoryNameOrEndpoint); } catch { console.warn(`[@prismicio/client] A repository name could not be inferred from the provided endpoint (\`${repositoryNameOrEndpoint}\`). Some methods will be disabled. Create the client using a repository name to prevent this warning. For more details, see ${devMsg("prefer-repository-name")}`); } this.documentAPIEndpoint = documentAPIEndpoint || repositoryNameOrEndpoint; } else { this.repositoryName = repositoryNameOrEndpoint; this.documentAPIEndpoint = documentAPIEndpoint || getRepositoryEndpoint(repositoryNameOrEndpoint); } if (!fetch) throw new PrismicError("A valid fetch implementation was not provided. In environments where fetch is not available, a fetch implementation must be provided via a polyfill or the `fetch` option.", void 0, void 0); if (typeof fetch !== "function") throw new PrismicError(`fetch must be a function, but received: ${typeof fetch}`, void 0, void 0); if (!isRepositoryEndpoint(this.documentAPIEndpoint)) throw new PrismicError(`documentAPIEndpoint is not a valid URL: ${documentAPIEndpoint}`, void 0, void 0); if (isRepositoryEndpoint(repositoryNameOrEndpoint) && documentAPIEndpoint && repositoryNameOrEndpoint !== documentAPIEndpoint) console.warn(`[@prismicio/client] Multiple incompatible endpoints were provided. Create the client using a repository name to prevent this error. For more details, see ${devMsg("prefer-repository-name")}`); if (process.env.NODE_ENV === "development" && /\.prismic\.io\/(?!api\/v2\/?)/i.test(this.documentAPIEndpoint)) throw new PrismicError("@prismicio/client only supports Prismic Rest API V2. Please provide only the repository name to the first createClient() parameter or use the getRepositoryEndpoint() helper to generate a valid Rest API V2 endpoint URL.", void 0, void 0); if (process.env.NODE_ENV === "development" && /\.prismic\.io$/i.test(new URL(this.documentAPIEndpoint).hostname) && !/\.cdn\.prismic\.io$/i.test(new URL(this.documentAPIEndpoint).hostname)) console.warn(`[@prismicio/client] The client was created with a non-CDN endpoint. Convert it to the CDN endpoint for better performance. For more details, see ${devMsg("endpoint-must-use-cdn")}`); this.accessToken = accessToken; this.routes = routes; this.brokenRoute = brokenRoute; this.defaultParams = defaultParams; this.fetchOptions = fetchOptions; this.fetchFn = fetch; this.graphQLFetch = this.graphQLFetch.bind(this); if (ref) this.queryContentFromRef(ref); } /** The Prismic repository's name. */ set repositoryName(value) { this.#repositoryName = value; } /** The Prismic repository's name. */ get repositoryName() { if (!this.#repositoryName) throw new PrismicError(`A repository name is required for this method but one could not be inferred from the provided API endpoint (\`${this.documentAPIEndpoint}\`). To fix this error, provide a repository name when creating the client. For more details, see ${devMsg("prefer-repository-name")}`, void 0, void 0); return this.#repositoryName; } /** @deprecated Replace with `documentAPIEndpoint`. */ set endpoint(value) { this.documentAPIEndpoint = value; } /** @deprecated Replace with `documentAPIEndpoint`. */ get endpoint() { return this.documentAPIEndpoint; } /** * Enables the client to automatically query content from a preview session. * * @example * * ```ts * client.enableAutoPreviews() * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#enableautopreviews} */ enableAutoPreviews() { this.#autoPreviews = true; } /** * Enables the client to automatically query content from a preview session * using an HTTP request object. * * @example * * ```ts * client.enableAutoPreviewsFromReq(req) * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#enableautopreviewsfromreq} */ enableAutoPreviewsFromReq(request$1) { this.enableAutoPreviews(); this.#autoPreviewsRequest = request$1; } /** * Disables the client from automatically querying content from a preview * session. * * @example * * ```ts * client.disableAutoPreviews() * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#disableautopreviews} */ disableAutoPreviews() { this.#autoPreviews = false; this.#autoPreviewsRequest = void 0; } /** * Fetches pages based on the `params` argument. Results are paginated. * * @example * * ```ts * const response = await client.get({ pageSize: 10 }) * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#get} */ async get(params) { return await (await this.#internalGet(params)).json(); } /** * Fetches the first page returned based on the `params` argument. * * @example * * ```ts * const page = await client.getFirst() * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getfirst} */ async getFirst(params) { const actualParams = (params === null || params === void 0 ? void 0 : params.page) || (params === null || params === void 0 ? void 0 : params.pageSize) ? params : { ...params, pageSize: 1 }; const response = await this.#internalGet(actualParams); const { results } = await response.clone().json(); if (results[0]) return results[0]; throw new NotFoundError("No documents were returned", response.url, void 0); } /** * Fetches all pages based on the `params` argument. This method may make * multiple network requests to fetch all matching pages. * * @example * * ```ts * const pages = await client.dangerouslyGetAll() * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#dangerouslygetall} */ async dangerouslyGetAll(params = {}) { var _this$defaultParams; const { limit = Infinity,...actualParams } = params; const resolvedParams = { ...actualParams, pageSize: Math.min(limit, actualParams.pageSize || ((_this$defaultParams = this.defaultParams) === null || _this$defaultParams === void 0 ? void 0 : _this$defaultParams.pageSize) || MAX_PAGE_SIZE) }; const documents = []; let latestResult; while ((!latestResult || latestResult.next_page) && documents.length < limit) { const page = latestResult ? latestResult.page + 1 : void 0; latestResult = await this.get({ ...resolvedParams, page }); documents.push(...latestResult.results); if (latestResult.next_page) await new Promise((res) => setTimeout(res, GET_ALL_QUERY_DELAY)); } return documents.slice(0, limit); } /** * Fetches a page with a specific ID. * * @example * * ```ts * const page = await client.getByID("WW4bKScAAMAqmluX") * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getbyid} */ async getByID(id, params) { return await this.getFirst(appendFilters(params, filter.at("document.id", id))); } /** * Fetches pages with specific IDs. Results are paginated. * * @example * * ```ts * const response = await client.getByIDs([ * "WW4bKScAAMAqmluX", * "U1kTRgEAAC8A5ldS", * ]) * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getbyids} */ async getByIDs(ids, params) { return await this.get(appendFilters(params, filter.in("document.id", ids))); } /** * Fetches pages with specific IDs. This method may make multiple network * requests to fetch all matching pages. * * @example * * ```ts * const pages = await client.getAllByIDs([ * "WW4bKScAAMAqmluX", * "U1kTRgEAAC8A5ldS", * ]) * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getallbyids} */ async getAllByIDs(ids, params) { return await this.dangerouslyGetAll(appendFilters(params, filter.in("document.id", ids))); } /** * Fetches a page with a specific UID and type. * * @example * * ```ts * const page = await client.getByUID("blog_post", "my-first-post") * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getbyuid} */ async getByUID(documentType, uid, params) { return await this.getFirst(appendFilters(params, filter.at("document.type", documentType), filter.at(`my.${documentType}.uid`, uid))); } /** * Fetches pages with specific UIDs and a specific type. Results are * paginated. * * @example * * ```ts * const response = await client.getByUIDs("blog_post", [ * "my-first-post", * "my-second-post", * ]) * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getbyuids} */ async getByUIDs(documentType, uids, params) { return await this.get(appendFilters(params, filter.at("document.type", documentType), filter.in(`my.${documentType}.uid`, uids))); } /** * Fetches pages with specific UIDs and a specific type. This method may make * multiple network requests to fetch all matching pages. * * @example * * ```ts * const pages = await client.getAllByUIDs("blog_post", [ * "my-first-post", * "my-second-post", * ]) * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getallbyuids} */ async getAllByUIDs(documentType, uids, params) { return await this.dangerouslyGetAll(appendFilters(params, filter.at("document.type", documentType), filter.in(`my.${documentType}.uid`, uids))); } /** * Fetches a specific single type page. * * @example * * ```ts * const page = await client.getSingle("settings") * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getsingle} */ async getSingle(documentType, params) { return await this.getFirst(appendFilters(params, filter.at("document.type", documentType))); } /** * Fetches pages with a specific type. Results are paginated. * * @example * * ```ts * const response = await client.getByType("blog_post") * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getbytype} */ async getByType(documentType, params) { return await this.get(appendFilters(params, filter.at("document.type", documentType))); } /** * Fetches pages with a specific type. This method may make multiple network * requests to fetch all matching documents. * * @example * * ```ts * const pages = await client.getAllByType("blog_post") * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getallbytype} */ async getAllByType(documentType, params) { return await this.dangerouslyGetAll(appendFilters(params, filter.at("document.type", documentType))); } /** * Fetches pages with a specific tag. Results are paginated. * * @example * * ```ts * const response = await client.getByTag("featured") * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getbytag} */ async getByTag(tag, params) { return await this.get(appendFilters(params, filter.any("document.tags", [tag]))); } /** * Fetches pages with a specific tag. This method may make multiple network * requests to fetch all matching documents. * * @example * * ```ts * const pages = await client.getAllByTag("featured") * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getallbytag} */ async getAllByTag(tag, params) { return await this.dangerouslyGetAll(appendFilters(params, filter.any("document.tags", [tag]))); } /** * Fetches pages with every tag from a list of tags. Results are paginated. * * @example * * ```ts * const response = await client.getByEveryTag(["featured", "homepage"]) * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getbyeverytag} */ async getByEveryTag(tags, params) { return await this.get(appendFilters(params, filter.at("document.tags", tags))); } /** * Fetches pages with every tag from a list of tags. This method may make * multiple network requests to fetch all matching pages. * * @example * * ```ts * const pages = await client.getAllByEveryTag(["featured", "homepage"]) * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getallbyeverytag} */ async getAllByEveryTag(tags, params) { return await this.dangerouslyGetAll(appendFilters(params, filter.at("document.tags", tags))); } /** * Fetches pages with at least one tag from a list of tags. Results are * paginated. * * @example * * ```ts * const response = await client.getBySomeTags(["featured", "homepage"]) * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getbysometags} */ async getBySomeTags(tags, params) { return await this.get(appendFilters(params, filter.any("document.tags", tags))); } /** * Fetches pages with at least one tag from a list of tags. This method may * make multiple network requests to fetch all matching documents. * * @example * * ```ts * const pages = await client.getAllBySomeTags(["featured", "homepage"]) * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getallbysometags} */ async getAllBySomeTags(tags, params) { return await this.dangerouslyGetAll(appendFilters(params, filter.any("document.tags", tags))); } /** * Fetches metadata about the client's Prismic repository. * * @example * * ```ts * const repository = await client.getRepository() * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getrepository} */ async getRepository(params) { if (this.#cachedRepository && this.#cachedRepositoryExpiration > Date.now()) return this.#cachedRepository; const url = new URL(this.documentAPIEndpoint); const accessToken = (params === null || params === void 0 ? void 0 : params.accessToken) || this.accessToken; if (accessToken) url.searchParams.set("access_token", accessToken); const response = await this.#request(url, params); if (response.ok) { this.#cachedRepository = await response.json(); this.#cachedRepositoryExpiration = Date.now() + REPOSITORY_CACHE_TTL; return this.#cachedRepository; } if (response.status === 404) throw new RepositoryNotFoundError(`Prismic repository not found. Check that "${this.documentAPIEndpoint}" is pointing to the correct repository.`, url.toString(), void 0); return await this.#throwContentAPIError(response, url.toString()); } /** * Fetches the repository's active refs. * * @example * * ```ts * const refs = await client.getRefs() * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getrefs} */ async getRefs(params) { return (await this.getRepository(params)).refs; } /** * Fetches a ref by its ID. * * @example * * ```ts * const ref = await client.getRefByID("YhE3YhEAACIA4321") * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getrefbyid} */ async getRefByID(id, params) { const ref = (await this.getRefs(params)).find((ref$1) => ref$1.id === id); if (!ref) throw new PrismicError(`Ref with ID "${id}" could not be found.`, void 0, void 0); return ref; } /** * Fetches a ref by its label. A release ref's label is its name shown in the * Page Builder. * * @example * * ```ts * const ref = await client.getRefByLabel("My Release") * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getrefbylabel} */ async getRefByLabel(label, params) { const ref = (await this.getRefs(params)).find((ref$1) => ref$1.label === label); if (!ref) throw new PrismicError(`Ref with label "${label}" could not be found.`, void 0, void 0); return ref; } /** * Fetches the repository's master ref. * * @example * * ```ts * const masterRef = await client.getMasterRef() * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getmasterref} */ async getMasterRef(params) { const ref = (await this.getRefs(params)).find((ref$1) => ref$1.isMasterRef); if (!ref) throw new PrismicError("Master ref could not be found.", void 0, void 0); return ref; } /** * Fetches the repository's active releases. * * @example * * ```ts * const releases = await client.getReleases() * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getreleases} */ async getReleases(params) { return (await this.getRefs(params)).filter((ref) => !ref.isMasterRef); } /** * Fetches a release with a specific ID. * * @example * * ```ts * const release = await client.getReleaseByID("YhE3YhEAACIA4321") * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getreleasebyid} */ async getReleaseByID(id, params) { const release = (await this.getReleases(params)).find((ref) => ref.id === id); if (!release) throw new PrismicError(`Release with ID "${id}" could not be found.`, void 0, void 0); return release; } /** * Fetches a release by its label. A release ref's label is its name shown in * the Page Builder. * * @example * * ```ts * const release = await client.getReleaseByLabel("My Release") * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#getreleasebylabel} */ async getReleaseByLabel(label, params) { const release = (await this.getReleases(params)).find((ref) => ref.label === label); if (!release) throw new PrismicError(`Release with label "${label}" could not be found.`, void 0, void 0); return release; } /** * Fetches the repository's page tags. * * @example * * ```ts * const tags = await client.getTags() * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#gettags} */ async getTags(params) { const repository = await this.getRepository(params); const form = repository.forms.tags; if (form) { const url = new URL(form.action); if (this.accessToken) url.searchParams.set("access_token", this.accessToken); const response = await this.#request(url, params); if (response.ok) return await response.json(); } return repository.tags; } /** * Builds a Content API query URL with a set of parameters. * * @example * * ```ts * const url = await client.buildQueryURL({ * filters: [filter.at("document.type", "blog_post")], * }) * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#buildqueryurl} */ async buildQueryURL({ signal, fetchOptions,...params } = {}) { const ref = params.ref || await this.#getResolvedRef({ accessToken: params.accessToken, signal, fetchOptions }); const integrationFieldsRef = params.integrationFieldsRef || (await this.getRepository({ accessToken: params.accessToken, signal, fetchOptions })).integrationFieldsRef || void 0; return buildQueryURL(this.documentAPIEndpoint, { ...this.defaultParams, ...params, ref, integrationFieldsRef, routes: params.routes || this.routes, brokenRoute: params.brokenRoute || this.brokenRoute, accessToken: params.accessToken || this.accessToken }); } /** * Fetches a previewed page's URL using a preview token and page ID. * * @example * * ```ts * const url = await client.resolvePreviewURL({ * linkResolver, * defaultURL: "/", * }) * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#resolvepreviewurl} */ async resolvePreviewURL(args) { let documentID = args.documentID; let previewToken = args.previewToken; if (typeof globalThis.location !== "undefined") { const searchParams = new URLSearchParams(globalThis.location.search); documentID = documentID || searchParams.get("documentId"); previewToken = previewToken || searchParams.get("token"); } else if (this.#autoPreviewsRequest) { if ("query" in this.#autoPreviewsRequest) { var _this$autoPreviewsReq, _this$autoPreviewsReq2; documentID = documentID || ((_this$autoPreviewsReq = this.#autoPreviewsRequest.query) === null || _this$autoPreviewsReq === void 0 ? void 0 : _this$autoPreviewsReq.documentId); previewToken = previewToken || ((_this$autoPreviewsReq2 = this.#autoPreviewsRequest.query) === null || _this$autoPreviewsReq2 === void 0 ? void 0 : _this$autoPreviewsReq2.token); } else if ("url" in this.#autoPreviewsRequest && this.#autoPreviewsRequest.url) { const searchParams = new URL(this.#autoPreviewsRequest.url, "missing-host://").searchParams; documentID = documentID || searchParams.get("documentId"); previewToken = previewToken || searchParams.get("token"); } } if (documentID != null && previewToken != null) { const url = asLink(await this.getByID(documentID, { ref: previewToken, lang: "*", signal: args.signal, fetchOptions: args.fetchOptions }), { linkResolver: args.linkResolver }); if (typeof url === "string") return url; } return args.defaultURL; } /** * Configures the client to query the latest published content. This is the * client's default mode. * * @example * * ```ts * client.queryLatestContent() * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#querylatestcontent} */ queryLatestContent() { this.#getRef = void 0; } /** * Configures the client to query content from a release with a specific ID. * * @example * * ```ts * client.queryContentFromReleaseByID("YhE3YhEAACIA4321") * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#querycontentfromreleasebyid} */ queryContentFromReleaseByID(id) { this.#getRef = async (params) => { return (await this.getReleaseByID(id, params)).ref; }; } /** * Configures the client to query content from a release with a specific * label. * * @example * * ```ts * client.queryContentFromReleaseByLabel("My Release") * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#querycontentfromreleasebylabel} */ queryContentFromReleaseByLabel(label) { this.#getRef = async (params) => { return (await this.getReleaseByLabel(label, params)).ref; }; } /** * Configures the client to query content from a specific ref. * * @example * * ```ts * client.queryContentFromRef("my-ref") * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#querycontentfromref} */ queryContentFromRef(ref) { this.#getRef = typeof ref === "string" ? () => ref : ref; } /** * A preconfigured `fetch()` function for Prismic's GraphQL API that can be * provided to GraphQL clients. * * @example * * ```ts * import { createClient, getGraphQLEndpoint } from "@prismicio/client" * * const client = createClient("example-prismic-repo") * const graphQLClient = new ApolloClient({ * link: new HttpLink({ * uri: getGraphQLEndpoint(client.repositoryName), * // Provide `client.graphQLFetch` as the fetch implementation. * fetch: client.graphQLFetch, * // Using GET is required. * useGETForQueries: true, * }), * cache: new InMemoryCache(), * }) * ``` * * @see {@link https://prismic.io/docs/technical-reference/prismicio-client/v7#graphqlfetch} */ async graphQLFetch(input, init) { const params = { accessToken: this.accessToken, fetchOptions: this.fetchOptions }; const repository = await this.getRepository(params); const ref = await this.#getResolvedRef(params); const headers = {}; headers["prismic-ref"] = ref; if (this.accessToken) headers["authorization"] = `Token ${this.accessToken}`; if (repository.integrationFieldsRef) headers["prismic-integration-field-ref"] = repository.integrationFieldsRef; for (const [key, value] of Object.entries((init === null || init === void 0 ? void 0 : init.headers) ?? {})) headers[key.toLowerCase()] = value; const url = new URL(typeof input === "string" ? input : input.url); const query = (url.searchParams.get("query") ?? "").replace(/(\n| )*( |{|})(\n| )*/gm, (_chars, _spaces, brackets) => brackets); url.searchParams.set("query", query); url.searchParams.set("ref", ref); return await this.fetchFn(url.toString(), { ...init, headers }); } /** * Returns the ref needed to query based on the client's current state. This * method may make a network request to fetch a ref or resolve the user's ref * thunk. * * If auto previews are enabled, the preview ref takes priority. * * The following strategies are used depending on the client's state: * * - If the user called `queryLatestContent`: Use the repository's master ref. * The ref is cached for 5 seconds. After 5 seconds, a new master ref is * fetched. * - If the user called `queryContentFromReleaseByID`: Use the release's ref. * The ref is cached for 5 seconds. After 5 seconds, a new ref for the * release is fetched. * - If the user called `queryContentFromReleaseByLabel`: Use the release's ref. * The ref is cached for 5 seconds. After 5 seconds, a new ref for the * release is fetched. * - If the user called `queryContentFromRef`: Use the provided ref. Fall back * to the master ref if the ref is not a string. */ async #getResolvedRef(params) { var _this$getRef; if (this.#autoPreviews) { var _this$autoPreviewsReq3, _globalThis$document; const previewRef = getPreviewCookie((((_this$autoPreviewsReq3 = this.#autoPreviewsRequest) === null || _this$autoPreviewsReq3 === void 0 ? void 0 : _this$autoPreviewsReq3.headers) ? "get" in this.#autoPreviewsRequest.headers ? this.#autoPreviewsRequest.headers.get("cookie") : this.#autoPreviewsRequest.headers.cookie : (_globalThis$document = globalThis.document) === null || _globalThis$document === void 0 ? void 0 : _globalThis$document.cookie) ?? ""); if (previewRef) return previewRef; } const ref = await ((_this$getRef = this.#getRef) === null || _this$getRef === void 0 ? void 0 : _this$getRef.call(this, params)); if (ref) return ref; return (await this.getMasterRef(params)).ref; } /** * Performs a low-level Content API request with the given parameters. * Automatically retries if an invalid ref is used. */ async #internalGet(params, attempt = 1) { const url = await this.buildQueryURL(params); const response = await this.#request(new URL(url), params); if (response.ok) return response; try { return await this.#throwContentAPIError(response, url); } catch (error) { if ((error instanceof RefNotFoundError || error instanceof RefExpiredError) && attempt < MAX_INVALID_REF_RETRY_ATTEMPTS) { var _error$message$match; if (!(params === null || params === void 0 ? void 0 : params.ref)) this.#cachedRepository = void 0; const masterRef = (_error$message$match = error.message.match(/master ref is: (?<ref>.*)$/i)) === null || _error$message$match === void 0 || (_error$message$match = _error$message$match.groups) === null || _error$message$match === void 0 ? void 0 : _error$message$match.ref; if (!masterRef) throw error; throttledWarn(`[@prismicio/client] The ref (${new URL(url).searchParams.get("ref")}) was ${error instanceof RefNotFoundError ? "invalid" : "expired"}. Now retrying with the latest master ref (${masterRef}). If you were previewing content, the response will not include draft content.`); return await this.#internalGet({ ...params, ref: masterRef }, attempt + 1); } throw error; } } /** * Throws an error based on a Content API response. Only call in known-errored * states. */ async #throwContentAPIError(response, url) { switch (response.status) { case 400: { const json = await response.clone().json(); throw new ParsingError(json.message, url, json); } case 401: { const json = await response.clone().json(); throw new ForbiddenError(json.message, url, json); } case 404: { const json = await response.clone().json(); switch (json.type) { case "api_notfound_error": throw new RefNotFoundError(json.message, url, json); case "api_security_error": if (/preview token.*expired/i.test(json.message)) throw new PreviewTokenExpiredError(json.message, url, json); default: throw new NotFoundError(json.message, url, json); } } case 410: { const json = await response.clone().json(); throw new RefExpiredError(json.message, url, json); } default: throw new PrismicError(void 0, url, await response.text()); } } /** Performs a low-level network request with the client's fetch options. */ async #request(url, params) { var _this$fetchOptions, _params$fetchOptions, _params$fetchOptions2, _this$fetchOptions2; return await request(url, { ...this.fetchOptions, ...params === null || params === void 0 ? void 0 : params.fetchOptions, headers: { ...(_this$fetchOptions = this.fetchOptions) === null || _this$fetchOptions === void 0 ? void 0 : _this$fetchOptions.headers, ...params === null || params === void 0 || (_params$fetchOptions = params.fetchOptions) === null || _params$fetchOptions === void 0 ? void 0 : _params$fetchOptions.headers }, signal: (params === null || params === void 0 || (_params$fetchOptions2 = params.fetchOptions) === null || _params$fetchOptions2 === void 0 ? void 0 : _params$fetchOptions2.signal) || (params === null || params === void 0 ? void 0 : params.signal) || ((_this$fetchOptions2 = this.fetchOptions) === null || _this$fetchOptions2 === void 0 ? void 0 : _this$fetchOptions2.signal) }, this.fetchFn); } }; /** Appends filters to a params object. */ function appendFilters(params = {}, ...filters) { return { ...params, filters: [...params.filters ?? [], ...filters] }; } //#endregion export { Client }; //# sourceMappingURL=Client.js.map