feat: add services package

This commit is contained in:
Karol Sójko
2022-07-05 20:51:42 +02:00
parent b614c71e79
commit fbfed0a05c
85 changed files with 2418 additions and 28 deletions

View File

@@ -0,0 +1,14 @@
import { WebClientRequiresDesktopMethods } from './DesktopWebCommunication'
import { DeviceInterface } from './DeviceInterface'
import { Environment } from './Environments'
import { WebOrDesktopDeviceInterface } from './WebOrDesktopDeviceInterface'
/* istanbul ignore file */
export function isDesktopDevice(x: DeviceInterface): x is DesktopDeviceInterface {
return x.environment === Environment.Desktop
}
export interface DesktopDeviceInterface extends WebOrDesktopDeviceInterface, WebClientRequiresDesktopMethods {
environment: Environment.Desktop
}

View File

@@ -0,0 +1,38 @@
import { DecryptedTransferPayload } from '@standardnotes/models'
import { FileBackupsDevice } from './FileBackupsDevice'
export interface WebClientRequiresDesktopMethods extends FileBackupsDevice {
localBackupsCount(): Promise<number>
viewlocalBackups(): void
deleteLocalBackups(): Promise<void>
syncComponents(payloads: unknown[]): void
onMajorDataChange(): void
onInitialDataLoad(): void
onSearch(text?: string): void
downloadBackup(): void | Promise<void>
get extensionsServerHost(): string
}
export interface DesktopClientRequiresWebMethods {
updateAvailable(): void
windowGainedFocus(): void
windowLostFocus(): void
onComponentInstallationComplete(componentData: DecryptedTransferPayload, error: unknown): Promise<void>
requestBackupFile(): Promise<string | undefined>
didBeginBackup(): void
didFinishBackup(success: boolean): void
}

View File

@@ -0,0 +1,84 @@
import { Environment } from './Environments'
import { ApplicationIdentifier } from '@standardnotes/common'
import {
FullyFormedTransferPayload,
TransferPayload,
LegacyRawKeychainValue,
NamespacedRootKeyInKeychain,
} from '@standardnotes/models'
/**
* Platforms must override this class to provide platform specific utilities
* and access to the migration service, such as exposing an interface to read
* raw values from the database or value storage.
*/
export interface DeviceInterface {
environment: Environment
deinit(): void
getRawStorageValue(key: string): Promise<string | undefined>
getJsonParsedRawStorageValue(key: string): Promise<unknown | undefined>
getAllRawStorageKeyValues(): Promise<{ key: string; value: unknown }[]>
setRawStorageValue(key: string, value: string): Promise<void>
removeRawStorageValue(key: string): Promise<void>
removeAllRawStorageValues(): Promise<void>
/**
* On web platforms, databased created may be new.
* New databases can be because of new sessions, or if the browser deleted it.
* In this case, callers should orchestrate with the server to redownload all items
* from scratch.
* @returns { isNewDatabase } - True if the database was newly created
*/
openDatabase(identifier: ApplicationIdentifier): Promise<{ isNewDatabase?: boolean } | undefined>
/**
* In a key/value database, this function returns just the keys.
*/
getDatabaseKeys(): Promise<string[]>
/**
* Remove all keychain and database data from device.
* @param workspaceIdentifiers An array of identifiers present during time of function call. Used in case
* caller needs to reference the identifiers. This param should not be used to selectively clear workspaces.
* @returns true for killsApplication if the clear data operation kills the application process completely.
* This tends to be the case for the desktop application.
*/
clearAllDataFromDevice(workspaceIdentifiers: ApplicationIdentifier[]): Promise<{ killsApplication: boolean }>
getAllRawDatabasePayloads<T extends FullyFormedTransferPayload = FullyFormedTransferPayload>(
identifier: ApplicationIdentifier,
): Promise<T[]>
saveRawDatabasePayload(payload: TransferPayload, identifier: ApplicationIdentifier): Promise<void>
saveRawDatabasePayloads(payloads: TransferPayload[], identifier: ApplicationIdentifier): Promise<void>
removeRawDatabasePayloadWithId(id: string, identifier: ApplicationIdentifier): Promise<void>
removeAllRawDatabasePayloads(identifier: ApplicationIdentifier): Promise<void>
getNamespacedKeychainValue(identifier: ApplicationIdentifier): Promise<NamespacedRootKeyInKeychain | undefined>
setNamespacedKeychainValue(value: NamespacedRootKeyInKeychain, identifier: ApplicationIdentifier): Promise<void>
clearNamespacedKeychainValue(identifier: ApplicationIdentifier): Promise<void>
setLegacyRawKeychainValue(value: LegacyRawKeychainValue): Promise<void>
clearRawKeychainValue(): Promise<void>
openUrl(url: string): void
performSoftReset(): void
performHardReset(): void
isDeviceDestroyed(): boolean
}

