Topsi Base Services
Installation and Usage
$ yarn add @topsi/services
import { MultiItemSyncService } from '@topsi/services';
// ...
const service = new MultiItemSyncService(config);
// ...
service
.items$
.subscribe(items => console.log(items));
// ...
service
.search('somestring')
.take(1)
.subscribe(res => console.log(res));
API
LoggerService
class UnitLoggerService {
log: (...args) => void
error: (...args) => void
warn: (...args) => void
verbose: (...args) => void
debug: (...args) => void
info: (...args) => void
}
class LoggerService extends {
constructor (config: LoggerServiceConfig, name: string)
constructor (name: string)
get: (subLoggerName?: string) => UnitLoggerService
}
AuthService
enum AuthStatus {
STATUS_RETRIEVING_CACHED_CREDENTIALS = 'auth/retrieving-cached-credentials'
STATUS_CHECKING_CREDENTIALS = 'auth/checking-credentials'
}
interface AuthServiceConfig {
// raw auth state stream
authState$: Observable<User|null>
// checker function that will be run every auth state (raw) change
checker: (user: User, authService: AuthService) => Promise<User|null>
signOutFxn: () => void
signInFxn: (strategy: string, payload: any) => void
}
class AuthService {
constructor (config: AuthServiceConfig)
// current checked user
currentUser$: Observable<User|null>
// current processing status
status$: Observable<AuthStatus|null>
// error stream
error$: Observable<Error>
signOut: () => Promise
signIn: (strategy: string, payload: any) => Promise
}
ItemSyncService
interface ItemSyncServiceConfig {
}
class ItemSyncService {
constructor (config: ItemSyncServiceConfig, name: string, storage: ItemSyncStorage|null, authService?: AuthService)
storage: ItemStyncStorage
user: User|null
setUser: (user: User) => this
authService: AuthService|null
autoSetUser: (authService: AuthService) => this
stopAutoSetUser: () => this
}
SingleItemSyncService
interface SingleItemSyncServiceConfig extends ItemSyncServiceConfig {
updateFlag: string = '$updating' // flag to indicate that the item is being updated
removeFlag: string = '$removing' // flag to indicate that the item is being removed
// used for showing optimistic update result
optimisticUpdate: (item: object, changes: object) => object
// used to update item online
updateItemOnline: (item: object, changes: object, user: User, finishUpdate: (updates?: object) => void, undoUpdate: () => void) => void
// used to remove item online
removeItemOnline: (item: object, user: User, confirmRemove: () => void, cancelRemove: () => void) => void
// used to listen to sections of data in realtime
createSectionsListener: (item: object, sections: string[], user: User, item$: Observable<object>) => Observable<object> | Promise<object>
}
class SingleItemSyncService<T> extends ItemSyncService {
constructor (config: SingleItemSyncServiceConfig, storage: ItemSyncStorage|null, authService?: AuthService, item: object)
constructor (config: SingleItemSyncServiceConfig, storage: ItemSyncStorage|null, authService?: AuthService, itemKey: string)
item$: Observable<T>
error$: Observable<Error>
startRealtimeData: (section: string) => this
stopRealtimeData: (section: string) => this
disconnect: () => this
update: (changes: object) => this
remove: () => this
}
MultiItemSyncService
interface MultiItemSyncServiceConfig<T> extends ItemSyncServiceConfig {
limit: number = 10 // pagination limit
createFlag: string = '$creating' // flag to indicate that the item is being created
searchKeys: string[] // keys of object that are tested when searching
resultKeys: string[] // only these keys are given on search results
// used for testing a searching against a local object
offlineMatchString: (obj: object, searchString: string, searchKeys?: string[], exact?: boolean) => boolean
getNextNItems: (limit?: number, offset?: number|string, user?: User) => Observable<T[]>
findOnlineBySearchString: (searchString: string, user: User, searchKeys?: string[], exact?: boolean) => Observable<T[]> | Promise<T[]>
findOnlineByField: (field: string, val: any, user: User) => Observable<T> | Promise<T>
createItemOnline: (item: object, user: User, finishCreate: (createdObject: object) => void, cancelCreate: (objectToCreate: object) => void) => void
optimisticCreate: (obj: object) => object
formatObjectToCreate: (obj: object) => object
}
class MultiItemSyncService<T> extends ItemSyncService {
constructor (config: MultiItemSyncServiceConfig, storage: ItemSyncStorage|null, authService?: AuthService)
items$: Observable<T[]>
error$: Observable<Error>
next: (limit?: number|null, offset?: number|string) => this
stop: () => this
search: (searchString: string, resultKeys?: string[], searchKeys?: string[], exact?: boolean) => Observable<Object[]>
create: (obj: object) => object
getOneByField: (field: string, val: any) => Observable<SingleItemService<T>>
// alias
getOneById: (id: string) => Observable<SingleItemService<T>>
}
Vue Helpers
SingleItemStoreModule
interface SyncSingleStoreOpts {
extraState?: object
extraGetters?: object
extraMutations?: object
extraActions?: object
// data template, only these keys will be reactive
template: object = { id: null }
// will run everytime `changes` object changes
pickValidChanges: (changes: object) => object
}
syncSingle: (store: VuexStore, service: MultiItemSyncService, moduleName: string, opts: SyncSingleStoreOpts) => void
// Module shape
interface RegeisteredVuexModuleState {
loading: boolean
error: Error | null
data: object // template would be used here
dataSub: rx.Subscription // searching observable's subscription
dataService: SingleItemSyncService // service of the currently selected item
changes: object // current changes made to the current data, will be used for updating
// and the extraState
}
// Module shape
interface RegeisteredVuexModuleGetters {
loaded: boolean
updating: boolean
removing: boolean
// and the extraGetters
}
// Module shape
interface RegeisteredVuexModuleMutations {
SET_DATA: (data: object): void
MUT_APPLY_TO_CHANGES: (fn: (changes: object) => object) => void
MUT_SET_DATA_SERVICE: (payload?: { dataService: SingleItemSyncService, dataSub: rx.Subscription }) => void
MUT_START_LOADING: () => void
MUT_STOP_LOADING: (error?: Error) => void
// and the extraMutations
}
// Module shape
interface RegeisteredVuexModuleActions {
loadWithId: (id: string): void
loadWithField: (payload?: { field: string, val: any }) => void
// will use `state.changes`
update: () => void
// undo
resetChanges: () => void
applyFnToChanges: (fn: (changes: object) => object) => void
setChanges: (changes: object) => void
remove: () => void
// and the extraActions
}
interface RegisteredVuexModule {
state: RegeisteredVuexModuleState
getters: RegeisteredVuexModuleGetters
mutations: RegeisteredVuexModuleMutations
actions: RegeisteredVuexModuleActions
}
MultiItemStoreModule
interface SyncMultiStoreOpts {
extraState?: object
extraGetters?: object
extraMutations?: object
extraActions?: object
// data template, only these keys will be reactive
template: object = { id: null }
// will run everytime `createObject` object changes
pickValidCreateFields: (changes: object) => object
}
syncSingle: (store: VuexStore, service: MultiItemSyncService, moduleName: string, opts: SyncMultiStoreOpts) => void
// Module shape
interface RegeisteredVuexModuleState {
search$: rx.Subject | null
searchSub: rx.Subscription | null
error: Error | null
items: []
searched: []
createObject: {}
// and the extraState
}
// Module shape
interface RegeisteredVuexModuleGetters {
searching: boolean
creating: boolean
// and the extraGetters
}
// Module shape
interface RegeisteredVuexModuleMutations {
MUT_SET_ITEMS: (items: object[]): void
MUT_SET_ERROR: (error?: Error) => void
MUT_SET_SEARCHED: (items: object[]): void
MUT_SET_SEARCH_STREAM: (payload?: { search$: rx.Subject, searchSub: rx.Subscription }) => void
MUT_APPLY_TO_CREATE_OBJECT: (fn: (changes: object) => object) => void
// and the extraMutations
}
// Module shape
interface RegeisteredVuexModuleActions {
stopSearch: () => void
searchItem: (searchString: string) => void
// will use `state.createObject`
create: () => void
resetCreateObject: () => void
applyFnToCreateObject: (fn: (createObject: object) => object) => void
setCreateObject: (createObject: object) => void
// and the extraActions
}
interface RegisteredVuexModule {
state: RegeisteredVuexModuleState
getters: RegeisteredVuexModuleGetters
mutations: RegeisteredVuexModuleMutations
actions: RegeisteredVuexModuleActions
}
AuthStoreModule
interface SyncAuthStoreOpts {
extraState?: object
extraGetters?: object
extraMutations?: object
extraActions?: object
// data template, only these keys will be reactive
template: object = { id: null }
// will run everytime `createObject` object changes
pickValidCreateFields: (changes: object) => object
}
syncSingle: (store: VuexStore, service: AuthService, moduleName: string, opts: SyncAuthStoreOpts) => void
// Module shape
interface RegeisteredVuexModuleState {
currentUser: User | null
status: AuthStatus | null
error: Error | null
// and the extraState
}
// Module shape
interface RegeisteredVuexModuleGetters {
isLoggedIn: boolean
// and the extraGetters
}
// Module shape
interface RegeisteredVuexModuleMutations {
MUT_SET_USER: (user: User): void
MUT_SET_ERROR: (error?: Error) => void
MUT_SET_STATUS: (status: AuthStatus): void
// and the extraMutations
}
// Module shape
interface RegeisteredVuexModuleActions {
signIn: (strategy: string, payload?: any) => void
signOut: (searchString: string) => void
// and the extraActions
}
interface RegisteredVuexModule {
state: RegeisteredVuexModuleState
getters: RegeisteredVuexModuleGetters
mutations: RegeisteredVuexModuleMutations
actions: RegeisteredVuexModuleActions
}