internal: incomplete vault systems behind feature flag (#2340)

This commit is contained in:
Mo
2023-06-30 09:01:56 -05:00
committed by GitHub
parent d16e401bb9
commit b032eb9c9b
638 changed files with 20321 additions and 4813 deletions

View File

@@ -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() {

View File

@@ -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 {

View File

@@ -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
}
}

View File

@@ -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>[]>>