sanity
Version:
Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches
129 lines (114 loc) • 3.84 kB
text/typescript
import {
type MendozaEffectPair,
type MendozaPatch,
type TransactionLogEventWithEffects,
} from '@sanity/types'
import {getVersionFromId} from '../../util/draftUtils'
import {
type EditDocumentVersionEvent,
isEditDocumentVersionEvent,
type UpdateLiveDocumentEvent,
} from './types'
import {isWithinMergeWindow} from './utils'
export function getEffectState(
effect?: MendozaEffectPair,
): 'noop' | 'deleted' | 'modified' | 'created' {
const modified = Boolean(effect)
const deleted = effect && isDeletePatch(effect?.apply)
const created = effect && isDeletePatch(effect?.revert)
if (deleted) {
return 'deleted'
}
if (created) {
return 'created'
}
if (modified) {
return 'modified'
}
return 'noop'
}
function isDeletePatch(patch: MendozaPatch): boolean {
return patch[0] === 0 && patch[1] === null
}
const getEditTransaction = (
transaction: TransactionLogEventWithEffects,
): EditDocumentVersionEvent['transactions'][number] => {
return {
type: 'editTransaction',
author: transaction.author,
timestamp: transaction.timestamp,
revisionId: transaction.id,
}
}
export function getEditEvents(
transactions: TransactionLogEventWithEffects[],
documentId: string,
liveEdit: true,
): UpdateLiveDocumentEvent[]
export function getEditEvents(
transactions: TransactionLogEventWithEffects[],
documentId: string,
liveEdit: false,
): EditDocumentVersionEvent[]
export function getEditEvents(
transactions: TransactionLogEventWithEffects[],
documentId: string,
liveEdit: boolean,
): (EditDocumentVersionEvent | UpdateLiveDocumentEvent)[]
export function getEditEvents(
transactions: TransactionLogEventWithEffects[],
documentId: string,
liveEdit: boolean,
): (EditDocumentVersionEvent | UpdateLiveDocumentEvent)[] {
const editTransactions = transactions
.filter((tx) => {
const effectState = getEffectState(tx.effects[documentId])
// We only care about the transactions that have modified the document
return effectState === 'modified'
})
// We sort the transactions by timestamp, newest first
.sort((a, b) => Date.parse(b.timestamp) - Date.parse(a.timestamp))
const result: (EditDocumentVersionEvent | UpdateLiveDocumentEvent)[] = []
for (const transaction of editTransactions) {
// If result is empty, add the current event
const event = liveEdit
? ({
id: transaction.id,
timestamp: transaction.timestamp,
type: 'updateLiveDocument',
documentId: documentId,
revisionId: transaction.id,
author: transaction.author,
} satisfies UpdateLiveDocumentEvent)
: ({
type: 'editDocumentVersion',
documentId: documentId,
id: transaction.id,
timestamp: transaction.timestamp,
author: transaction.author,
contributors: [transaction.author],
releaseId: getVersionFromId(documentId),
revisionId: transaction.id,
transactions: [getEditTransaction(transaction)],
} satisfies EditDocumentVersionEvent)
if (result.length === 0) {
result.push(event)
continue
}
const lastEvent = result[result.length - 1]
if (isWithinMergeWindow(lastEvent.timestamp, event.timestamp)) {
if (isEditDocumentVersionEvent(lastEvent)) {
// Add the transaction event to the transactions
lastEvent.transactions.push(getEditTransaction(transaction))
if (!lastEvent.contributors.includes(event.author) && lastEvent.author !== event.author) {
// Update event the contributors list
lastEvent.contributors.push(event.author)
}
}
} else {
// If the time difference is greater than the window, add as a new event
result.push(event)
}
}
return result
}