internal: incomplete vault systems behind feature flag (#2340)
This commit is contained in:
@@ -21,17 +21,15 @@ export class AccountSyncOperation {
|
||||
* @param receiver A function that receives callback multiple times during the operation
|
||||
*/
|
||||
constructor(
|
||||
private payloads: ServerSyncPushContextualPayload[],
|
||||
public readonly payloads: ServerSyncPushContextualPayload[],
|
||||
private receiver: ResponseSignalReceiver<ServerSyncResponse>,
|
||||
private lastSyncToken: string,
|
||||
private paginationToken: string,
|
||||
private apiService: SNApiService,
|
||||
public readonly options: {
|
||||
syncToken?: string
|
||||
paginationToken?: string
|
||||
sharedVaultUuids?: string[]
|
||||
},
|
||||
) {
|
||||
this.payloads = payloads
|
||||
this.lastSyncToken = lastSyncToken
|
||||
this.paginationToken = paginationToken
|
||||
this.apiService = apiService
|
||||
this.receiver = receiver
|
||||
this.pendingPayloads = payloads.slice()
|
||||
}
|
||||
|
||||
@@ -55,13 +53,19 @@ export class AccountSyncOperation {
|
||||
})
|
||||
const payloads = this.popPayloads(this.upLimit)
|
||||
|
||||
const rawResponse = await this.apiService.sync(payloads, this.lastSyncToken, this.paginationToken, this.downLimit)
|
||||
const rawResponse = await this.apiService.sync(
|
||||
payloads,
|
||||
this.options.syncToken,
|
||||
this.options.paginationToken,
|
||||
this.downLimit,
|
||||
this.options.sharedVaultUuids,
|
||||
)
|
||||
|
||||
const response = new ServerSyncResponse(rawResponse)
|
||||
this.responses.push(response)
|
||||
|
||||
this.lastSyncToken = response.lastSyncToken as string
|
||||
this.paginationToken = response.paginationToken as string
|
||||
this.options.syncToken = response.lastSyncToken as string
|
||||
this.options.paginationToken = response.paginationToken as string
|
||||
|
||||
try {
|
||||
await this.receiver(SyncSignal.Response, response)
|
||||
@@ -75,7 +79,7 @@ export class AccountSyncOperation {
|
||||
}
|
||||
|
||||
get done() {
|
||||
return this.pendingPayloads.length === 0 && !this.paginationToken
|
||||
return this.pendingPayloads.length === 0 && !this.options.paginationToken
|
||||
}
|
||||
|
||||
private get pendingUploadCount() {
|
||||
|
||||
@@ -1,27 +1,36 @@
|
||||
import {
|
||||
ApiEndpointParam,
|
||||
ConflictParams,
|
||||
ConflictType,
|
||||
SharedVaultInviteServerHash,
|
||||
SharedVaultServerHash,
|
||||
HttpError,
|
||||
HttpResponse,
|
||||
isErrorResponse,
|
||||
RawSyncResponse,
|
||||
ServerItemResponse,
|
||||
UserEventServerHash,
|
||||
AsymmetricMessageServerHash,
|
||||
} from '@standardnotes/responses'
|
||||
import {
|
||||
FilterDisallowedRemotePayloadsAndMap,
|
||||
CreateServerSyncSavedPayload,
|
||||
ServerSyncSavedContextualPayload,
|
||||
FilteredServerItem,
|
||||
TrustedConflictParams,
|
||||
} from '@standardnotes/models'
|
||||
import { deepFreeze } from '@standardnotes/utils'
|
||||
import { TrustedServerConflictMap } from './ServerConflictMap'
|
||||
|
||||
export class ServerSyncResponse {
|
||||
public readonly savedPayloads: ServerSyncSavedContextualPayload[]
|
||||
public readonly retrievedPayloads: FilteredServerItem[]
|
||||
public readonly uuidConflictPayloads: FilteredServerItem[]
|
||||
public readonly dataConflictPayloads: FilteredServerItem[]
|
||||
public readonly rejectedPayloads: FilteredServerItem[]
|
||||
readonly savedPayloads: ServerSyncSavedContextualPayload[]
|
||||
readonly retrievedPayloads: FilteredServerItem[]
|
||||
readonly conflicts: TrustedServerConflictMap
|
||||
|
||||
readonly asymmetricMessages: AsymmetricMessageServerHash[]
|
||||
readonly vaults: SharedVaultServerHash[]
|
||||
readonly vaultInvites: SharedVaultInviteServerHash[]
|
||||
readonly userEvents: UserEventServerHash[]
|
||||
|
||||
private readonly rawConflictObjects: ConflictParams[]
|
||||
|
||||
private successResponseData: RawSyncResponse | undefined
|
||||
|
||||
@@ -32,6 +41,10 @@ export class ServerSyncResponse {
|
||||
this.successResponseData = rawResponse.data
|
||||
}
|
||||
|
||||
const conflicts = this.successResponseData?.conflicts || []
|
||||
const legacyConflicts = this.successResponseData?.unsaved || []
|
||||
this.rawConflictObjects = conflicts.concat(legacyConflicts)
|
||||
|
||||
this.savedPayloads = FilterDisallowedRemotePayloadsAndMap(this.successResponseData?.saved_items || []).map(
|
||||
(rawItem) => {
|
||||
return CreateServerSyncSavedPayload(rawItem)
|
||||
@@ -40,15 +53,53 @@ export class ServerSyncResponse {
|
||||
|
||||
this.retrievedPayloads = FilterDisallowedRemotePayloadsAndMap(this.successResponseData?.retrieved_items || [])
|
||||
|
||||
this.dataConflictPayloads = FilterDisallowedRemotePayloadsAndMap(this.rawDataConflictItems)
|
||||
this.conflicts = this.filterConflicts()
|
||||
|
||||
this.uuidConflictPayloads = FilterDisallowedRemotePayloadsAndMap(this.rawUuidConflictItems)
|
||||
this.vaults = this.successResponseData?.shared_vaults || []
|
||||
|
||||
this.rejectedPayloads = FilterDisallowedRemotePayloadsAndMap(this.rawRejectedPayloads)
|
||||
this.vaultInvites = this.successResponseData?.shared_vault_invites || []
|
||||
|
||||
this.asymmetricMessages = this.successResponseData?.asymmetric_messages || []
|
||||
|
||||
this.userEvents = this.successResponseData?.user_events || []
|
||||
|
||||
deepFreeze(this)
|
||||
}
|
||||
|
||||
private filterConflicts(): TrustedServerConflictMap {
|
||||
const conflicts = this.rawConflictObjects
|
||||
const trustedConflicts: TrustedServerConflictMap = {}
|
||||
|
||||
for (const conflict of conflicts) {
|
||||
let serverItem: FilteredServerItem | undefined
|
||||
let unsavedItem: FilteredServerItem | undefined
|
||||
|
||||
if (conflict.unsaved_item) {
|
||||
unsavedItem = FilterDisallowedRemotePayloadsAndMap([conflict.unsaved_item])[0]
|
||||
}
|
||||
|
||||
if (conflict.server_item) {
|
||||
serverItem = FilterDisallowedRemotePayloadsAndMap([conflict.server_item])[0]
|
||||
}
|
||||
|
||||
if (!trustedConflicts[conflict.type]) {
|
||||
trustedConflicts[conflict.type] = []
|
||||
}
|
||||
|
||||
const conflictArray = trustedConflicts[conflict.type]
|
||||
if (conflictArray) {
|
||||
const entry: TrustedConflictParams = <TrustedConflictParams>{
|
||||
type: conflict.type,
|
||||
server_item: serverItem,
|
||||
unsaved_item: unsavedItem,
|
||||
}
|
||||
conflictArray.push(entry)
|
||||
}
|
||||
}
|
||||
|
||||
return trustedConflicts
|
||||
}
|
||||
|
||||
public get error(): HttpError | undefined {
|
||||
return isErrorResponse(this.rawResponse) ? this.rawResponse.data?.error : undefined
|
||||
}
|
||||
@@ -66,56 +117,9 @@ export class ServerSyncResponse {
|
||||
}
|
||||
|
||||
public get numberOfItemsInvolved(): number {
|
||||
return this.allFullyFormedPayloads.length
|
||||
}
|
||||
const allPayloads = [...this.retrievedPayloads, ...this.rawConflictObjects]
|
||||
|
||||
private get allFullyFormedPayloads(): FilteredServerItem[] {
|
||||
return [
|
||||
...this.retrievedPayloads,
|
||||
...this.dataConflictPayloads,
|
||||
...this.uuidConflictPayloads,
|
||||
...this.rejectedPayloads,
|
||||
]
|
||||
}
|
||||
|
||||
private get rawUuidConflictItems(): ServerItemResponse[] {
|
||||
return this.rawConflictObjects
|
||||
.filter((conflict) => {
|
||||
return conflict.type === ConflictType.UuidConflict
|
||||
})
|
||||
.map((conflict) => {
|
||||
return conflict.unsaved_item || conflict.item!
|
||||
})
|
||||
}
|
||||
|
||||
private get rawDataConflictItems(): ServerItemResponse[] {
|
||||
return this.rawConflictObjects
|
||||
.filter((conflict) => {
|
||||
return conflict.type === ConflictType.ConflictingData
|
||||
})
|
||||
.map((conflict) => {
|
||||
return conflict.server_item || conflict.item!
|
||||
})
|
||||
}
|
||||
|
||||
private get rawRejectedPayloads(): ServerItemResponse[] {
|
||||
return this.rawConflictObjects
|
||||
.filter((conflict) => {
|
||||
return (
|
||||
conflict.type === ConflictType.ContentTypeError ||
|
||||
conflict.type === ConflictType.ContentError ||
|
||||
conflict.type === ConflictType.ReadOnlyError
|
||||
)
|
||||
})
|
||||
.map((conflict) => {
|
||||
return conflict.unsaved_item!
|
||||
})
|
||||
}
|
||||
|
||||
private get rawConflictObjects(): ConflictParams[] {
|
||||
const conflicts = this.successResponseData?.conflicts || []
|
||||
const legacyConflicts = this.successResponseData?.unsaved || []
|
||||
return conflicts.concat(legacyConflicts)
|
||||
return allPayloads.length
|
||||
}
|
||||
|
||||
public get hasError(): boolean {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ConflictParams, ConflictType } from '@standardnotes/responses'
|
||||
import {
|
||||
ImmutablePayloadCollection,
|
||||
HistoryMap,
|
||||
@@ -11,13 +12,12 @@ import {
|
||||
DeltaRemoteRejected,
|
||||
DeltaEmit,
|
||||
} from '@standardnotes/models'
|
||||
import { DecryptedServerConflictMap } from './ServerConflictMap'
|
||||
|
||||
type PayloadSet = {
|
||||
retrievedPayloads: FullyFormedPayloadInterface[]
|
||||
savedPayloads: ServerSyncSavedContextualPayload[]
|
||||
uuidConflictPayloads: FullyFormedPayloadInterface[]
|
||||
dataConflictPayloads: FullyFormedPayloadInterface[]
|
||||
rejectedPayloads: FullyFormedPayloadInterface[]
|
||||
conflicts: DecryptedServerConflictMap
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,8 +39,8 @@ export class ServerSyncResponseResolver {
|
||||
|
||||
emits.push(this.processRetrievedPayloads())
|
||||
emits.push(this.processSavedPayloads())
|
||||
emits.push(this.processUuidConflictPayloads())
|
||||
emits.push(this.processDataConflictPayloads())
|
||||
emits.push(this.processUuidConflictUnsavedPayloads())
|
||||
emits.push(this.processDataConflictServerPayloads())
|
||||
emits.push(this.processRejectedPayloads())
|
||||
|
||||
return emits
|
||||
@@ -60,27 +60,42 @@ export class ServerSyncResponseResolver {
|
||||
return delta.result()
|
||||
}
|
||||
|
||||
private processDataConflictPayloads(): DeltaEmit {
|
||||
const collection = ImmutablePayloadCollection.WithPayloads(this.payloadSet.dataConflictPayloads)
|
||||
private getConflictsForType<T extends ConflictParams<FullyFormedPayloadInterface>>(type: ConflictType): T[] {
|
||||
const results = this.payloadSet.conflicts[type] || []
|
||||
|
||||
const delta = new DeltaRemoteDataConflicts(this.baseCollection, collection, this.historyMap)
|
||||
return results as T[]
|
||||
}
|
||||
|
||||
private processDataConflictServerPayloads(): DeltaEmit {
|
||||
const delta = new DeltaRemoteDataConflicts(
|
||||
this.baseCollection,
|
||||
this.getConflictsForType(ConflictType.ConflictingData),
|
||||
this.historyMap,
|
||||
)
|
||||
|
||||
return delta.result()
|
||||
}
|
||||
|
||||
private processUuidConflictPayloads(): DeltaEmit {
|
||||
const collection = ImmutablePayloadCollection.WithPayloads(this.payloadSet.uuidConflictPayloads)
|
||||
|
||||
const delta = new DeltaRemoteUuidConflicts(this.baseCollection, collection)
|
||||
private processUuidConflictUnsavedPayloads(): DeltaEmit {
|
||||
const delta = new DeltaRemoteUuidConflicts(this.baseCollection, this.getConflictsForType(ConflictType.UuidConflict))
|
||||
|
||||
return delta.result()
|
||||
}
|
||||
|
||||
private processRejectedPayloads(): DeltaEmit {
|
||||
const collection = ImmutablePayloadCollection.WithPayloads(this.payloadSet.rejectedPayloads)
|
||||
const conflicts = [
|
||||
...this.getConflictsForType(ConflictType.ContentTypeError),
|
||||
...this.getConflictsForType(ConflictType.ContentError),
|
||||
...this.getConflictsForType(ConflictType.ReadOnlyError),
|
||||
...this.getConflictsForType(ConflictType.UuidError),
|
||||
...this.getConflictsForType(ConflictType.SharedVaultSnjsVersionError),
|
||||
...this.getConflictsForType(ConflictType.SharedVaultInsufficientPermissionsError),
|
||||
...this.getConflictsForType(ConflictType.SharedVaultNotMemberError),
|
||||
...this.getConflictsForType(ConflictType.SharedVaultInvalidState),
|
||||
]
|
||||
|
||||
const delta = new DeltaRemoteRejected(this.baseCollection, collection)
|
||||
|
||||
return delta.result()
|
||||
const delta = new DeltaRemoteRejected(this.baseCollection, conflicts)
|
||||
const result = delta.result()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { ConflictType, ConflictParams } from '@standardnotes/responses'
|
||||
import { FullyFormedPayloadInterface, TrustedConflictParams } from '@standardnotes/models'
|
||||
|
||||
export type TrustedServerConflictMap = Partial<Record<ConflictType, TrustedConflictParams[]>>
|
||||
export type DecryptedServerConflictMap = Partial<Record<ConflictType, ConflictParams<FullyFormedPayloadInterface>[]>>
|
||||
Reference in New Issue
Block a user