1 import type { Callback } from '@proton/pass/types';
3 import { partialMerge } from './merge';
5 /** Handles edge-case where object property is a function - in this
6 * case do not allow passing a setter function */
7 type Setter<T, K extends keyof T> = T[K] extends Callback ? T[K] : T[K] | ((prev: T[K]) => T[K]);
9 export type ObjectHandler<T, R = T> = {
11 get: <K extends keyof T>(key: K) => T[K];
12 merge: (obj: Partial<T>) => ObjectHandler<T, R>;
13 set: <K extends keyof T>(key: K, value: Setter<T, K>) => ObjectHandler<T, R>;
16 /** Creates a handler for the given object, allowing controlled access to its
17 * properties. This promotes a read/write layer over direct object mutation by
18 * passing around a handle instead of the object itself to functions consuming
19 * the underlying data. The object is kept referentially equal under the hood. */
20 export const objectHandler = <T extends object, R extends any = T>(
23 ): ObjectHandler<T, R> => {
24 const handler: ObjectHandler<T, R> = {
26 const obj = Object.freeze({ ...data });
27 return (map?.(obj) ?? obj) as R;
30 data = partialMerge(data, obj);
33 get: (key) => data[key],
34 set: (key, value) => {
35 data[key] = typeof value === 'function' ? value(data[key]) : value;