UNPKG

@prismicio/client

Version:

The official JavaScript + TypeScript client library for Prismic

1,259 lines (1,258 loc) 44.9 kB
var __defProp = Object.defineProperty; var __typeError = (msg) => { throw TypeError(msg); }; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)); var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value); var _repositoryName; import { appendFilters } from "./lib/appendFilters.js"; import { castThunk } from "./lib/castThunk.js"; import { devMsg } from "./lib/devMsg.js"; import { everyTagFilter } from "./lib/everyTagFilter.js"; import { findMasterRef } from "./lib/findMasterRef.js"; import { findRefByID } from "./lib/findRefByID.js"; import { findRefByLabel } from "./lib/findRefByLabel.js"; import { getPreviewCookie } from "./lib/getPreviewCookie.js"; import { minifyGraphQLQuery } from "./lib/minifyGraphQLQuery.js"; import { someTagsFilter } from "./lib/someTagsFilter.js"; import { throttledLog } from "./lib/throttledLog.js"; import { typeFilter } from "./lib/typeFilter.js"; import { ForbiddenError } from "./errors/ForbiddenError.js"; import { NotFoundError } from "./errors/NotFoundError.js"; import { ParsingError } from "./errors/ParsingError.js"; import { PreviewTokenExpiredError } from "./errors/PreviewTokenExpired.js"; import { PrismicError } from "./errors/PrismicError.js"; import { RefExpiredError } from "./errors/RefExpiredError.js"; import { RefNotFoundError } from "./errors/RefNotFoundError.js"; import { RepositoryNotFoundError } from "./errors/RepositoryNotFoundError.js"; import { asLink } from "./helpers/asLink.js"; import { BaseClient } from "./BaseClient.js"; import { buildQueryURL } from "./buildQueryURL.js"; import { filter } from "./filter.js"; import { getRepositoryEndpoint } from "./getRepositoryEndpoint.js"; import { getRepositoryName } from "./getRepositoryName.js"; import { isRepositoryEndpoint } from "./isRepositoryEndpoint.js"; const MAX_PAGE_SIZE = 100; const REPOSITORY_CACHE_TTL = 5e3; const GET_ALL_QUERY_DELAY = 500; const DEFAULT_RETRY_AFTER_MS = 1e3; const MAX_INVALID_REF_RETRY_ATTEMPTS = 3; var RefStateMode; (function(RefStateMode2) { RefStateMode2["Master"] = "Master"; RefStateMode2["ReleaseID"] = "ReleaseID"; RefStateMode2["ReleaseLabel"] = "ReleaseLabel"; RefStateMode2["Manual"] = "Manual"; })(RefStateMode || (RefStateMode = {})); class Client extends BaseClient { /** * Creates a Prismic client that can be used to query a repository. * * If used in an environment where a global `fetch` function is unavailable, * such as in some Node.js versions, the `fetch` option must be provided as * part of the `options` parameter. * * @param repositoryNameOrEndpoint - The Prismic repository name or full Rest * API V2 endpoint for the repository. * @param options - Configuration that determines how content will be queried * from the Prismic repository. * * @returns A client that can query content from the repository. */ constructor(repositoryNameOrEndpoint, options = {}) { super(options); __privateAdd(this, _repositoryName); /** * The Prismic REST API V2 endpoint for the repository (use * `prismic.getRepositoryEndpoint` for the default endpoint). */ __publicField(this, "documentAPIEndpoint"); /** * The secure token for accessing the API (only needed if your repository is * set to private). * * {@link https://user-guides.prismic.io/en/articles/1036153-generating-an-access-token} */ __publicField(this, "accessToken"); /** * A list of route resolver objects that define how a document's `url` field * is resolved. * * {@link https://prismic.io/docs/route-resolver} */ __publicField(this, "routes"); /** * The `brokenRoute` option allows you to define the route populated in the * `url` property for broken link or content relationship fields. A broken * link is a link or content relationship field whose linked document has been * unpublished or deleted. * * {@link https://prismic.io/docs/route-resolver} */ __publicField(this, "brokenRoute"); /** * Default parameters that will be sent with each query. These parameters can * be overridden on each query if needed. */ __publicField(this, "defaultParams"); /** * The client's ref mode state. This determines which ref is used during * queries. */ __publicField(this, "refState", { mode: RefStateMode.Master, autoPreviewsEnabled: true }); /** * Cached repository value. */ __publicField(this, "cachedRepository"); /** * Timestamp at which the cached repository data is considered stale. */ __publicField(this, "cachedRepositoryExpiration", 0); if ((options.documentAPIEndpoint || isRepositoryEndpoint(repositoryNameOrEndpoint)) && process.env.NODE_ENV === "development") { const documentAPIEndpoint = options.documentAPIEndpoint || repositoryNameOrEndpoint; if (/\.prismic\.io\/(?!api\/v2\/?)/i.test(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); } const hostname = new URL(documentAPIEndpoint).hostname.toLowerCase(); if (hostname.endsWith(".prismic.io") && !hostname.endsWith(".cdn.prismic.io")) { 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")}`); } if (options.documentAPIEndpoint && isRepositoryEndpoint(repositoryNameOrEndpoint) && repositoryNameOrEndpoint !== options.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 (isRepositoryEndpoint(repositoryNameOrEndpoint)) { this.documentAPIEndpoint = repositoryNameOrEndpoint; try { this.repositoryName = getRepositoryName(repositoryNameOrEndpoint); } catch (error) { 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")}`); } } else { this.documentAPIEndpoint = options.documentAPIEndpoint || getRepositoryEndpoint(repositoryNameOrEndpoint); this.repositoryName = repositoryNameOrEndpoint; } this.accessToken = options.accessToken; this.routes = options.routes; this.brokenRoute = options.brokenRoute; this.defaultParams = options.defaultParams; if (options.ref) { this.queryContentFromRef(options.ref); } this.graphQLFetch = this.graphQLFetch.bind(this); } /** * The Prismic repository's name. */ set repositoryName(value) { __privateSet(this, _repositoryName, value); } /** * The Prismic repository's name. */ get repositoryName() { if (!__privateGet(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 __privateGet(this, _repositoryName); } /** * The Prismic REST API V2 endpoint for the repository (use * `prismic.getRepositoryEndpoint` for the default endpoint). * * @deprecated Use `documentAPIEndpoint` instead. */ // TODO: Remove in v8. set endpoint(value) { this.documentAPIEndpoint = value; } /** * The Prismic REST API V2 endpoint for the repository (use * `prismic.getRepositoryEndpoint` for the default endpoint). * * @deprecated Use `documentAPIEndpoint` instead. */ // TODO: Remove in v8. get endpoint() { return this.documentAPIEndpoint; } /** * Enables the client to automatically query content from a preview session if * one is active in browser environments. This is enabled by default in the * browser. * * For server environments, use `enableAutoPreviewsFromReq`. * * @example * * ```ts * client.enableAutoPreviews() * ``` * * @see enableAutoPreviewsFromReq */ enableAutoPreviews() { this.refState.autoPreviewsEnabled = true; } /** * Enables the client to automatically query content from a preview session if * one is active in server environments. This is disabled by default on the * server. * * For browser environments, use `enableAutoPreviews`. * * @example * * ```ts * // In an express app * app.get("/", function (req, res) { * client.enableAutoPreviewsFromReq(req) * }) * ``` * * @param req - An HTTP server request object containing the request's * cookies. */ enableAutoPreviewsFromReq(req) { this.refState.httpRequest = req; this.refState.autoPreviewsEnabled = true; } /** * Disables the client from automatically querying content from a preview * session if one is active. * * Automatic preview content querying is enabled by default unless this method * is called. * * @example * * ```ts * client.disableAutoPreviews() * ``` */ disableAutoPreviews() { this.refState.autoPreviewsEnabled = false; } /** * Queries content from the Prismic repository. * * @example * * ```ts * const response = await client.get() * ``` * * @typeParam TDocument - Type of Prismic documents returned. * * @param params - Parameters to filter, sort, and paginate results. * * @returns A paginated response containing the result of the query. */ async get(params) { const { data } = await this._get(params); return data; } /** * Queries content from the Prismic repository and returns only the first * result, if any. * * @example * * ```ts * const document = await client.getFirst() * ``` * * @typeParam TDocument - Type of the Prismic document returned. * * @param params - Parameters to filter, sort, and paginate results. * * @returns The first result of the query, if any. */ async getFirst(params) { var _a; const actualParams = { ...params }; if (!(params && params.page) && !(params == null ? void 0 : params.pageSize)) { actualParams.pageSize = ((_a = this.defaultParams) == null ? void 0 : _a.pageSize) ?? 1; } const { data, url } = await this._get(actualParams); const firstResult = data.results[0]; if (firstResult) { return firstResult; } throw new NotFoundError("No documents were returned", url, void 0); } /** * **IMPORTANT**: Avoid using `dangerouslyGetAll` as it may be slower and * require more resources than other methods. Prefer using other methods that * filter by filters such as `getAllByType`. * * Queries content from the Prismic repository and returns all matching * content. If no filters are provided, all documents will be fetched. * * This method may make multiple network requests to query all matching * content. * * @example * * ```ts * const response = await client.dangerouslyGetAll() * ``` * * @typeParam TDocument - Type of Prismic documents returned. * * @param params - Parameters to filter, sort, and paginate results. * * @returns A list of documents matching the query. */ async dangerouslyGetAll(params = {}) { var _a; const { limit = Infinity, ...actualParams } = params; const resolvedParams = { ...actualParams, pageSize: Math.min(limit, actualParams.pageSize || ((_a = this.defaultParams) == null ? void 0 : _a.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); } /** * Queries a document from the Prismic repository with a specific ID. * * @remarks * A document's UID is different from its ID. An ID is automatically generated * for all documents and is made available on its `id` property. A UID is * provided in the Prismic editor and is unique among all documents of its * custom type. * * @example * * ```ts * const document = await client.getByID("WW4bKScAAMAqmluX") * ``` * * @typeParam TDocument- Type of the Prismic document returned. * * @param id - ID of the document. * @param params - Parameters to filter, sort, and paginate the results. * * @returns The document with an ID matching the `id` parameter, if a matching * document exists. */ async getByID(id, params) { return await this.getFirst(appendFilters(params, filter.at("document.id", id))); } /** * Queries documents from the Prismic repository with specific IDs. * * @remarks * A document's UID is different from its ID. An ID is automatically generated * for all documents and is made available on its `id` property. A UID is * provided in the Prismic editor and is unique among all documents of its * custom type. * * @example * * ```ts * const response = await client.getByIDs([ * "WW4bKScAAMAqmluX", * "U1kTRgEAAC8A5ldS", * ]) * ``` * * @typeParam TDocument - Type of Prismic documents returned. * * @param ids - A list of document IDs. * @param params - Parameters to filter, sort, and paginate the results. * * @returns A paginated response containing documents with IDs matching the * `ids` parameter. */ async getByIDs(ids, params) { return await this.get(appendFilters(params, filter.in("document.id", ids))); } /** * Queries all documents from the Prismic repository with specific IDs. * * This method may make multiple network requests to query all matching * content. * * @remarks * A document's UID is different from its ID. An ID is automatically generated * for all documents and is made available on its `id` property. A UID is * provided in the Prismic editor and is unique among all documents of its * custom type. * * @example * * ```ts * const response = await client.getAllByIDs([ * "WW4bKScAAMAqmluX", * "U1kTRgEAAC8A5ldS", * ]) * ``` * * @typeParam TDocument - Type of Prismic documents returned. * * @param ids - A list of document IDs. * @param params - Parameters to filter, sort, and paginate the results. * * @returns A list of documents with IDs matching the `ids` parameter. */ async getAllByIDs(ids, params) { return await this.dangerouslyGetAll(appendFilters(params, filter.in("document.id", ids))); } /** * Queries a document from the Prismic repository with a specific UID and * custom type. * * @remarks * A document's UID is different from its ID. An ID is automatically generated * for all documents and is made available on its `id` property. A UID is * provided in the Prismic editor and is unique among all documents of its * custom type. * * @example * * ```ts * const document = await client.getByUID("blog_post", "my-first-post") * ``` * * @typeParam TDocument - Type of the Prismic document returned. * * @param documentType - The API ID of the document's custom type. * @param uid - UID of the document. * @param params - Parameters to filter, sort, and paginate the results. * * @returns The document with a UID matching the `uid` parameter, if a * matching document exists. */ async getByUID(documentType, uid, params) { return await this.getFirst(appendFilters(params, [ typeFilter(documentType), filter.at(`my.${documentType}.uid`, uid) ])); } /** * Queries document from the Prismic repository with specific UIDs and Custom * Type. * * @remarks * A document's UID is different from its ID. An ID is automatically generated * for all documents and is made available on its `id` property. A UID is * provided in the Prismic editor and is unique among all documents of its * custom type. * * @example * * ```ts * const document = await client.getByUIDs("blog_post", [ * "my-first-post", * "my-second-post", * ]) * ``` * * @typeParam TDocument - Type of the Prismic document returned. * * @param documentType - The API ID of the document's custom type. * @param uids - A list of document UIDs. * @param params - Parameters to filter, sort, and paginate the results. * * @returns A paginated response containing documents with UIDs matching the * `uids` parameter. */ async getByUIDs(documentType, uids, params) { return await this.get(appendFilters(params, [ typeFilter(documentType), filter.in(`my.${documentType}.uid`, uids) ])); } /** * Queries all documents from the Prismic repository with specific UIDs and * custom type. * * This method may make multiple network requests to query all matching * content. * * @remarks * A document's UID is different from its ID. An ID is automatically generated * for all documents and is made available on its `id` property. A UID is * provided in the Prismic editor and is unique among all documents of its * custom type. * * @example * * ```ts * const response = await client.getAllByUIDs([ * "my-first-post", * "my-second-post", * ]) * ``` * * @typeParam TDocument - Type of Prismic documents returned. * * @param documentType - The API ID of the document's custom type. * @param uids - A list of document UIDs. * @param params - Parameters to filter, sort, and paginate the results. * * @returns A list of documents with UIDs matching the `uids` parameter. */ async getAllByUIDs(documentType, uids, params) { return await this.dangerouslyGetAll(appendFilters(params, [ typeFilter(documentType), filter.in(`my.${documentType}.uid`, uids) ])); } /** * Queries a singleton document from the Prismic repository for a specific * custom type. * * @remarks * A singleton document is one that is configured in Prismic to only allow one * instance. For example, a repository may be configured to contain just one * Settings document. This is in contrast to a repeatable custom type which * allows multiple instances of itself. * * @example * * ```ts * const document = await client.getSingle("settings") * ``` * * @typeParam TDocument - Type of the Prismic document returned. * * @param documentType - The API ID of the singleton custom type. * @param params - Parameters to filter, sort, and paginate the results. * * @returns The singleton document for the custom type, if a matching document * exists. */ async getSingle(documentType, params) { return await this.getFirst(appendFilters(params, typeFilter(documentType))); } /** * Queries documents from the Prismic repository for a specific custom type. * * Use `getAllByType` instead if you need to query all documents for a * specific custom type. * * @example * * ```ts * const response = await client.getByType("blog_post") * ``` * * @typeParam TDocument - Type of Prismic documents returned. * * @param documentType - The API ID of the custom type. * @param params - Parameters to filter, sort, and paginate the results. * * @returns A paginated response containing documents of the custom type. */ async getByType(documentType, params) { return await this.get(appendFilters(params, typeFilter(documentType))); } /** * Queries all documents from the Prismic repository for a specific Custom * Type. * * This method may make multiple network requests to query all matching * content. * * @example * * ```ts * const response = await client.getByType("blog_post") * ``` * * @typeParam TDocument - Type of Prismic documents returned. * * @param documentType - The API ID of the custom type. * @param params - Parameters to filter, sort, and paginate the results. * * @returns A list of all documents of the custom type. */ async getAllByType(documentType, params) { return await this.dangerouslyGetAll(appendFilters(params, typeFilter(documentType))); } /** * Queries documents from the Prismic repository with a specific tag. * * Use `getAllByTag` instead if you need to query all documents with a * specific tag. * * @example * * ```ts * const response = await client.getByTag("food") * ``` * * @typeParam TDocument - Type of Prismic documents returned. * * @param tag - The tag that must be included on a document. * @param params - Parameters to filter, sort, and paginate the results. * * @returns A paginated response containing documents with the tag. */ async getByTag(tag, params) { return await this.get(appendFilters(params, someTagsFilter(tag))); } /** * Queries all documents from the Prismic repository with a specific tag. * * This method may make multiple network requests to query all matching * content. * * @example * * ```ts * const response = await client.getAllByTag("food") * ``` * * @typeParam TDocument - Type of Prismic documents returned. * * @param tag - The tag that must be included on a document. * @param params - Parameters to filter, sort, and paginate the results. * * @returns A list of all documents with the tag. */ async getAllByTag(tag, params) { return await this.dangerouslyGetAll(appendFilters(params, someTagsFilter(tag))); } /** * Queries documents from the Prismic repository with specific tags. A * document must be tagged with all of the queried tags to be included. * * @example * * ```ts * const response = await client.getByEveryTag(["food", "fruit"]) * ``` * * @typeParam TDocument - Type of Prismic documents returned. * * @param tags - A list of tags that must be included on a document. * @param params - Parameters to filter, sort, and paginate the results. * * @returns A paginated response containing documents with the tags. */ async getByEveryTag(tags, params) { return await this.get(appendFilters(params, everyTagFilter(tags))); } /** * Queries documents from the Prismic repository with specific tags. A * document must be tagged with all of the queried tags to be included. * * This method may make multiple network requests to query all matching * content. * * @example * * ```ts * const response = await client.getAllByEveryTag(["food", "fruit"]) * ``` * * @typeParam TDocument - Type of Prismic documents returned. * * @param tags - A list of tags that must be included on a document. * @param params - Parameters to filter, sort, and paginate the results. * * @returns A list of all documents with the tags. */ async getAllByEveryTag(tags, params) { return await this.dangerouslyGetAll(appendFilters(params, everyTagFilter(tags))); } /** * Queries documents from the Prismic repository with specific tags. A * document must be tagged with at least one of the queried tags to be * included. * * @example * * ```ts * const response = await client.getByEveryTag(["food", "fruit"]) * ``` * * @typeParam TDocument - Type of Prismic documents returned. * * @param tags - A list of tags that must be included on a document. * @param params - Parameters to filter, sort, and paginate the results. * * @returns A paginated response containing documents with at least one of the * tags. */ async getBySomeTags(tags, params) { return await this.get(appendFilters(params, someTagsFilter(tags))); } /** * Queries documents from the Prismic repository with specific tags. A * document must be tagged with at least one of the queried tags to be * included. * * This method may make multiple network requests to query all matching * content. * * @example * * ```ts * const response = await client.getAllBySomeTags(["food", "fruit"]) * ``` * * @typeParam TDocument - Type of Prismic documents returned. * * @param tags - A list of tags that must be included on a document. * @param params - Parameters to filter, sort, and paginate the results. * * @returns A list of all documents with at least one of the tags. */ async getAllBySomeTags(tags, params) { return await this.dangerouslyGetAll(appendFilters(params, someTagsFilter(tags))); } /** * Returns metadata about the Prismic repository, such as its refs, releases, * and custom types. * * @returns Repository metadata. */ async getRepository(params) { const url = new URL(this.documentAPIEndpoint); if (this.accessToken) { url.searchParams.set("access_token", this.accessToken); } return await this.fetch(url.toString(), params); } /** * Returns a list of all refs for the Prismic repository. * * Refs are used to identify which version of the repository's content should * be queried. All repositories will have at least one ref pointing to the * latest published content called the "master ref". * * @returns A list of all refs for the Prismic repository. */ async getRefs(params) { const repository = await this.getRepository(params); return repository.refs; } /** * Returns a ref for the Prismic repository with a matching ID. * * @param id - ID of the ref. * * @returns The ref with a matching ID, if it exists. */ async getRefByID(id, params) { const refs = await this.getRefs(params); return findRefByID(refs, id); } /** * Returns a ref for the Prismic repository with a matching label. * * @param label - Label of the ref. * * @returns The ref with a matching label, if it exists. */ async getRefByLabel(label, params) { const refs = await this.getRefs(params); return findRefByLabel(refs, label); } /** * Returns the master ref for the Prismic repository. The master ref points to * the repository's latest published content. * * @returns The repository's master ref. */ async getMasterRef(params) { const refs = await this.getRefs(params); return findMasterRef(refs); } /** * Returns a list of all Releases for the Prismic repository. Releases are * used to group content changes before publishing. * * @returns A list of all Releases for the Prismic repository. */ async getReleases(params) { const refs = await this.getRefs(params); return refs.filter((ref) => !ref.isMasterRef); } /** * Returns a Release for the Prismic repository with a matching ID. * * @param id - ID of the Release. * * @returns The Release with a matching ID, if it exists. */ async getReleaseByID(id, params) { const releases = await this.getReleases(params); return findRefByID(releases, id); } /** * Returns a Release for the Prismic repository with a matching label. * * @param label - Label of the ref. * * @returns The ref with a matching label, if it exists. */ async getReleaseByLabel(label, params) { const releases = await this.getReleases(params); return findRefByLabel(releases, label); } /** * Returns a list of all tags used in the Prismic repository. * * @returns A list of all tags used in the repository. */ async getTags(params) { try { const tagsForm = await this.getCachedRepositoryForm("tags", params); const url = new URL(tagsForm.action); if (this.accessToken) { url.searchParams.set("access_token", this.accessToken); } return await this.fetch(url.toString(), params); } catch { const repository = await this.getRepository(params); return repository.tags; } } /** * Builds a URL used to query content from the Prismic repository. * * @param params - Parameters to filter, sort, and paginate the results. * * @returns A URL string that can be requested to query content. */ async buildQueryURL({ signal, fetchOptions, ...params } = {}) { const ref = params.ref || await this.getResolvedRefString({ signal, fetchOptions }); const integrationFieldsRef = params.integrationFieldsRef || (await this.getCachedRepository({ 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 }); } /** * Determines the URL for a previewed document during an active preview * session. The result of this method should be used to redirect the user to * the document's URL. * * @example * * ```ts * const url = client.resolvePreviewURL({ * linkResolver: (document) => `/${document.uid}` * defaultURL: '/' * }) * ``` * * @param args - Arguments to configure the URL resolving. * * @returns The URL for the previewed document during an active preview * session. The user should be redirected to this URL. */ async resolvePreviewURL(args) { var _a, _b; 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.refState.httpRequest) { if ("query" in this.refState.httpRequest) { documentID = documentID || ((_a = this.refState.httpRequest.query) == null ? void 0 : _a.documentId); previewToken = previewToken || ((_b = this.refState.httpRequest.query) == null ? void 0 : _b.token); } else if ("url" in this.refState.httpRequest && this.refState.httpRequest.url) { const searchParams = new URL(this.refState.httpRequest.url, "missing-host://").searchParams; documentID = documentID || searchParams.get("documentId"); previewToken = previewToken || searchParams.get("token"); } } if (documentID != null && previewToken != null) { const document = await this.getByID(documentID, { ref: previewToken, lang: "*", signal: args.signal, fetchOptions: args.fetchOptions }); const url = asLink(document, { linkResolver: args.linkResolver }); if (typeof url === "string") { return url; } } return args.defaultURL; } /** * Configures the client to query the latest published content for all future * queries. * * If the `ref` parameter is provided during a query, it takes priority for * that query. * * @example * * ```ts * await client.queryLatestContent() * const document = await client.getByID("WW4bKScAAMAqmluX") * ``` */ queryLatestContent() { this.refState.mode = RefStateMode.Master; } /** * Configures the client to query content from a specific Release identified * by its ID for all future queries. * * If the `ref` parameter is provided during a query, it takes priority for * that query. * * @example * * ```ts * await client.queryContentFromReleaseByID("YLB7OBAAACMA7Cpa") * const document = await client.getByID("WW4bKScAAMAqmluX") * ``` * * @param releaseID - The ID of the Release. */ queryContentFromReleaseByID(releaseID) { this.refState = { ...this.refState, mode: RefStateMode.ReleaseID, releaseID }; } /** * Configures the client to query content from a specific Release identified * by its label for all future queries. * * If the `ref` parameter is provided during a query, it takes priority for * that query. * * @example * * ```ts * await client.queryContentFromReleaseByLabel("My Release") * const document = await client.getByID("WW4bKScAAMAqmluX") * ``` * * @param releaseLabel - The label of the Release. */ queryContentFromReleaseByLabel(releaseLabel) { this.refState = { ...this.refState, mode: RefStateMode.ReleaseLabel, releaseLabel }; } /** * Configures the client to query content from a specific ref. The ref can be * provided as a string or a function. * * If a function is provided, the ref is fetched lazily before each query. The * function may also be asynchronous. * * @example * * ```ts * await client.queryContentFromRef("my-ref") * const document = await client.getByID("WW4bKScAAMAqmluX") * ``` * * @param ref - The ref or a function that returns the ref from which to query * content. */ queryContentFromRef(ref) { this.refState = { ...this.refState, mode: RefStateMode.Manual, ref }; } /** * A `fetch()` function to be used with GraphQL clients configured for * Prismic's GraphQL API. It automatically applies the necessary `prismic-ref` * and Authorization headers. Queries will automatically be minified by * removing whitespace where possible. * * @example * * ```ts * const graphQLClient = new ApolloClient({ * link: new HttpLink({ * uri: prismic.getGraphQLEndpoint(repositoryName), * // Provide `client.graphQLFetch` as the fetch implementation. * fetch: client.graphQLFetch, * // Using GET is required. * useGETForQueries: true, * }), * cache: new InMemoryCache(), * }) * ``` * * @param input - The `fetch()` `input` parameter. Only strings are supported. * @param init - The `fetch()` `init` parameter. Only plain objects are * supported. * * @returns The `fetch()` Response for the request. * * @experimental */ async graphQLFetch(input, init) { const cachedRepository = await this.getCachedRepository(); const ref = await this.getResolvedRefString(); const unsanitizedHeaders = { "Prismic-ref": ref, Authorization: this.accessToken ? `Token ${this.accessToken}` : "", // Asserting `init.headers` is a Record since popular GraphQL // libraries pass this as a Record. Header objects as input // are unsupported. ...init ? init.headers : {} }; if (cachedRepository.integrationFieldsRef) { unsanitizedHeaders["Prismic-integration-field-ref"] = cachedRepository.integrationFieldsRef; } const headers = {}; for (const key in unsanitizedHeaders) { if (unsanitizedHeaders[key]) { headers[key.toLowerCase()] = unsanitizedHeaders[key]; } } const url = new URL( // Asserting `input` is a string since popular GraphQL // libraries pass this as a string. Request objects as // input are unsupported. input ); url.searchParams.set("ref", ref); const query = url.searchParams.get("query"); if (query) { url.searchParams.set( "query", // Compress the GraphQL query (if it exists) by // removing whitespace. This is done to // optimize the query size and avoid // hitting the upper limit of GET requests // (2048 characters). minifyGraphQLQuery(query) ); } return await this.fetchFn(url.toString(), { ...init, headers }); } /** * Returns a cached version of `getRepository` with a TTL. * * @returns Cached repository metadata. */ async getCachedRepository(params) { if (!this.cachedRepository || Date.now() >= this.cachedRepositoryExpiration) { this.cachedRepositoryExpiration = Date.now() + REPOSITORY_CACHE_TTL; this.cachedRepository = await this.getRepository(params); } return this.cachedRepository; } /** * Returns a cached Prismic repository form. Forms are used to determine API * endpoints for types of repository data. * * @param name - Name of the form. * * @returns The repository form. * * @throws If a matching form cannot be found. */ async getCachedRepositoryForm(name, params) { const cachedRepository = await this.getCachedRepository(params); const form = cachedRepository.forms[name]; if (!form) { throw new PrismicError(`Form with name "${name}" could not be found`, void 0, void 0); } return form; } /** * 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 if available. * * 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. * * @returns The ref to use during a query. */ async getResolvedRefString(params) { var _a, _b; if (this.refState.autoPreviewsEnabled) { let previewRef; let cookieJar; if ((_a = this.refState.httpRequest) == null ? void 0 : _a.headers) { if ("get" in this.refState.httpRequest.headers && typeof this.refState.httpRequest.headers.get === "function") { cookieJar = this.refState.httpRequest.headers.get("cookie"); } else if ("cookie" in this.refState.httpRequest.headers) { cookieJar = this.refState.httpRequest.headers.cookie; } } else if ((_b = globalThis.document) == null ? void 0 : _b.cookie) { cookieJar = globalThis.document.cookie; } if (cookieJar) { previewRef = getPreviewCookie(cookieJar); } if (previewRef) { return previewRef; } } const cachedRepository = await this.getCachedRepository(params); const refModeType = this.refState.mode; if (refModeType === RefStateMode.ReleaseID) { return findRefByID(cachedRepository.refs, this.refState.releaseID).ref; } else if (refModeType === RefStateMode.ReleaseLabel) { return findRefByLabel(cachedRepository.refs, this.refState.releaseLabel).ref; } else if (refModeType === RefStateMode.Manual) { const res = await castThunk(this.refState.ref)(); if (typeof res === "string") { return res; } } return findMasterRef(cachedRepository.refs).ref; } /** * The private implementation of `this.get`. It returns the API response and * the URL used to make the request. The URL is sometimes used in the public * method to include in thrown errors. * * This method retries requests that throw `RefNotFoundError` or * `RefExpiredError`. It contains special logic to retry with the latest * master ref, provided in the API's error message. * * @typeParam TDocument - Type of Prismic documents returned. * * @param params - Parameters to filter, sort, and paginate results. * * @returns An object containing the paginated response containing the result * of the query and the URL used to make the API request. */ async _get(params, attemptCount = 0) { var _a, _b; const url = await this.buildQueryURL(params); try { const data = await this.fetch(url, params); return { data, url }; } catch (error) { if (!(error instanceof RefNotFoundError || error instanceof RefExpiredError) || attemptCount >= MAX_INVALID_REF_RETRY_ATTEMPTS - 1) { throw error; } if (!(params == null ? void 0 : params.ref)) { this.cachedRepository = void 0; } const masterRef = (_b = (_a = error.message.match(/Master ref is: (?<ref>.*)$/)) == null ? void 0 : _a.groups) == null ? void 0 : _b.ref; if (!masterRef) { throw error; } const badRef = new URL(url).searchParams.get("ref"); const issue = error instanceof RefNotFoundError ? "invalid" : "expired"; throttledLog(`[@prismicio/client] The ref (${badRef}) was ${issue}. Now retrying with the latest master ref (${masterRef}). If you were previewing content, the response will not include draft content.`, { level: "warn" }); return await this._get({ ...params, ref: masterRef }, attemptCount + 1); } } /** * Performs a network request using the configured `fetch` function. It * assumes all successful responses will have a JSON content type. It also * normalizes unsuccessful network requests. * * @typeParam T - The JSON response. * * @param url - URL to the resource to fetch. * @param params - Prismic REST API parameters for the network request. * * @returns The JSON response from the network request. */ async fetch(url, params = {}) { const res = await super.fetch(url, params); if (res.status !== 404 && res.status !== 429 && res.json == null) { throw new PrismicError(void 0, url, res.json || res.text); } switch (res.status) { case 200: case 201: { return res.json; } case 400: { throw new ParsingError(res.json.message, url, res.json); } case 401: case 403: { throw new ForbiddenError(res.json.error || res.json.message, url, res.json); } case 404: { if (res.json === void 0) { throw new RepositoryNotFoundError(`Prismic repository not found. Check that "${this.documentAPIEndpoint}" is pointing to the correct repository.`, url, url.startsWith(this.documentAPIEndpoint) ? void 0 : res.text); } if (res.json.type === "api_notfound_error") { throw new RefNotFoundError(res.json.message, url, res.json); } if (res.json.type === "api_security_error" && /preview token.*expired/i.test(res.json.message)) { throw new PreviewTokenExpiredError(res.json.message, url, res.json); } throw new NotFoundError(res.json.message, url, res.json); } case 410: { throw new RefExpiredError(res.json.message, url, res.json); } case 429: { const parsedRetryAfter = Number(res.headers.get("retry-after")); const delay = Number.isNaN(parsedRetryAfter) ? DEFAULT_RETRY_AFTER_MS : parsedRetryAfter * 1e3; return await new Promise((resolve, reject) => { setTimeout(async () => { try { resolve(await this.fetch(url, params)); } catch (error) { reject(error); } }, delay); }); } } throw new PrismicError(void 0, url, res.json); } } _repositoryName = new WeakMap(); export { Client, GET_ALL_QUERY_DELAY, REPOSITORY_CACHE_TTL }; //# sourceMappingURL=Client.js.map