@stackbit/cms-sanity
Version:
Stackbit Sanity CMS Interface
766 lines • 37.8 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SanityContentSource = void 0;
const lodash_1 = __importDefault(require("lodash"));
const https_1 = __importDefault(require("https"));
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const glob_1 = require("glob");
const types_1 = require("@stackbit/types");
const utils_1 = require("@stackbit/utils");
const fetcher = __importStar(require("./sanity-schema-fetcher"));
const sanity_api_client_1 = require("./sanity-api-client");
const sanity_schema_converter_1 = require("./sanity-schema-converter");
const sanity_document_converter_1 = require("./sanity-document-converter");
const utils_2 = require("./utils");
const sanity_operation_converter_1 = require("./sanity-operation-converter");
const ASSET_TYPES = ['sanity.imageAsset', 'cloudinary.asset', 'bynder.asset', 'aprimo.cdnasset'];
const SANITY_API_VERSION = '1';
class SanityContentSource {
constructor(options) {
this.userMap = {};
this.projectId = options.projectId;
this.dataset = options.dataset;
this.token = options.token;
this.studioUrl = options.studioUrl;
this.sanityQuery = options.sanityQuery || '*[!(_id in path("_.**"))]';
this.rootPath = options.rootPath;
this.studioPath = options.studioPath;
this.studioInstallCommand = options.studioInstallCommand;
this.schemaGlob = options.schemaGlob;
this.listenerVisibility = options.listenerVisibility;
this.defaultLocale = options.defaultLocale;
if (!this.rootPath) {
throw new Error(`Required parameter 'rootPath' is missing.`);
}
this.convertListenerResult = (0, utils_1.deferWhileRunning)(this.convertListenerResult, {
thisArg: this,
debounceDelay: 50,
debounceMaxDelay: 500,
argsResolver: ({ nextArgs, prevArgs }) => {
const [events] = nextArgs;
const [prevEvents] = prevArgs ?? [[]];
return [[...prevEvents, ...events].filter(Boolean)];
}
});
// Normalize paths to be absolute
this.studioPath = !this.studioPath || path_1.default.isAbsolute(this.studioPath) ? this.studioPath : path_1.default.join(this.rootPath, this.studioPath);
}
async getVersion() {
return (0, types_1.getVersion)({ packageJsonPath: path_1.default.join(__dirname, '../package.json') });
}
getContentSourceType() {
return 'sanity';
}
getProjectId() {
return `${this.projectId}:${this.dataset}`;
}
getProjectEnvironment() {
return this.dataset;
}
getProjectManageUrl() {
return this.studioUrl;
}
async init({ logger, userLogger, localDev, runCommand, userCommandSpawner, cache }) {
this.logger = logger.createLogger({ label: 'cms-sanity' });
this.userLogger = userLogger.createLogger({ label: 'cms-sanity' });
this.localDev = localDev;
this.runCommand = runCommand;
this.userCommandSpawner = userCommandSpawner;
this.cache = cache;
this.logger.debug('init', { localDev });
this.client = new sanity_api_client_1.SanityClient({
projectId: this.projectId,
dataset: this.dataset,
token: this.token,
useCdn: false,
apiVersion: SANITY_API_VERSION
});
await this.validateConfig();
if (!localDev) {
await this.installStudio();
}
await this.reset();
}
async reset() {
this.logger.debug('reset');
}
async destroy() {
this.logger.debug('destroy');
}
async validateConfig() {
this.logger.debug('Validating config...');
if (this.studioPath && !(await fs_extra_1.default.pathExists(this.studioPath))) {
throw new Error(`Can't find Sanity Studio in ${this.studioPath}. Verify that the studio path is pointing to the right place.`);
}
if (lodash_1.default.isEmpty(this.token)) {
throw new Error(`Please provide a Sanity token.`);
}
try {
await this.client.fetch(`*[_type == 'system.group'] {_id}`);
}
catch (err) {
if (err?.response?.body?.error === 'Dataset not found') {
throw new Error(`Can't find specified Sanity dataset '${this.dataset}'. Verify that the dataset is pointing to an existing Sanity dataset.`);
}
else {
throw new Error(`Can't connect to Sanity. Verify that the token has access to the Sanity project defined.`);
}
}
}
async installStudio() {
if (this.studioInstallCommand) {
this.userLogger.info('Installing Sanity Studio using custom command');
await this.runCommand(this.studioInstallCommand, [], {
shell: true,
cwd: this.studioPath ?? this.rootPath,
logger: this.userLogger.createLogger({ label: 'sanity-studio-install' })
});
}
else {
if (!this.studioPath || this.studioPath === this.rootPath) {
this.logger.debug('Studio path is the same as root path. Skipping studio installation.');
return;
}
const packageManager = await (0, utils_1.getPackageManager)(this.studioPath);
if (!packageManager) {
throw new Error("No package manager detected. Can't install Sanity Studio.");
}
this.userLogger.info(`Installing Sanity Studio using ${packageManager.name}`);
await this.runCommand(packageManager.cmd, packageManager.args, {
env: packageManager.env,
cwd: this.studioPath,
logger: this.userLogger.createLogger({ label: 'sanity-studio-install' })
});
}
}
startWatchingContentUpdates() {
this.logger.debug('startWatchingContentUpdates');
const createSanityListener = () => {
//TODO Sanity types for listener visibility are broken in this @sanity/client version
return this.client.listen(this.sanityQuery, {}, { visibility: this.listenerVisibility === 'query' ? 'query' : undefined }).subscribe({
next: async (event) => {
if (event.type !== 'mutation') {
return;
}
if (lodash_1.default.startsWith(event.documentId, '_.') || event.identity === '<system>' || lodash_1.default.startsWith(event.result?.resultType, 'system.')) {
return;
}
this.logger.debug('SanityListener: content changed', {
event: event?.transition,
transactionId: event?.transactionId,
eventId: event?.eventId,
documentId: event?.documentId
});
await this.convertListenerResult([event]).catch((err) => {
this.logger.error('SanityListener: convertListenerResult threw an error', err);
});
this.logger.debug('SanityListener: content changed handler done', {
event: event?.transition,
transactionId: event?.transactionId,
eventId: event?.eventId,
documentId: event?.documentId
});
},
error: (error) => {
this.logger.error('SanityListener: threw error', error);
},
complete: () => {
this.logger.debug('SanityListener: complete received');
}
});
};
if (this.contentChangeSubscription) {
this.stopWatchingContentUpdates();
}
this.contentChangeSubscription = createSanityListener();
this.contentChangeSubscriptionInterval = setInterval(() => {
const newListener = createSanityListener();
this.contentChangeSubscription.unsubscribe();
this.contentChangeSubscription = newListener;
}, 1000 * 60 * 20);
}
stopWatchingContentUpdates() {
this.logger.debug('stopWatchingContentUpdates');
if (this.contentChangeSubscription) {
this.logger.debug('stopping content change listener');
this.contentChangeSubscription.unsubscribe();
this.contentChangeSubscription = null;
clearInterval(this.contentChangeSubscriptionInterval);
this.contentChangeSubscriptionInterval = null;
}
}
async convertListenerResult(events) {
const result = {
documents: [],
assets: [],
scheduledActions: [],
deletedDocumentIds: [],
deletedAssetIds: [],
deletedScheduledActionIds: []
};
const logContext = {
event: events?.map((event) => event?.transition)?.join(','),
transactionId: events?.map((event) => event?.transactionId)?.join(','),
eventId: events?.map((event) => event?.eventId)?.join(','),
documentId: events?.map((event) => event?.documentId)?.join(',')
};
this.logger.debug('SanityListener: content changed, convert started', logContext);
// fetch document history once for all events
const documentIds = lodash_1.default.uniq(events.filter((event) => event.transition !== 'disappear' && event.result && (0, sanity_document_converter_1.isDraftId)(event.documentId)).map((event) => event.documentId)).filter(Boolean);
const documentsHistory = await this.getDocumentsHistory(documentIds);
// fetch updated scheduled actions after a second delay to allow sanity to update the status of any executed scheduled action
const pureDocumentIds = lodash_1.default.uniq(events.map((event) => (0, sanity_document_converter_1.getPureObjectId)(event.documentId))).filter(Boolean);
setTimeout(async () => {
try {
const sanitySchedules = await (0, sanity_api_client_1.fetchScheduledActions)({ projectId: this.projectId, dataset: this.dataset }, this.client, {
documentIds: pureDocumentIds
});
const remoteScheduledActions = (0, sanity_document_converter_1.convertAndFilterScheduledActions)(sanitySchedules);
const cachedScheduledActions = pureDocumentIds.flatMap((documentId) => this.cache.getScheduledActionsForDocumentId(documentId));
const updatedActions = lodash_1.default.differenceWith(remoteScheduledActions, cachedScheduledActions, lodash_1.default.isEqual);
if (updatedActions.length) {
this.logger.debug('SanityListener: Scheduled actions changed, updating', { updatedSchedulesCount: updatedActions.length });
this.cache.updateContent({ scheduledActions: updatedActions });
}
}
catch (err) {
this.logger.debug('SanityListener: Failed to fetch Scheduled actions for updated documents', { ...logContext, error: err });
}
}, 1000);
// save local cache of documents and assets to be reused between events
const documentMap = {};
const assetMap = {};
for (const event of events) {
const pureObjectId = (0, sanity_document_converter_1.getPureObjectId)(event.documentId);
const document = documentMap[pureObjectId] || this.cache.getDocumentById(pureObjectId);
const asset = this.cache.getAssetById(pureObjectId);
const isDraft = (0, sanity_document_converter_1.isDraftId)(event.documentId);
// cleanup deleted ids - either prevents duplicates or removes ids that are no longer deleted
const existingDeletedDocumentIdIndex = result.deletedDocumentIds.indexOf(pureObjectId);
if (existingDeletedDocumentIdIndex >= 0) {
result.deletedDocumentIds = result.deletedDocumentIds.splice(existingDeletedDocumentIdIndex, 1);
}
const existingDeletedAssetIdIndex = result.deletedAssetIds.indexOf(pureObjectId);
if (existingDeletedAssetIdIndex >= 0) {
result.deletedAssetIds = result.deletedAssetIds.splice(existingDeletedAssetIdIndex, 1);
}
if (event.transition === 'disappear') {
if (document) {
const { context } = document;
if ((isDraft && !context.publishedDocument) || (!isDraft && !context.draftDocument)) {
// notify deleted only if already in content cache
if (this.cache.getDocumentById(pureObjectId)) {
result.deletedDocumentIds.push(pureObjectId);
}
// remove now-deleted document from result
if (documentMap[pureObjectId]) {
delete documentMap[pureObjectId];
}
}
else {
const documents = [isDraft ? context.publishedDocument : context.draftDocument];
const [convertedDocuments] = this.convertDocuments({
documents,
getModelByName: this.cache.getModelByName,
studioUrl: this.studioUrl,
documentsHistory
});
if (convertedDocuments) {
documentMap[pureObjectId] = convertedDocuments;
}
}
}
else if (asset) {
result.deletedAssetIds.push(pureObjectId);
if (assetMap[pureObjectId]) {
delete assetMap[pureObjectId];
}
}
}
if (event.result) {
const publishedDocument = isDraft ? document?.context.publishedDocument : event.result;
const draftDocument = isDraft ? event.result : document?.context.draftDocument;
const documents = [publishedDocument, draftDocument].filter(Boolean);
if (ASSET_TYPES.includes(event.result._type)) {
const convertedAssets = (0, sanity_document_converter_1.convertAssets)({ assets: documents, documentsHistory });
assetMap[pureObjectId] = convertedAssets[0];
}
else {
const [convertedDocuments] = this.convertDocuments({
documents: documents,
getModelByName: this.cache.getModelByName,
studioUrl: this.studioUrl,
documentsHistory
});
if (convertedDocuments) {
documentMap[pureObjectId] = convertedDocuments;
}
}
}
}
result.documents = Object.values(documentMap);
result.assets = Object.values(assetMap);
this.logger.debug('SanityListener: content changed, convert done', logContext);
return this.cache.updateContent(result);
}
convertVersionsFromDocumentHistory(versions) {
return versions.map((version) => {
return {
id: version.id,
documentId: (0, sanity_document_converter_1.getPureObjectId)(version.documentIDs[0]),
srcType: this.getContentSourceType(),
srcProjectId: this.projectId,
createdAt: version.timestamp,
createdBy: this.userMap[version.author]?.email
};
});
}
convertVersionForDocument(version, document) {
const [documentVersion] = this.convertVersionsFromDocumentHistory([version]);
if (!documentVersion) {
throw new Error('Document version could not be converted');
}
return {
...documentVersion,
document
};
}
async getSanitySchema() {
let sanitySchema;
try {
sanitySchema = await fetcher.spawnFetchSchema({
studioPath: this.studioPath ?? this.rootPath,
repoPath: this.rootPath,
spawnRunner: this.userCommandSpawner,
logger: this.logger
});
}
catch (err) {
if (!lodash_1.default.isEmpty(err) && lodash_1.default.isString(err)) {
this.userLogger.info(err);
}
this.userLogger.error('Error fetching Sanity schema');
throw err;
}
return sanitySchema;
}
async getSchema() {
this.logger.debug('getSchema');
const sanitySchema = await this.getSanitySchema();
const { models, locales } = (0, sanity_schema_converter_1.convertSchema)({
schema: sanitySchema,
logger: this.logger,
defaultLocale: this.defaultLocale
});
return {
models,
locales,
context: null
};
}
async getDocumentsHistory(documentIds) {
this.logger.debug('getDocumentsHistory started', documentIds.length);
const draftDocumentIds = documentIds.filter((documentId) => (0, sanity_document_converter_1.isDraftId)(documentId));
const historyData = await (0, sanity_api_client_1.fetchDocumentsHistory)({ documentIds: draftDocumentIds, dataset: this.dataset, client: this.client });
const notCachedDocAuthors = historyData.reduce((acc, doc) => {
const user = this.userMap[doc.author];
if (!user && !acc.includes(doc.author) && doc.author !== 'system' && doc.author !== '<system>') {
acc.push(doc.author);
}
return acc;
}, []);
if (notCachedDocAuthors.length) {
try {
const authors = await (0, sanity_api_client_1.fetchUsers)(notCachedDocAuthors, this.client);
for (const author of authors) {
this.userMap[author.id] = author;
}
}
catch (err) {
this.logger.error('getDocumentsHistory error fetching authors', err);
this.userLogger.warn('Error fetching users from Sanity. Make sure the Sanity token has the appropriate permissions.');
}
}
this.logger.debug('getDocumentsHistory done fetch');
return draftDocumentIds.reduce((acc, documentId) => {
const docHistory = historyData.filter(({ documentIDs }) => documentIDs.includes(documentId));
const docHistoryWithAuthor = [];
for (const history of docHistory) {
const author = this.userMap[history.author];
if (!author) {
this.logger.debug(`getDocumentsHistory author is missing in userMap`, { authorId: history.author });
continue;
}
if (author.email) {
docHistoryWithAuthor.push({
...history,
author: author.email
});
}
}
if (docHistoryWithAuthor.length) {
acc[documentId] = docHistoryWithAuthor;
}
return acc;
}, {});
}
// centralized place that handles document conversion to allow easy content source extension
convertDocuments(options) {
return (0, sanity_document_converter_1.convertDocuments)(options);
}
async getDocuments() {
this.logger.debug('getDocuments');
const documents = await this.client.fetch(this.sanityQuery);
this.logger.debug(`fetched ${documents.length} entries from project ${this.projectId} and dataset ${this.dataset}`);
const documentsHistory = await this.getDocumentsHistory(documents.map((document) => document._id));
return this.convertDocuments({
documents: documents.filter((document) => !ASSET_TYPES.includes(document._type)),
getModelByName: this.cache.getModelByName,
documentsHistory,
studioUrl: this.studioUrl
});
}
async getAssets() {
const documents = await this.client.fetch('*[_type in $types]', { types: ASSET_TYPES });
this.logger.debug(`fetched ${documents.length} assets from project ${this.projectId} and dataset ${this.dataset}`);
const documentsHistory = await this.getDocumentsHistory(documents.map((document) => document._id));
return (0, sanity_document_converter_1.convertAssets)({
assets: documents.filter((document) => ASSET_TYPES.includes(document._type)),
documentsHistory
});
}
async hasAccess({ userContext }) {
if (!this.localDev) {
if (!userContext?.accessToken) {
return {
hasConnection: false,
hasPermissions: false
};
}
let tokenExpired = true;
try {
const testTokenResult = await (0, sanity_api_client_1.testToken)(userContext.accessToken);
const accessTokenExpiresAt = testTokenResult?.accessTokenExpiresAt;
if (accessTokenExpiresAt) {
const expiresAt = new Date(accessTokenExpiresAt);
tokenExpired = new Date().getTime() - expiresAt.getTime() >= 0;
}
}
catch (e) {
// pass
}
if (tokenExpired) {
return {
hasConnection: false,
hasPermissions: false
};
}
}
try {
const userClient = this.getApiClientForUser({ userContext });
await userClient.fetch(`*[_type == 'system.group'] {_id}`);
return {
hasConnection: true,
hasPermissions: true
};
}
catch (error) {
this.logger.debug('Sanity: failed to access project', { error });
return {
hasConnection: true,
hasPermissions: false
};
}
}
async onFilesChange({ updatedFiles }) {
let invalidateSchema = false;
if (this.studioPath) {
const relStudioPath = path_1.default.relative(this.rootPath, this.studioPath);
const sanityPackageJson = path_1.default.join(relStudioPath, 'package.json');
const needsStudioInstall = lodash_1.default.some(updatedFiles, (updatedFile) => updatedFile === sanityPackageJson);
invalidateSchema = lodash_1.default.some(updatedFiles, (updatedFile) => updatedFile.startsWith(relStudioPath));
if (needsStudioInstall) {
this.logger.debug('Sanity Studio package.json changed, reinstalling...');
await this.installStudio();
}
}
if (this.schemaGlob) {
const existingSchemaFiles = await (0, glob_1.glob)(this.schemaGlob, { cwd: this.rootPath, absolute: false });
invalidateSchema = !lodash_1.default.isEmpty(lodash_1.default.intersection(updatedFiles, existingSchemaFiles));
}
return { invalidateSchema };
}
async createDocument({ updateOperationFields, model, locale, userContext }) {
const sanityDocument = {
_id: sanity_document_converter_1.DRAFT_ID_PREFIX,
_type: model.name
};
try {
lodash_1.default.forEach(updateOperationFields, (updateOperationField, fieldName) => {
const childModelField = lodash_1.default.find(model.fields, (field) => field.name === fieldName);
if (!childModelField) {
throw new Error(`No model field found for field: ${fieldName}`);
}
const value = (0, sanity_operation_converter_1.mapUpdateOperationFieldToSanityValue)({
updateOperationField,
getModelByName: this.cache.getModelByName,
modelField: childModelField,
rootModel: model,
modelFieldPath: [fieldName],
locale
});
if ((0, utils_2.isLocalizedModelField)(childModelField)) {
lodash_1.default.set(sanityDocument, fieldName, [
(0, sanity_operation_converter_1.localizedValue)({
value,
model,
modelFieldPath: [fieldName],
locale
})
]);
}
else {
lodash_1.default.set(sanityDocument, fieldName, value);
}
});
const userClient = this.getApiClientForUser({ userContext });
const result = await userClient.create(sanityDocument);
const pureObjectId = (0, sanity_document_converter_1.getPureObjectId)(result._id);
return { documentId: pureObjectId };
}
catch (error) {
this.logger.error('Error creating document', error);
throw new Error(`Error creating document. ${error.message}`);
}
}
async updateDocument({ document, operations, userContext }) {
this.logger.debug('updateDocument');
const documentId = document.id;
const userClient = this.getApiClientForUser({ userContext });
const draftObjectId = (0, sanity_document_converter_1.getDraftObjectId)(documentId);
const sanityDocument = (document.context.draftDocument || document.context.publishedDocument);
const modelName = document.modelName;
const model = this.cache.getModelByName(modelName);
try {
if (!model) {
throw new Error(`Could not find document model '${modelName}'.`);
}
const transaction = lodash_1.default.reduce(operations, (transaction, operation) => {
const patchObject = (0, sanity_operation_converter_1.convertUpdateOperation)({
operation,
sanityDocument,
getModelByName: this.cache.getModelByName,
model
});
return transaction.patch(draftObjectId, patchObject);
}, userClient.transaction().createIfNotExists({
...sanityDocument,
_id: draftObjectId
}));
await transaction.commit({ visibility: this.listenerVisibility === 'query' ? 'sync' : 'async', returnDocuments: true });
}
catch (error) {
this.logger.error(`Error updating document ${document.id}`, error);
throw new Error(`Error updating document ${document.id}. ${error.message}`);
}
}
async deleteDocument({ document, userContext }) {
const userClient = this.getApiClientForUser({ userContext });
const draftObjectId = (0, sanity_document_converter_1.getDraftObjectId)(document.id);
const pureObjectId = (0, sanity_document_converter_1.getPureObjectId)(document.id);
await Promise.all([userClient.delete(pureObjectId), userClient.delete(draftObjectId)]);
}
async uploadAsset({ url, base64, fileName, mimeType, userContext }) {
const userClient = this.getApiClientForUser({ userContext });
const assetType = mimeType.startsWith('image/') ? 'image' : 'file';
let uploadResult;
if (url) {
uploadResult = await new Promise((resolve, reject) => {
https_1.default.get(url, (downloadStream) => {
userClient.assets.upload(assetType, downloadStream, { filename: fileName }).then(resolve).catch(reject);
});
});
}
else {
const buffer = Buffer.from(base64, 'base64');
uploadResult = await userClient.assets.upload(assetType, buffer, { filename: fileName });
}
const documentsHistory = await this.getDocumentsHistory([uploadResult._id]);
const assets = (0, sanity_document_converter_1.convertAssets)({ assets: [uploadResult], documentsHistory });
return assets[0];
}
async validateDocuments({ documents, assets, locale, userContext }) {
return { errors: [] };
}
async publishDocuments({ documents, assets, userContext }) {
const userClient = this.getApiClientForUser({ userContext });
const publishedDocumentIds = documents.map((document) => (0, sanity_document_converter_1.getPureObjectId)(document.id));
const draftDocumentIds = publishedDocumentIds.map((documentId) => (0, sanity_document_converter_1.getDraftObjectId)(documentId));
const query = '*[ _id in $documentIds ]';
const sanityDocuments = await userClient.fetch(query, { documentIds: [...draftDocumentIds, ...publishedDocumentIds] });
const draftDocuments = sanityDocuments.filter((document) => (0, sanity_document_converter_1.isDraftId)(document._id));
const transaction = lodash_1.default.reduce(draftDocuments, (transaction, document) => {
const documentId = document._id;
const publishedDocument = lodash_1.default.find(sanityDocuments, { _id: (0, sanity_document_converter_1.getPureObjectId)(documentId) });
if (publishedDocument) {
// borrowed form Sanity folks - https://github.com/sanity-io/sanity/blob/c3c875ed51bf49ebceedc40abe50ad17ccbf489b/packages/%40sanity/desk-tool/src/pane/DocumentPane.js#L860
// Hack until other mutations support revision locking
transaction = transaction.patch(publishedDocument._id, {
unset: ['_reserved_prop_'],
ifRevisionID: publishedDocument._rev
});
}
// you should omit it to be sure it get's the right timestamp from the server
const documentForPublishing = lodash_1.default.omit(document, ['_updatedAt']);
return transaction
.createOrReplace({
...documentForPublishing,
_id: (0, sanity_document_converter_1.getPureObjectId)(documentId)
})
.delete(documentId);
}, userClient.transaction());
await transaction.commit();
}
async getScheduledActions() {
this.logger.debug('getScheduledPublishes');
const sanitySchedules = await (0, sanity_api_client_1.fetchScheduledActions)({ projectId: this.projectId, dataset: this.dataset }, this.client);
return (0, sanity_document_converter_1.convertAndFilterScheduledActions)(sanitySchedules);
}
async createScheduledAction({ documentIds, name, action, executeAt, userContext }) {
this.logger.debug('createScheduledAction');
const userClient = this.getApiClientForUser({ userContext });
const sanitySchedule = await userClient.request({
method: 'POST',
uri: `/schedules/${this.projectId}/${this.dataset}`,
body: {
documents: documentIds.map((docId) => ({ documentId: docId })),
executeAt: executeAt,
name: name
}
});
const schedule = (0, sanity_document_converter_1.convertScheduledAction)(sanitySchedule);
await this.cache.updateContent({ scheduledActions: [schedule] });
this.logger.debug('createScheduledAction - Create success', { originalSchedule: sanitySchedule, schedule });
return { newScheduledActionId: schedule.id };
}
async cancelScheduledAction({ scheduledActionId, userContext }) {
this.logger.debug('cancelScheduledAction');
const userClient = this.getApiClientForUser({ userContext });
const response = await userClient
.request({
method: 'PATCH',
uri: `/schedules/${this.projectId}/${this.dataset}/${scheduledActionId}`,
body: {
state: 'cancelled'
}
})
.then(() => userClient.request({
method: 'GET',
uri: `/schedules/${this.projectId}/${this.dataset}/${scheduledActionId}`
}));
const sanitySchedule = response.schedules[0];
const schedule = (0, sanity_document_converter_1.convertScheduledAction)(sanitySchedule);
await this.cache.updateContent({ scheduledActions: [schedule] });
this.logger.debug('cancelScheduledAction - Cancel success', { originalSchedule: sanitySchedule, schedule });
return { cancelledScheduledActionId: schedule.id };
}
async updateScheduledAction({ scheduledActionId, documentIds, name, executeAt, userContext }) {
this.logger.debug('updateScheduledAction');
const updateObj = (0, utils_1.omitByNil)({
documents: documentIds?.map((documentId) => ({ documentId })),
name,
executeAt
});
const userClient = this.getApiClientForUser({ userContext });
const response = await userClient
.request({
method: 'PATCH',
uri: `/schedules/${this.projectId}/${this.dataset}/${scheduledActionId}`,
body: updateObj
})
.then(() => userClient.request({
method: 'GET',
uri: `/schedules/${this.projectId}/${this.dataset}/${scheduledActionId}`
}));
const sanitySchedule = response.schedules[0];
const schedule = (0, sanity_document_converter_1.convertScheduledAction)(sanitySchedule);
await this.cache.updateContent({ scheduledActions: [schedule] });
this.logger.debug('updateScheduledAction - Update success', { originalSchedule: sanitySchedule, schedule });
return { updatedScheduledActionId: schedule.id };
}
getApiClientForUser({ userContext }) {
if (this.localDev) {
return this.client;
}
const userAccessToken = userContext?.accessToken;
if (!userAccessToken) {
throw new Error(`Permissions error: user does not have an access token for project: '${this.projectId}'.`);
}
return new sanity_api_client_1.SanityClient({
projectId: this.projectId,
dataset: this.dataset,
token: userAccessToken,
useCdn: false,
apiVersion: SANITY_API_VERSION
});
}
async getDocumentVersions({ documentId }) {
this.logger.debug('getDocumentVersions', { documentId });
const documentHistory = await (0, sanity_api_client_1.fetchDocumentsHistory)({
documentIds: [documentId, (0, sanity_document_converter_1.getDraftObjectId)(documentId)],
dataset: this.dataset,
client: this.client,
limitTime: false
});
if (!documentHistory) {
return { versions: [] };
}
return { versions: this.convertVersionsFromDocumentHistory(documentHistory) };
}
async getDocumentForVersion({ documentId, versionId }) {
this.logger.debug('getDocumentForVersion', { documentId, versionId });
const draftDocumentId = (0, sanity_document_converter_1.getDraftObjectId)(documentId);
const [version, document] = await Promise.all([
(0, sanity_api_client_1.fetchDocumentRevision)({ documentId, draftDocumentId, versionId, dataset: this.dataset, client: this.client }),
(0, sanity_api_client_1.fetchDocumentForRevision)({ documentId, draftDocumentId, versionId, dataset: this.dataset, client: this.client })
]);
const [contextualDocument] = this.convertDocuments({
documents: [document],
getModelByName: this.cache.getModelByName,
studioUrl: this.studioUrl
});
if (!contextualDocument) {
throw new Error(`Could not get document ${documentId} for revision ${versionId}`);
}
return { version: this.convertVersionForDocument(version, contextualDocument) };
}
}
exports.SanityContentSource = SanityContentSource;
//# sourceMappingURL=sanity-content-source.js.map