UNPKG

@prismicio/client

Version:

The official JavaScript + TypeScript client library for Prismic

506 lines (505 loc) 17.5 kB
"use strict"; var __defProp = Object.defineProperty; 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); Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const devMsg = require("./lib/devMsg.cjs"); const pLimit = require("./lib/pLimit.cjs"); const resolveMigrationDocumentData = require("./lib/resolveMigrationDocumentData.cjs"); const PrismicError = require("./errors/PrismicError.cjs"); const Client = require("./Client.cjs"); class WriteClient extends Client.Client { /** * Creates a Prismic client that can be used to query and write content to 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 repositoryName - The Prismic repository name for the repository. * @param options - Configuration that determines how content will be queried * from and written to the Prismic repository. * * @returns A client that can query and write content to the repository. */ constructor(repositoryName, options) { super(repositoryName, options); __publicField(this, "writeToken"); __publicField(this, "assetAPIEndpoint", "https://asset-api.prismic.io/"); __publicField(this, "migrationAPIEndpoint", "https://migration.prismic.io/"); /** * {@link resolveAssetTagIDs} rate limiter. */ __publicField(this, "_resolveAssetTagIDsLimit", pLimit.pLimit()); if (typeof globalThis.window !== "undefined") { console.warn(`[@prismicio/client] Prismic write client appears to be running in a browser environment. This is not recommended as it exposes your write token. Consider using Prismic write client in a server environment only, preferring the regular client for browser environment. For more details, see ${devMsg.devMsg("avoid-write-client-in-browser")}`); } this.writeToken = options.writeToken; if (options.assetAPIEndpoint) { this.assetAPIEndpoint = `${options.assetAPIEndpoint}/`; } if (options.migrationAPIEndpoint) { this.migrationAPIEndpoint = `${options.migrationAPIEndpoint}/`; } } /** * Creates a migration release on the Prismic repository based on the provided * prepared migration. * * @param migration - A migration prepared with {@link createMigration}. * @param params - An event listener and additional fetch parameters. * * @see Prismic Migration API technical reference: {@link https://prismic.io/docs/migration-api-technical-reference} */ async migrate(migration, params = {}) { var _a, _b; (_a = params.reporter) == null ? void 0 : _a.call(params, { type: "start", data: { pending: { documents: migration._documents.length, assets: migration._assets.size } } }); await this.migrateCreateAssets(migration, params); await this.migrateCreateDocuments(migration, params); await this.migrateUpdateDocuments(migration, params); (_b = params.reporter) == null ? void 0 : _b.call(params, { type: "end", data: { migrated: { documents: migration._documents.length, assets: migration._assets.size } } }); } /** * Creates assets in the Prismic repository's media library. * * @param migration - A migration prepared with {@link createMigration}. * @param params - An event listener and additional fetch parameters. * * @internal This method is one of the step performed by the {@link migrate} method. */ async migrateCreateAssets(migration, { reporter, ...fetchParams } = {}) { let created = 0; for (const [_, migrationAsset] of migration._assets) { reporter == null ? void 0 : reporter({ type: "assets:creating", data: { current: ++created, remaining: migration._assets.size - created, total: migration._assets.size, asset: migrationAsset } }); const { file, filename, notes, credits, alt, tags } = migrationAsset.config; let resolvedFile; if (typeof file === "string") { let url; try { url = new URL(file); } catch (error) { } if (url) { resolvedFile = await this.fetchForeignAsset(url.toString(), fetchParams); } else { resolvedFile = file; } } else if (file instanceof URL) { resolvedFile = await this.fetchForeignAsset(file.toString(), fetchParams); } else { resolvedFile = file; } const asset = await this.createAsset(resolvedFile, filename, { ...{ notes, credits, alt, tags }, ...fetchParams }); migrationAsset.asset = asset; } reporter == null ? void 0 : reporter({ type: "assets:created", data: { created } }); } /** * Creates documents in the Prismic repository's migration release. * * @param migration - A migration prepared with {@link createMigration}. * @param params - An event listener and additional fetch parameters. * * @internal This method is one of the step performed by the {@link migrate} method. */ async migrateCreateDocuments(migration, { reporter, ...fetchParams } = {}) { var _a, _b; const repository = await this.getRepository(fetchParams); const masterLocale = repository.languages.find((lang) => lang.is_master).id; reporter == null ? void 0 : reporter({ type: "documents:masterLocale", data: { masterLocale } }); const documentsToCreate = []; for (const doc of migration._documents) { if (!doc.document.id) { if (doc.document.lang === masterLocale) { documentsToCreate.unshift(doc); } else { documentsToCreate.push(doc); } } } let created = 0; for (const doc of documentsToCreate) { reporter == null ? void 0 : reporter({ type: "documents:creating", data: { current: ++created, remaining: documentsToCreate.length - created, total: documentsToCreate.length, document: doc } }); let masterLanguageDocumentID; if (doc.masterLanguageDocument) { const masterLanguageDocument = await resolveMigrationDocumentData.resolveMigrationContentRelationship(doc.masterLanguageDocument); masterLanguageDocumentID = "id" in masterLanguageDocument ? masterLanguageDocument.id : void 0; } else if (doc.originalPrismicDocument) { const maybeOriginalID = (_a = doc.originalPrismicDocument.alternate_languages.find(({ lang }) => lang === masterLocale)) == null ? void 0 : _a.id; if (maybeOriginalID) { masterLanguageDocumentID = (_b = migration._getByOriginalID(maybeOriginalID)) == null ? void 0 : _b.document.id; } } const { id } = await this.createDocument( // We'll upload documents data later on. { ...doc.document, data: {} }, doc.title, { masterLanguageDocumentID, ...fetchParams } ); doc.document.id = id; } reporter == null ? void 0 : reporter({ type: "documents:created", data: { created } }); } /** * Updates documents in the Prismic repository's migration release with their * patched data. * * @param migration - A migration prepared with {@link createMigration}. * @param params - An event listener and additional fetch parameters. * * @internal This method is one of the step performed by the {@link migrate} method. */ async migrateUpdateDocuments(migration, { reporter, ...fetchParams } = {}) { let i = 0; for (const doc of migration._documents) { reporter == null ? void 0 : reporter({ type: "documents:updating", data: { current: ++i, remaining: migration._documents.length - i, total: migration._documents.length, document: doc } }); await this.updateDocument( doc.document.id, // We need to forward again document name and tags to update them // in case the document already existed during the previous step. { ...doc.document, documentTitle: doc.title, data: await resolveMigrationDocumentData.resolveMigrationDocumentData(doc.document.data, migration) }, fetchParams ); } reporter == null ? void 0 : reporter({ type: "documents:updated", data: { updated: migration._documents.length } }); } /** * Creates an asset in the Prismic media library. * * @param file - The file to upload as an asset. * @param filename - The filename of the asset. * @param params - Additional asset data and fetch parameters. * * @returns The created asset. */ async createAsset(file, filename, { notes, credits, alt, tags, ...params } = {}) { const url = new URL("assets", this.assetAPIEndpoint); const formData = new FormData(); formData.append("file", new File([file], filename, { type: file instanceof File ? file.type : void 0 })); if (notes) { formData.append("notes", notes); } if (credits) { formData.append("credits", credits); } if (alt) { formData.append("alt", alt); } const asset = await this.fetch(url.toString(), this.buildAssetAPIQueryParams({ method: "POST", body: formData, params })); if (tags && tags.length) { return this.updateAsset(asset.id, { tags }); } return asset; } /** * Updates an asset in the Prismic media library. * * @param id - The ID of the asset to update. * @param params - The asset data to update and additional fetch parameters. * * @returns The updated asset. */ async updateAsset(id, { notes, credits, alt, filename, tags, ...params } = {}) { const url = new URL(`assets/${id}`, this.assetAPIEndpoint); if (tags && tags.length) { tags = await this.resolveAssetTagIDs(tags, { createTags: true, ...params }); } return this.fetch(url.toString(), this.buildAssetAPIQueryParams({ method: "PATCH", body: { notes, credits, alt, filename, tags }, params })); } /** * Fetches a foreign asset from a URL. * * @param url - The URL of the asset to fetch. * @param params - Additional fetch parameters. * * @returns A file representing the fetched asset. */ async fetchForeignAsset(url, params = {}) { var _a, _b, _c, _d; const requestInit = { ...this.fetchOptions, ...params.fetchOptions, headers: { ...(_a = this.fetchOptions) == null ? void 0 : _a.headers, ...(_b = params.fetchOptions) == null ? void 0 : _b.headers }, signal: ((_c = params.fetchOptions) == null ? void 0 : _c.signal) || params.signal || ((_d = this.fetchOptions) == null ? void 0 : _d.signal) }; const res = await this.fetchFn(url, requestInit); if (!res.ok) { throw new PrismicError.PrismicError("Could not fetch foreign asset", url, void 0); } const blob = await res.blob(); return new File([blob], "", { type: res.headers.get("content-type") || void 0 }); } /** * Resolves asset tag IDs from tag names. * * @param tagNames - An array of tag names to resolve. * @param params - Whether or not missing tags should be created and * additional fetch parameters. * * @returns An array of resolved tag IDs. */ async resolveAssetTagIDs(tagNames = [], { createTags, ...params } = {}) { return this._resolveAssetTagIDsLimit(async () => { const existingTags = await this.getAssetTags(params); const existingTagMap = {}; for (const tag of existingTags) { existingTagMap[tag.name] = tag; } const resolvedTagIDs = []; for (const tagName of tagNames) { if (!existingTagMap[tagName] && createTags) { existingTagMap[tagName] = await this.createAssetTag(tagName, params); } if (existingTagMap[tagName]) { resolvedTagIDs.push(existingTagMap[tagName].id); } } return resolvedTagIDs; }); } /** * Creates a tag in the Asset API. * * @remarks * Tags should be at least 3 characters long and 20 characters at most. * * @param name - The name of the tag to create. * @param params - Additional fetch parameters. * * @returns The created tag. */ async createAssetTag(name, params) { const url = new URL("tags", this.assetAPIEndpoint); return this.fetch(url.toString(), this.buildAssetAPIQueryParams({ method: "POST", body: { name }, params })); } /** * Queries existing tags from the Asset API. * * @param params - Additional fetch parameters. * * @returns An array of existing tags. */ async getAssetTags(params) { const url = new URL("tags", this.assetAPIEndpoint); const { items } = await this.fetch(url.toString(), this.buildAssetAPIQueryParams({ params })); return items; } /** * Creates a document in the repository's migration release. * * @typeParam TType - Type of Prismic documents to create. * * @param document - The document to create. * @param documentTitle - The title of the document to create which will be * displayed in the editor. * @param params - Document master language document ID and additional fetch * parameters. * * @returns The ID of the created document. * * @see Prismic Migration API technical reference: {@link https://prismic.io/docs/migration-api-technical-reference} */ async createDocument(document, documentTitle, { masterLanguageDocumentID, ...params } = {}) { const url = new URL("documents", this.migrationAPIEndpoint); const result = await this.fetch(url.toString(), this.buildMigrationAPIQueryParams({ method: "POST", body: { title: documentTitle, type: document.type, uid: document.uid || void 0, lang: document.lang, alternate_language_id: masterLanguageDocumentID, tags: document.tags, data: document.data }, params })); return { id: result.id }; } /** * Updates an existing document in the repository's migration release. * * @typeParam TType - Type of Prismic documents to update. * * @param id - The ID of the document to update. * @param document - The document content to update. * @param params - Additional fetch parameters. * * @see Prismic Migration API technical reference: {@link https://prismic.io/docs/migration-api-technical-reference} */ async updateDocument(id, document, params) { const url = new URL(`documents/${id}`, this.migrationAPIEndpoint); await this.fetch(url.toString(), this.buildMigrationAPIQueryParams({ method: "PUT", body: { title: document.documentTitle, uid: document.uid || void 0, tags: document.tags, data: document.data }, params })); } /** * Builds fetch parameters for the Asset API. * * @typeParam TBody - Type of the body to send in the fetch request. * * @param params - Method, body, and additional fetch parameters. * * @returns An object that can be fetched to interact with the Asset API. * * @see Prismic Asset API technical reference: {@link https://prismic.io/docs/asset-api-technical-reference} */ buildAssetAPIQueryParams({ method, body, params }) { var _a; const headers = { ...(_a = params == null ? void 0 : params.fetchOptions) == null ? void 0 : _a.headers, authorization: `Bearer ${this.writeToken}`, repository: this.repositoryName }; let _body; if (body instanceof FormData) { _body = body; } else if (body) { _body = JSON.stringify(body); headers["content-type"] = "application/json"; } return { ...params, fetchOptions: { ...params == null ? void 0 : params.fetchOptions, method, body: _body, headers } }; } /** * Builds fetch parameters for the Migration API. * * @typeParam TBody - Type of the body to send in the fetch request. * * @param params - Method, body, and additional fetch options. * * @returns An object that can be fetched to interact with the Migration API. * * @see Prismic Migration API technical reference: {@link https://prismic.io/docs/migration-api-technical-reference} */ buildMigrationAPIQueryParams({ method, body, params }) { var _a; return { ...params, fetchOptions: { ...params == null ? void 0 : params.fetchOptions, method, body: JSON.stringify(body), headers: { ...(_a = params == null ? void 0 : params.fetchOptions) == null ? void 0 : _a.headers, "content-type": "application/json", repository: this.repositoryName, authorization: `Bearer ${this.writeToken}` } } }; } } exports.WriteClient = WriteClient; //# sourceMappingURL=WriteClient.cjs.map