Skip to content

Commit

Permalink
feat(storage): added include and exclude matchers
Browse files Browse the repository at this point in the history
- added sub-branch option to sync a sub-branch of state to storage
  • Loading branch information
andrewcourtice committed Nov 17, 2022
1 parent 8c9849b commit 4afe572
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 6 deletions.
33 changes: 30 additions & 3 deletions extensions/storage/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ import {
INTERNAL,
InternalStore,
MutationEventData,
ReadState,
} from '@harlem/core';

import {
functionIdentity,
matchGetFilter,
objectFromPath,
objectOmit,
objectSet,
objectTrace,
typeIsNil,
} from '@harlem/utilities';

Expand All @@ -29,9 +35,11 @@ function getOptions<TState extends BaseState>(options?: Partial<Options<TState>>
prefix: 'harlem',
sync: true,
restore: false,
include: '*',
exclude: [],
serialiser: state => JSON.stringify(state),
parser: value => JSON.parse(value),
branch: functionIdentity,
...options,
};
}
Expand All @@ -43,9 +51,11 @@ export default function storageExtension<TState extends BaseState>(options?: Par
prefix,
sync,
restore,
include,
exclude,
serialiser,
parser,
branch,
} = _options;

return (store: InternalStore<TState>) => {
Expand All @@ -62,26 +72,43 @@ export default function storageExtension<TState extends BaseState>(options?: Par

store.register('extensions', 'storage', () => _options);

const {
value,
getNodes,
resetNodes,
} = objectTrace<ReadState<TState>>();

const storage = type === 'session' ? sessionStorage : localStorage;
const storageKey = prefix ? `${prefix}:${store.name}` : store.name;
const mutationFilter = matchGetFilter({
include,
exclude,
});

resetNodes();
branch(value);

function startStorageWrite() {
store.on(EVENTS.mutation.success, (event?: EventPayload<MutationEventData>) => {
if (!event || event.data.mutation === MUTATIONS.sync || exclude.includes(event.data.mutation)) {
if (!event || event.data.mutation === MUTATIONS.sync || mutationFilter(event.data.mutation)) {
return;
}

try {
const state = objectOmit(store.state, INTERNAL.pattern);
storage.setItem(storageKey, serialiser(state));
const subState = objectFromPath(state, getNodes());

storage.setItem(storageKey, serialiser(subState as typeof state));
} catch {
console.warn('Failed to write to storage');
}
});
}

function syncStorage(value: string) {
store.write(MUTATIONS.sync, SENDER, state => Object.assign(state, parser(value)));
store.write(MUTATIONS.sync, SENDER, state => {
objectSet(state, getNodes(), parser(value), INTERNAL.pattern);
});
}

function listener({ key, storageArea, newValue }: StorageEvent) {
Expand Down
11 changes: 8 additions & 3 deletions extensions/storage/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import {
import type {
BaseState,
BranchAccessor,
ReadState,
} from '@harlem/core';

import type {
Matchable,
} from '@harlem/utilities';

export type StorageType = 'local' | 'session';

export interface Options<TState extends BaseState> {
export interface Options<TState extends BaseState> extends Matchable {
type: StorageType;
prefix: string;
sync: boolean;
restore: boolean;
exclude: string[];
serialiser(state: ReadState<TState>): string;
parser(value: string): TState;
branch: BranchAccessor<TState, unknown>;
}

0 comments on commit 4afe572

Please sign in to comment.