View File

@@ -0,0 +1,16 @@
export enum Environment {
Web = 1,
Desktop = 2,
Mobile = 3,
}
export enum Platform {
Ios = 1,
Android = 2,
MacWeb = 3,
MacDesktop = 4,
WindowsWeb = 5,
WindowsDesktop = 6,
LinuxWeb = 7,
LinuxDesktop = 8,
}

View File

@@ -0,0 +1,51 @@
import { Uuid } from '@standardnotes/common'
import { BackupFileEncryptedContextualPayload } from '@standardnotes/models'
/* istanbul ignore file */
export const FileBackupsConstantsV1 = {
Version: '1.0.0',
MetadataFileName: 'metadata.sn.json',
BinaryFileName: 'file.encrypted',
}
export interface FileBackupMetadataFile {
info: Record<string, string>
file: BackupFileEncryptedContextualPayload
itemsKey: BackupFileEncryptedContextualPayload
version: '1.0.0'
}
export interface FileBackupsMapping {
version: typeof FileBackupsConstantsV1.Version
files: Record<
Uuid,
{
backedUpOn: Date
absolutePath: string
relativePath: string
metadataFileName: typeof FileBackupsConstantsV1.MetadataFileName
binaryFileName: typeof FileBackupsConstantsV1.BinaryFileName
version: typeof FileBackupsConstantsV1.Version
}
>
}
export interface FileBackupsDevice {
getFilesBackupsMappingFile(): Promise<FileBackupsMapping>
saveFilesBackupsFile(
uuid: Uuid,
metaFile: string,
downloadRequest: {
chunkSizes: number[]
valetToken: string
url: string
},
): Promise<'success' | 'failed'>
isFilesBackupsEnabled(): Promise<boolean>
enableFilesBackups(): Promise<void>
disableFilesBackups(): Promise<void>
changeFilesBackupsLocation(): Promise<string | undefined>
getFilesBackupsLocation(): Promise<string>
openFilesBackupsLocation(): Promise<void>
}

View File

@@ -0,0 +1,9 @@
import { DeviceInterface } from './DeviceInterface'
import { Environment } from './Environments'
import { RawKeychainValue } from '@standardnotes/models'
export interface MobileDeviceInterface extends DeviceInterface {
environment: Environment.Mobile
getRawKeychainValue(): Promise<RawKeychainValue | undefined>
}

View File

@@ -0,0 +1,18 @@
import { DeviceInterface } from './DeviceInterface'
import { Environment } from './Environments'
import { MobileDeviceInterface } from './MobileDeviceInterface'
import { isMobileDevice } from './TypeCheck'
describe('device type check', () => {
it('should return true for mobile devices', () => {
const device = { environment: Environment.Mobile } as jest.Mocked<MobileDeviceInterface>
expect(isMobileDevice(device)).toBeTruthy()
})
it('should return false for non mobile devices', () => {
const device = { environment: Environment.Web } as jest.Mocked<DeviceInterface>
expect(isMobileDevice(device)).toBeFalsy()
})
})

View File

@@ -0,0 +1,9 @@
import { Environment } from './Environments'
import { MobileDeviceInterface } from './MobileDeviceInterface'
import { DeviceInterface } from './DeviceInterface'
/* istanbul ignore file */
export function isMobileDevice(x: DeviceInterface): x is MobileDeviceInterface {
return x.environment === Environment.Mobile
}

View File

@@ -0,0 +1,10 @@
import { DeviceInterface } from './DeviceInterface'
import { RawKeychainValue } from '@standardnotes/models'
export interface WebOrDesktopDeviceInterface extends DeviceInterface {
readonly appVersion: string
getKeychainValue(): Promise<RawKeychainValue>
setKeychainValue(value: RawKeychainValue): Promise<void>
}