@persevie/statemanjs
Version:
Proper state manager for JavaScript
1 lines • 52.2 kB
Source Map (JSON)
{"version":3,"file":"statemanjs.mjs","sources":["../../src/statemanjs/service/debugService.ts","../../src/statemanjs/utility.ts","../../src/statemanjs/service/statemanjsBaseService.ts","../../src/statemanjs/service/statemanjsService.ts","../../src/statemanjs/service/transactionService.ts","../../src/statemanjs/index.ts"],"sourcesContent":["/* istanbul ignore file */\n\nimport { DebugAPI } from \"../api/debugAPI\";\nimport { TransactionAPI } from \"../api/transactionAPI\";\n\nexport class DebugService<T> implements DebugAPI<T> {\n constructor(transactionService: TransactionAPI<T>) {\n this.transactionService = transactionService;\n }\n\n transactionService: TransactionAPI<T>;\n}\n","/* istanbul ignore file */\n/**\n * Makes the error message clear and beautiful.\n * @param description Description of where the error occurred\n * (for example - 'an error occurred while setting the new state').\n * @param error Error object.\n * @returns Nice error message 🌸.\n */\nfunction formatError(description: string, error: unknown): string {\n return `${description}: ${getErrorMessage(error)}`;\n}\n\nfunction getErrorMessage(error: unknown): string {\n return (error as Error).message;\n}\n\nexport { formatError, getErrorMessage };\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { StatemanjsBaseAPI } from \"../api/statemanjsBaseAPI\";\nimport {\n StatemanjsStateWrapper,\n ActionKind,\n Subscriber,\n UpdateCb,\n SubscriptionCb,\n SubscriptionOptions,\n UnsubscribeCb,\n CustomComparator,\n DefaultComparator,\n BaseSetOptions,\n} from \"../entities\";\nimport { formatError, getErrorMessage } from \"../utility\";\n\nexport class StatemanjsBaseService<T> implements StatemanjsBaseAPI<T> {\n /**\n * The proxied state object, wrapped to intercept access and modifications.\n * This is the core state being managed by Statemanjs.\n */\n #proxiedState: StatemanjsStateWrapper<T>;\n\n /**\n * A map of active subscribers identified by a unique symbol.\n */\n #activeSubscribers: Record<symbol, Subscriber> = {};\n\n /**\n * Indicates if properties should be checked for changes.\n */\n #isNeedToCheckProperties = false;\n\n /**\n * The kind of action currently being performed (e.g., 'set' or 'update').\n */\n #actionKind: ActionKind = \"none\";\n\n /**\n * Controls whether access to the state is allowed. Prevents unauthorized access.\n */\n #isAccessToStateAllowed = false;\n\n /**\n * Controls whether the state can be unwrapped, which might bypass proxies.\n */\n #isUnwrapAllowed = false;\n\n /**\n * Flag indicating whether any part of the state was changed during the last operation.\n */\n #wasChanged = false;\n\n /**\n * Stores the path to the property that was changed in the state.\n */\n #pathToChangedProperty: Set<string> = new Set();\n\n /**\n * If set to true, skips state comparison during updates.\n */\n #skipComparison = false;\n\n /**\n * Cache for storing previously created proxies for properties in the state.\n */\n #proxyCache: Map<string, any>;\n\n /**\n * Set of method names considered dangerous, which should be guarded during state modifications.\n */\n readonly #dangerMethods: Set<string> = new Set([\n \"clear\", // (Map; Set)\n \"delete\", // (Map; WeakSet; Set)\n \"set\", // (Map)\n \"add\", // (WeakSet; Set)\n \"fill\", // (Array; TypedArray)\n \"reverse\", // (Array; TypedArray)\n \"sort\", // (Array; TypedArray)\n \"unscopables\", // (Symbol)\n \"pop\", // (Array)\n \"push\", // (Array)\n \"shift\", // (Array)\n \"unshift\", // (Array)\n \"splice\", // (Array)\n ]);\n\n readonly customComparator: CustomComparator<T> | undefined;\n\n readonly defaultComparator: DefaultComparator;\n\n constructor(\n element: T,\n options: {\n customComparator?: CustomComparator<T>;\n defaultComparator?: DefaultComparator;\n },\n ) {\n // Bindings\n this.get = this.get.bind(this);\n this.set = this.set.bind(this);\n this.update = this.update.bind(this);\n this.subscribe = this.subscribe.bind(this);\n this.unsubscribeById = this.unsubscribeById.bind(this);\n this.unsubscribeByIds = this.unsubscribeByIds.bind(this);\n this.getActiveSubscribersCount =\n this.getActiveSubscribersCount.bind(this);\n this.unsubscribeAll = this.unsubscribeAll.bind(this);\n this.unwrap = this.unwrap.bind(this);\n this.getPathToChangedProperty =\n this.getPathToChangedProperty.bind(this);\n\n // Initialize custom comparator\n this.customComparator = options.customComparator;\n\n // Initialize default comparator\n this.defaultComparator = options.defaultComparator || \"ref\";\n\n // Initialize cache for proxies\n this.#proxyCache = new Map();\n\n // Wrap and proxy the state\n this.#proxiedState = new Proxy<StatemanjsStateWrapper<T>>(\n { __STATEMANJS_STATE__: element } as StatemanjsStateWrapper<T>,\n this.#createHandler([]),\n );\n }\n\n #isPrimitive(value: unknown): boolean {\n return (\n value === null ||\n typeof value === \"undefined\" ||\n typeof value === \"boolean\" ||\n typeof value === \"number\" ||\n typeof value === \"string\" ||\n typeof value === \"symbol\" ||\n typeof value === \"bigint\"\n );\n }\n\n #addPathToChangedProperty(path: string): void {\n this.#pathToChangedProperty.add(path);\n }\n\n #resetPathToChangedProperty(): void {\n this.#pathToChangedProperty = new Set();\n }\n\n /**\n * Saves the slot of a target property, binding functions if necessary.\n *\n * @param {any} target - The target object.\n * @param {any} prop - The property to be accessed.\n * @returns {any} The value of the target's property, bound if it's a function.\n */\n #saveSlots(target: any, prop: any): any {\n return target && typeof target[prop] == \"function\"\n ? target[prop].bind(target)\n : target[prop];\n }\n\n /**\n * Converts a property path array to a dot-separated string.\n *\n * @param {(string | symbol)[]} path - The array of path segments.\n * @returns {string} The stringified path.\n */\n #stringifyPath(path: (string | symbol)[]): string {\n let result = \"\";\n\n for (let i = 0; i < path.length; i++) {\n const p = path[i];\n result += typeof p === \"symbol\" ? p.toString() : p;\n if (i < path.length - 1) {\n result += \".\";\n }\n }\n\n return result;\n }\n\n /**\n * Checks the access kind (function, object, etc.) and returns appropriate proxies or values.\n *\n * @param {any} target - The target object.\n * @param {any} prop - The property to access.\n * @param {(string | symbol)[]} path - The path to the property.\n * @returns {any} The accessed value or a proxy of it.\n */\n #checkAccessKind(target: any, prop: any, path: (string | symbol)[]): any {\n const targetProp = target[prop];\n const isFunc = typeof targetProp === \"function\";\n const isObj = this.#isObject(targetProp) && targetProp !== null;\n\n if (isFunc) {\n if (\n this.#dangerMethods.has(prop) &&\n !this.#isAccessToStateAllowed\n ) {\n throw new Error(\n \"Access is denied. Use 'update' method to do this.\",\n );\n }\n\n const newPath = path.concat(prop);\n\n if (this.#dangerMethods.has(prop)) {\n this.#wasChanged = true;\n this.#clearProxyCache(path);\n }\n\n return new Proxy(\n this.#saveSlots(target, prop),\n this.#createHandler(newPath),\n );\n }\n\n if (isObj && !this.#isUnwrapAllowed) {\n const newPath = path.concat(prop);\n const stringifiedPath = this.#stringifyPath(newPath);\n\n if (!this.#proxyCache.has(stringifiedPath)) {\n const newProxy = new Proxy(\n this.#saveSlots(target, prop),\n this.#createHandler(newPath),\n );\n this.#proxyCache.set(stringifiedPath, newProxy);\n }\n\n return this.#proxyCache.get(stringifiedPath);\n }\n\n return this.#saveSlots(target, prop);\n }\n\n #clearProxyCache(path: (string | symbol)[]): void {\n const pathString = this.#stringifyPath(path);\n for (const key of this.#proxyCache.keys()) {\n if (key.startsWith(pathString)) {\n this.#proxyCache.delete(key);\n }\n }\n }\n\n #isEqualShallow(a: any, b: any): boolean {\n if (this.#isPrimitive(a) || this.#isPrimitive(b)) {\n return a === b;\n }\n\n if (Object.keys(a).length !== Object.keys(b).length) {\n return false;\n }\n\n for (const key in a) {\n if (a[key] !== b[key]) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Updates a property in the state and marks the state as changed.\n *\n * @param {any} target - The target object.\n * @param {any} prop - The property to update.\n * @param {any} val - The new value to set.\n * @param {any} newPath - The path to the property being updated.\n */\n #updateProperty(target: any, prop: any, val: any, newPath: any): void {\n target[prop] = val;\n this.#wasChanged = true;\n this.#clearProxyCache(newPath);\n\n if (this.#isNeedToCheckProperties && this.#actionKind === \"update\") {\n const filteredPath = newPath.slice(1);\n const pathString = this.#stringifyPath(filteredPath);\n\n if (pathString.length) {\n this.#addPathToChangedProperty(pathString);\n }\n }\n }\n\n /**\n * Determines whether a property should be updated based on the comparator.\n *\n * @param {any} target - The target object.\n * @param {any} prop - The property to check.\n * @param {any} val - The new value to set.\n * @returns {boolean} True if the property should be updated, otherwise false.\n */\n #isUpdateNeeded(target: any, prop: any, val: any): boolean {\n switch (this.defaultComparator) {\n case \"ref\":\n return target[prop] !== val;\n case \"shallow\":\n return !this.#isEqualShallow(target[prop], val);\n case \"custom\":\n if (!this.customComparator) {\n throw new Error(\"Custom comparator is not provided.\");\n }\n return !this.customComparator(target[prop], val);\n case \"none\":\n default:\n return true;\n }\n }\n\n #createHandler(\n path: (string | symbol)[],\n ): ProxyHandler<StatemanjsStateWrapper<T>> {\n return {\n get: (target: any, prop: any): any => {\n return this.#checkAccessKind(target, prop, path);\n },\n set: (target: any, prop: any, val: any): boolean => {\n if (!this.#isAccessToStateAllowed) {\n throw new Error(\"Access is denied.\");\n }\n\n const newPath = path.concat(prop);\n\n if (\n this.#skipComparison ||\n this.#isUpdateNeeded(target, prop, val)\n ) {\n this.#updateProperty(target, prop, val, newPath);\n }\n\n return true;\n },\n defineProperty: (): boolean => {\n throw new Error(\"Cannot define property.\");\n },\n deleteProperty: (target: any, prop: string | symbol): boolean => {\n if (!this.#isAccessToStateAllowed) {\n throw new Error(\n 'Cannot delete property directly. Use \"update\" instead.',\n );\n }\n\n if (!(prop in target)) {\n console.warn(`property not found: ${String(prop)}`);\n return false;\n }\n\n const newPath = path.concat(prop);\n delete target[prop as string];\n this.#clearProxyCache(newPath);\n return true;\n },\n };\n }\n\n #addSubscriber(subscriber: Subscriber): void {\n this.#activeSubscribers[subscriber.subId] = subscriber;\n }\n\n #generateSubscriberId(): symbol {\n const id = Symbol();\n\n return id;\n }\n\n #runActiveSubscribersCb(): void {\n const activeSubscribers = this.#activeSubscribers;\n const inactiveSubscribersId: symbol[] = [];\n\n const keys = Object.getOwnPropertySymbols(activeSubscribers);\n\n for (const id of keys) {\n const s = activeSubscribers[id];\n try {\n if (!s.notifyCondition || s.notifyCondition()) {\n s.subCb();\n }\n } catch (error) {\n inactiveSubscribersId.push(id);\n console.info(\n `One of your subscribers marked as inactive and was removed. Error message - ${getErrorMessage(\n error,\n )}`,\n );\n }\n }\n\n if (inactiveSubscribersId.length > 0) {\n this.unsubscribeByIds(inactiveSubscribersId);\n }\n }\n\n #isObject(entity: unknown): boolean {\n return entity !== null && typeof entity === \"object\";\n }\n\n /**\n * Determines if any of the specified properties are part of any path in the state.\n *\n * @param {string[]} properties - The properties to check.\n * @param {string[]} paths - The paths to compare against.\n * @returns {boolean} True if any property is part of any path, otherwise false.\n */\n #isPropertyInPath(properties: string[], paths: string[]): boolean {\n const propertiesMap = new Map(\n properties.map((prop) => [prop, prop.length]),\n );\n\n // the root has been changed\n if (paths.length === 0) {\n return true;\n }\n\n return paths.some((path) => {\n for (const [prop, length] of propertiesMap) {\n if (path.slice(0, length) === prop) {\n return true;\n }\n }\n return false;\n });\n }\n\n /**\n * Safely modifies the state within a controlled environment, ensuring access permissions.\n *\n * @param {() => void} modifier - The function that modifies the state.\n * @param {ActionKind} actionKind - The kind of action being performed.\n * @returns {boolean} True if the state was modified, otherwise false.\n */\n #performSafeModification(\n modifier: () => void,\n actionKind: ActionKind,\n ): boolean {\n this.#isAccessToStateAllowed = true;\n this.#actionKind = actionKind;\n modifier();\n this.#actionKind = \"none\";\n this.#isAccessToStateAllowed = false;\n\n return this.#wasChanged;\n }\n\n public get(): T {\n return this.#proxiedState.__STATEMANJS_STATE__;\n }\n\n public set(newState: T, options: BaseSetOptions<T>): boolean {\n try {\n const wasChanged = this.#performSafeModification((): void => {\n this.#skipComparison = options.skipComparison || false;\n\n this.#proxiedState.__STATEMANJS_STATE__ = newState;\n }, \"set\");\n\n if (!wasChanged) {\n return false;\n }\n\n options.afterUpdate();\n\n this.#wasChanged = false;\n this.#runActiveSubscribersCb();\n this.#resetPathToChangedProperty();\n this.#actionKind = \"none\";\n\n return true;\n } catch (error) {\n throw new Error(\n formatError(\n \"An error occurred while setting the new state\",\n error,\n ),\n );\n }\n }\n\n public update(updateCb: UpdateCb<T>, options: BaseSetOptions<T>): boolean {\n try {\n const wasChanged = this.#performSafeModification((): void => {\n this.#skipComparison = options.skipComparison || false;\n\n updateCb(this.get());\n }, \"update\");\n\n if (!wasChanged) {\n return false;\n }\n\n options.afterUpdate();\n\n this.#wasChanged = false;\n this.#runActiveSubscribersCb();\n this.#resetPathToChangedProperty();\n this.#actionKind = \"none\";\n\n return true;\n } catch (error) {\n throw new Error(\n formatError(\n \"An error occurred while updating the state\",\n error,\n ),\n );\n }\n }\n\n public subscribe(\n subscriptionCb: SubscriptionCb<T>,\n subscriptionOptions: SubscriptionOptions<T> = {},\n ): UnsubscribeCb {\n const subscriberId = this.#generateSubscriberId();\n\n const notifyConditionCb = subscriptionOptions.notifyCondition;\n const hasProperties =\n subscriptionOptions.properties &&\n subscriptionOptions.properties.length > 0;\n\n if (hasProperties) {\n this.#isNeedToCheckProperties = true;\n }\n\n this.#addSubscriber({\n subId: subscriberId,\n subCb: () => subscriptionCb(this.get()),\n notifyCondition: (): boolean => {\n if (hasProperties) {\n if (!this.#isObject(this.unwrap())) {\n throw new Error(\n \"You can't add properties to track if your state is not an object\",\n );\n }\n\n try {\n return this.#isPropertyInPath(\n subscriptionOptions.properties as string[],\n this.getPathToChangedProperty(),\n );\n } catch (error) {\n throw new Error(\n formatError(\n \"An error occurred when accessing a property from the subscriptionOptions list\",\n error,\n ),\n );\n }\n }\n\n return (\n notifyConditionCb === undefined ||\n notifyConditionCb(this.get())\n );\n },\n isProtected: subscriptionOptions.protect ?? false,\n });\n\n return (): void => {\n if (!hasProperties) {\n this.#isNeedToCheckProperties = false;\n }\n\n this.unsubscribeById(subscriberId);\n };\n }\n\n public unsubscribeById(subscriberId: symbol): void {\n delete this.#activeSubscribers[subscriberId];\n }\n\n public unsubscribeByIds(subscriberIds: symbol[]): void {\n subscriberIds.forEach((id) => {\n this.unsubscribeById(id);\n });\n }\n\n public getActiveSubscribersCount(): number {\n return Object.getOwnPropertySymbols(this.#activeSubscribers).length;\n }\n\n public unsubscribeAll(): void {\n this.#isNeedToCheckProperties = false;\n\n const protectedSubscribers: Record<symbol, Subscriber> = {};\n\n for (const id of Object.getOwnPropertySymbols(\n this.#activeSubscribers,\n )) {\n const subscriber = this.#activeSubscribers[id];\n if (subscriber.isProtected) {\n protectedSubscribers[id] = subscriber;\n }\n }\n\n this.#activeSubscribers = protectedSubscribers;\n }\n\n public unwrap(): T {\n this.#isUnwrapAllowed = true;\n const unwrapped = this.get();\n this.#isUnwrapAllowed = false;\n\n return unwrapped;\n }\n\n public getPathToChangedProperty(): string[] {\n return Array.from(this.#pathToChangedProperty.values());\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { DebugAPI } from \"../api/debugAPI\";\nimport { StatemanjsAPI } from \"../api/statemanjsApi\";\nimport { StatemanjsBaseAPI } from \"../api/statemanjsBaseAPI\";\nimport { StatemanjsComputedAPI } from \"../api/statemanjsComputedAPI\";\nimport {\n SetOptions,\n StatemanjsComputedServiceOptions,\n StatemanjsServiceOptions,\n SubscriptionCb,\n SubscriptionOptions,\n UnsubscribeCb,\n UpdateCb,\n UpdateOptions,\n} from \"../entities\";\nimport { formatError } from \"../utility\";\nimport { StatemanjsBaseService } from \"./statemanjsBaseService\";\n\nexport class StatemanjsService<E> implements StatemanjsAPI<E> {\n #statemanjsBaseService: StatemanjsBaseAPI<E>;\n\n readonly DEBUG: DebugAPI<E> | undefined;\n\n constructor(element: E, options: StatemanjsServiceOptions<E>) {\n // Bindings\n this.set = this.set.bind(this);\n this.get = this.get.bind(this);\n this.subscribe = this.subscribe.bind(this);\n this.unsubscribeAll = this.unsubscribeAll.bind(this);\n this.getActiveSubscribersCount =\n this.getActiveSubscribersCount.bind(this);\n this.update = this.update.bind(this);\n this.unwrap = this.unwrap.bind(this);\n\n this.#statemanjsBaseService = new StatemanjsBaseService(element, {\n customComparator: options.customComparator,\n defaultComparator: options.defaultComparator,\n });\n this.DEBUG = options.debugService;\n }\n\n /**\n * Accepts a new state and compares it with the current one.\n * Nothing will happen if the passed value is equal to the current one.\n * @param newState New state.\n * @returns Status of operation.\n */\n set(newState: E, options: SetOptions<E> = {}): boolean {\n try {\n const wasChanged = this.#statemanjsBaseService.set(newState, {\n afterUpdate: (): void => {\n if (this.DEBUG !== undefined) {\n this.DEBUG.transactionService.addTransaction(\n this.unwrap(),\n );\n }\n },\n ...options,\n });\n\n return wasChanged;\n } catch (error) {\n throw new Error(\n formatError(\n \"An error occurred while setting the new state\",\n error,\n ),\n );\n }\n }\n\n /** Get current state */\n get(): E {\n return this.#statemanjsBaseService.get();\n }\n\n /**\n * The method of subscribing to the status change.\n * Accepts a callback function (subscription callback),\n * which will be called at each update, and a subscription options object.\n * In the options, you can specify information about the subscription,\n * as well as specify the condition under which the subscriber will be notified\n * and mark the subscriber as protected. All subscribers are unprotected by default.\n * Protected subscribers can only be unsubscribed using the unsubscribe method returned by this method.\n * Returns the unsubscribe callback function.\n *\n * @param subscriptionCb A function that runs on every update.\n * @param subscriptionOptions Additional information and notification condition.\n * @returns Unsubscribe callback function.\n */\n subscribe(\n subscriptionCb: SubscriptionCb<E>,\n subscriptionOptions: SubscriptionOptions<E> = {},\n ): UnsubscribeCb {\n return this.#statemanjsBaseService.subscribe(\n subscriptionCb,\n subscriptionOptions,\n );\n }\n\n /** Remove all unprotected subscribers */\n unsubscribeAll(): void {\n this.#statemanjsBaseService.unsubscribeAll();\n }\n\n /**\n * Returns count of all active subscribers.\n * @returns number.\n */\n getActiveSubscribersCount(): number {\n return this.#statemanjsBaseService.getActiveSubscribersCount();\n }\n\n /**\n * Flexible state update.\n * @param updateCb Callback for state updates.\n */\n update(updateCb: UpdateCb<E>, options: UpdateOptions<E> = {}): boolean {\n try {\n const wasChanged = this.#statemanjsBaseService.update(updateCb, {\n afterUpdate: (): void => {\n if (this.DEBUG !== undefined) {\n this.DEBUG.transactionService.addTransaction(\n this.unwrap(),\n );\n }\n },\n ...options,\n });\n\n return wasChanged;\n } catch (error) {\n throw new Error(\n formatError(\n \"An error occurred while updating the state\",\n error,\n ),\n );\n }\n }\n\n /**\n * Unwrap a proxy object to a regular JavaScript object\n * @returns unwrapped state\n */\n unwrap(): E {\n return this.#statemanjsBaseService.unwrap();\n }\n\n /**\n * Dispatch an async action\n * @param action An async action. It accepts a stateManager object,\n * which is used to access the current state.\n * @returns Promise.\n */\n async asyncAction(\n action: (stateManager: StatemanjsAPI<E>) => Promise<void>,\n ): Promise<void> {\n try {\n await action(this);\n } catch (error) {\n throw new Error(\n `An error occurred while dispatching the async action: ${\n (error as Error).message\n }`,\n );\n }\n }\n\n /**\n * Create a computed state for a state property.\n * @param selectorFn A function that returns a value of a state property.\n * @returns A computed state.\n */\n createSelector<T>(\n selectorFn: (state: E) => T,\n subscriptionOptions: SubscriptionOptions<any> = {},\n ): StatemanjsComputedAPI<T> {\n const selector = (): T => selectorFn(this.get());\n return new StatemanjsComputedService<T>(selector, [this], {\n debugService: this.DEBUG,\n customComparator: this.#statemanjsBaseService.customComparator,\n defaultComparator: this.#statemanjsBaseService.defaultComparator,\n ...subscriptionOptions,\n });\n }\n}\n\nexport class StatemanjsComputedService<T> implements StatemanjsComputedAPI<T> {\n #statemanjs: StatemanjsAPI<T>;\n\n constructor(\n callback: () => T,\n deps: (StatemanjsAPI<any> | StatemanjsComputedAPI<any>)[],\n options: StatemanjsComputedServiceOptions<any>,\n ) {\n if (!deps.length) {\n throw new Error(\"No dependencies provided\");\n }\n\n // Bindings\n this.get = this.get.bind(this);\n this.subscribe = this.subscribe.bind(this);\n this.unsubscribeAll = this.unsubscribeAll.bind(this);\n this.getActiveSubscribersCount =\n this.getActiveSubscribersCount.bind(this);\n this.unwrap = this.unwrap.bind(this);\n\n this.#statemanjs = new StatemanjsService<T>(callback(), {\n debugService: options.debugService,\n customComparator: options.customComparator,\n defaultComparator: options.defaultComparator,\n });\n\n for (const d of deps) {\n d.subscribe(\n (): void => {\n this.#statemanjs.set(callback());\n },\n {\n notifyCondition: options.notifyCondition,\n protect:\n options.protect === undefined ? true : options.protect,\n properties: options.properties,\n },\n );\n }\n }\n\n /** Get current state */\n get(): T {\n return this.#statemanjs.get();\n }\n\n /**\n * The method of subscribing to the status change.\n * Accepts a callback function (subscription callback),\n * which will be called at each update, and a subscription options object.\n * In the options, you can specify information about the subscription,\n * as well as specify the condition under which the subscriber will be notified\n * and mark the subscriber as protected. All subscribers are unprotected by default.\n * Protected subscribers can only be unsubscribed using the unsubscribe method returned by this method.\n * Returns the unsubscribe callback function.\n *\n * @param subscriptionCb A function that runs on every update.\n * @param subscriptionOptions Additional information and notification condition.\n * @returns Unsubscribe callback function.\n */\n subscribe(\n subscriptionCb: SubscriptionCb<T>,\n subscriptionOptions?: SubscriptionOptions<T> | undefined,\n ): UnsubscribeCb {\n return this.#statemanjs.subscribe(subscriptionCb, subscriptionOptions);\n }\n\n /** Remove all unprotected subscribers */\n unsubscribeAll(): void {\n this.#statemanjs.unsubscribeAll();\n }\n\n /**\n * Returns count of all active subscribers.\n * @returns number.\n */\n getActiveSubscribersCount(): number {\n return this.#statemanjs.getActiveSubscribersCount();\n }\n\n /**\n * Unwrap a proxy object to a regular JavaScript object\n * @returns unwrapped state\n */\n unwrap(): T {\n return this.#statemanjs.unwrap();\n }\n}\n","import { TransactionAPI } from \"../api/transactionAPI\";\nimport { Transaction, TransactionDiff } from \"../types/transactionTypes\";\n\nexport class TransactionService<T> implements TransactionAPI<T> {\n constructor(maxLength: number) {\n this.addTransaction = this.addTransaction.bind(this);\n this.getLastTransaction = this.getLastTransaction.bind(this);\n this.getAllTransactions = this.getAllTransactions.bind(this);\n this.getTransactionByNumber = this.getTransactionByNumber.bind(this);\n this.getLastDiff = this.getLastDiff.bind(this);\n this.getDiffBetween = this.getDiffBetween.bind(this);\n\n this.#maxLength = maxLength > 2 ? maxLength : 2;\n }\n\n #transactions: Map<number, Transaction<T>> = new Map();\n #transactionCounter: number = 1;\n #maxLength: number;\n\n get totalTransactions(): number {\n return this.#transactionCounter;\n }\n\n addTransaction(snapshot: T): void {\n const number = this.#transactionCounter++;\n const timestamp = Date.now();\n const transaction: Transaction<T> = {\n number,\n snapshot: JSON.parse(JSON.stringify(snapshot)),\n timestamp,\n };\n\n if (this.#transactions.size >= this.#maxLength) {\n const oldestTransactionNumber = Array.from(\n this.#transactions.keys(),\n )[0];\n this.#transactions.delete(oldestTransactionNumber);\n }\n\n this.#transactions.set(number, transaction);\n }\n\n getLastTransaction(): Transaction<T> | null {\n return this.#transactions.size > 0\n ? JSON.parse(\n JSON.stringify(Array.from(this.#transactions.values())),\n ).pop()!\n : null;\n }\n\n getAllTransactions(): Transaction<T>[] {\n return JSON.parse(\n JSON.stringify(Array.from(this.#transactions.values())),\n );\n }\n\n getTransactionByNumber(number: number): Transaction<T> | null {\n return (\n JSON.parse(JSON.stringify(this.#transactions.get(number))) || null\n );\n }\n\n getLastDiff(): TransactionDiff<T> | null {\n const transactionsArray = JSON.parse(\n JSON.stringify(Array.from(this.#transactions.values())),\n );\n const length = transactionsArray.length;\n if (length < 2) {\n return null;\n }\n\n const oldSnapshot = transactionsArray[length - 2].snapshot;\n const newSnapshot = transactionsArray[length - 1].snapshot;\n\n return { old: oldSnapshot, new: newSnapshot };\n }\n\n getDiffBetween(\n transactionA: number,\n transactionB: number,\n ): TransactionDiff<T> | null {\n if (transactionA >= transactionB) {\n throw new Error(\"transactionA must be less than transactionB\");\n }\n\n const oldTransaction = this.#transactions.get(transactionA);\n const newTransaction = this.#transactions.get(transactionB);\n\n if (!oldTransaction || !newTransaction) {\n return null;\n }\n\n return JSON.parse(\n JSON.stringify({\n old: oldTransaction.snapshot,\n new: newTransaction.snapshot,\n }),\n );\n }\n}\n","/* istanbul ignore file */\n\nimport { DebugAPI } from \"./api/debugAPI\";\nimport { StatemanjsAPI } from \"./api/statemanjsApi\";\nimport { StatemanjsComputedAPI } from \"./api/statemanjsComputedAPI\";\nimport {\n CustomComparator,\n DefaultComparator,\n SubscriptionOptions,\n} from \"./entities\";\nimport { DebugService } from \"./service/debugService\";\nimport {\n StatemanjsService,\n StatemanjsComputedService,\n} from \"./service/statemanjsService\";\nimport { TransactionService } from \"./service/transactionService\";\n\nexport type StatemanjsOptions<T> = {\n transactionsLen?: number;\n customComparator?: CustomComparator<T>;\n defaultComparator?: DefaultComparator;\n};\n\nexport function createState<T>(\n element: T,\n options?: StatemanjsOptions<T>,\n): StatemanjsAPI<T> {\n let debugService: DebugAPI<T> | undefined;\n\n if (options !== undefined && options.transactionsLen !== undefined) {\n debugService = new DebugService(\n new TransactionService(options.transactionsLen),\n );\n }\n\n return new StatemanjsService(element, {\n debugService,\n customComparator: options?.customComparator,\n defaultComparator: options?.defaultComparator,\n });\n}\n\nexport function createComputedState<T>(\n callback: () => T,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n deps: StatemanjsAPI<any>[],\n options?: StatemanjsOptions<T>,\n): StatemanjsComputedAPI<T> {\n return new StatemanjsComputedService<T>(callback, deps, {\n ...(options || {}),\n debugService:\n options !== undefined && options.transactionsLen !== undefined\n ? new DebugService(\n new TransactionService(options.transactionsLen),\n )\n : undefined,\n customComparator: options?.customComparator,\n defaultComparator: options?.defaultComparator,\n });\n}\n\nexport type { StatemanjsAPI, StatemanjsComputedAPI, SubscriptionOptions };\n"],"names":["DebugService","constructor","transactionService","__publicField","this","formatError","description","error","getErrorMessage","message","_proxiedState","_activeSubscribers","_isNeedToCheckProperties","_actionKind","_isAccessToStateAllowed","_isUnwrapAllowed","_wasChanged","_pathToChangedProperty","_skipComparison","_proxyCache","_dangerMethods","_isPrimitive","isPrimitive_fn","_addPathToChangedProperty","addPathToChangedProperty_fn","_resetPathToChangedProperty","resetPathToChangedProperty_fn","_saveSlots","saveSlots_fn","_stringifyPath","stringifyPath_fn","_checkAccessKind","checkAccessKind_fn","_clearProxyCache","clearProxyCache_fn","_isEqualShallow","isEqualShallow_fn","_updateProperty","updateProperty_fn","_isUpdateNeeded","isUpdateNeeded_fn","_createHandler","createHandler_fn","_addSubscriber","addSubscriber_fn","_generateSubscriberId","generateSubscriberId_fn","_runActiveSubscribersCb","runActiveSubscribersCb_fn","_isObject","isObject_fn","_isPropertyInPath","isPropertyInPath_fn","_performSafeModification","performSafeModification_fn","StatemanjsBaseService","element","options","__privateAdd","Set","get","bind","set","update","subscribe","unsubscribeById","unsubscribeByIds","getActiveSubscribersCount","unsubscribeAll","unwrap","getPathToChangedProperty","customComparator","defaultComparator","__privateSet","Map","Proxy","__STATEMANJS_STATE__","__privateMethod","call","__privateGet","newState","skipComparison","afterUpdate","Error","updateCb","subscriptionCb","subscriptionOptions","_a","subscriberId","notifyConditionCb","notifyCondition","hasProperties","properties","length","subId","subCb","isProtected","protect","subscriberIds","forEach","id","Object","getOwnPropertySymbols","protectedSubscribers","subscriber","unwrapped","Array","from","values","WeakMap","WeakSet","value","path","add","target","prop","result","i","p","toString","targetProp","isFunc","isObj","has","newPath","concat","stringifiedPath","newProxy","pathString","key","keys","startsWith","delete","a","b","val","filteredPath","slice","defineProperty","deleteProperty","console","warn","String","Symbol","activeSubscribers","inactiveSubscribersId","s","push","info","entity","paths","propertiesMap","map","some","modifier","actionKind","_statemanjsBaseService","_statemanjs","StatemanjsService","DEBUG","debugService","__spreadValues","addTransaction","asyncAction","action","createSelector","selectorFn","StatemanjsComputedService","callback","deps","d","_transactions","_transactionCounter","_maxLength","TransactionService","maxLength","getLastTransaction","getAllTransactions","getTransactionByNumber","getLastDiff","getDiffBetween","totalTransactions","snapshot","number","_","timestamp","Date","now","transaction","JSON","parse","stringify","size","oldestTransactionNumber","pop","transactionsArray","old","new","transactionA","transactionB","oldTransaction","newTransaction","createState","transactionsLen","createComputedState"],"mappings":"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