import InternalStore from './store' ; import eventEmitter from './event-emitter' ; import { EVENTS , SENDER , } from './constants' ; import { lock , } from '@harlem/utilities' ; import type { App , Plugin , } from 'vue' ; import type { BaseState , EventPayload , ExtendedStore , Extension , HarlemPlugin , InternalStores , MutationEventData , MutationTriggerHandler , PluginOptions , Store , StoreOptions , } from './types' ; export { EVENTS , INTERNAL , } from './constants' ; export * from './types' ; const stores = new Map ( ) ; let installed = false ; function validateStoreCreation ( name ) { const store = stores . get ( name ) ; if ( store && ! store . allowsOverwrite ) { throw new Error ( `A store named ${ name } has already been registered.` ) ; } } function emitCreated ( store , state ) { const created = ( ) => { store . emit ( EVENTS . store . created , SENDER , state ) ; store . emit ( EVENTS . devtools . update , SENDER , state ) ; } ; if ( installed ) { return created ( ) ; } eventEmitter . once ( EVENTS . core . installed , created ) ; } function getExtendedStore < TState extends BaseState , TExtensions extends Extension < TState > [ ] > ( store , extensions ) { return extensions . reduce ( ( output , extension ) => { let result = { } ; try { result = extension ( store ) || { } ; } catch { result = { } ; } return { ... output , ... result , } ; } , { } ) ; } function installPlugin ( plugin , app ) { if ( ! plugin || typeof plugin . install !== 'function' ) { return ; } const { name , install , } = plugin ; const lockedStores = lock ( stores , [ 'set' , 'delete' , 'clear' , ] ) ; try { install ( app , eventEmitter , lockedStores ) ; } catch ( error ) { console . warn ( `Failed to install Harlem plugin: ${ name }. Skipping.` ) ; } } export const on = eventEmitter . on . bind ( eventEmitter ) ; export const once = eventEmitter . once . bind ( eventEmitter ) ; export function createStore < TState extends BaseState , TExtensions extends Extension < TState > [ ] > ( name , state , options ? ) { const { allowOverwrite , providers , extensions , } = { allowOverwrite : true , extensions : [ store => ( { } ) ] as TExtensions , ... options , } ; validateStoreCreation ( name ) ; const store = new InternalStore ( name , state , { allowOverwrite , providers , } ) ; const destroy = ( ) => { stores . delete ( name ) ; store . destroy ( ) ; store . emit ( EVENTS . store . destroyed , SENDER , state ) ; store . emit ( EVENTS . devtools . update , SENDER , state ) ; } ; const getMutationTrigger = ( eventName ) => { return < TPayload = any , TResult = any > ( mutationName , handler ) => { const mutations = ( [ ] as string [ ] ) . concat ( mutationName ) ; return store . on ( eventName , ( event ? ) => { if ( event && mutations . includes ( event . data . mutation ) ) { handler ( event . data ) ; } } ) ; } ; } ; const onBeforeMutation = getMutationTrigger ( EVENTS . mutation . before ) ; const onAfterMutation = getMutationTrigger ( EVENTS . mutation . after ) ; const onMutationSuccess = getMutationTrigger ( EVENTS . mutation . success ) ; const onMutationError = getMutationTrigger ( EVENTS . mutation . error ) ; const extendedStore = getExtendedStore < TState , TExtensions > ( store , extensions ) ; stores . set ( name , store ) ; emitCreated ( store , state ) ; return { destroy , onBeforeMutation , onAfterMutation , onMutationSuccess , onMutationError , state : store . state , getter : store . getter . bind ( store ) , mutation : store . mutation . bind ( store ) , suppress : store . suppress . bind ( store ) , on : store . on . bind ( store ) , once : store . once . bind ( store ) , ... extendedStore , } as any ; } export default { install ( app , options ? ) { const { plugins , } = { plugins : [ ] , ... options , } ; if ( plugins ) { plugins . forEach ( plugin => installPlugin ( plugin , app ) ) ; } installed = true ; eventEmitter . emit ( EVENTS . core . installed ) ; } , } as Plugin ;