diff --git a/persist.ts b/persist.ts index ad3536796..41ee0033d 100644 --- a/persist.ts +++ b/persist.ts @@ -14,3 +14,6 @@ export const internal: { } = { observablePersistConfiguration, }; + +import { persistActivateNode } from './src/persist/persistActivateNode'; +persistActivateNode(); diff --git a/src/ObservableObject.ts b/src/ObservableObject.ts index 3516a4761..6705d0568 100644 --- a/src/ObservableObject.ts +++ b/src/ObservableObject.ts @@ -44,6 +44,8 @@ import type { UpdateFn, RetryOptions, ObservablePersistStateInternal, + OnSetExtra, + SubscribeOptions, } from './observableInterfaces'; import { observe } from './observe'; import { onChange } from './onChange'; @@ -888,6 +890,7 @@ function createNodeActivationParams(node: NodeValue): ActivateProxyParams { retry, subscribe, updateLastSync, + obs$: getProxy(node), }; } @@ -989,7 +992,7 @@ const activateNodeBase = (globalState.activateNode = function activateNodeBase( ) { isSetting = true; batch( - () => onSetFn(params), + () => onSetFn(params, { update } as OnSetExtra), () => { isSetting = false; }, @@ -1017,7 +1020,7 @@ const activateNodeBase = (globalState.activateNode = function activateNodeBase( }; if (subscriber) { - subscriber({ update, refresh }); + subscriber({ update, refresh } as SubscribeOptions); } return { update }; diff --git a/src/observableInterfaces.ts b/src/observableInterfaces.ts index db92e5b03..4c2f03944 100644 --- a/src/observableInterfaces.ts +++ b/src/observableInterfaces.ts @@ -482,9 +482,9 @@ interface BaseNodeValue { activated?: boolean; proxyFn2?: (key: string, params: ActivateParams) => any; activationState?: { - onSetFn?: (value: ListenerParams) => void; + onSetFn?: (value: ListenerParams, extra: OnSetExtra) => void; update?: UpdateFn; - subscriber?: (params: { update: UpdateFn; refresh: () => void }) => void; + subscriber?: (params: SubscribeOptions) => void; retryOptions?: RetryOptions; lastSync: { value?: number }; cacheOptions?: CacheOptions; @@ -543,7 +543,8 @@ export interface CacheOptions { pluginLocal?: ClassConstructor; } export interface ActivateParams { - onSet: (fn: (params: ListenerParams) => void) => void; + obs$: Observable; + onSet: (fn: (params: ListenerParams, extra: OnSetExtra) => void) => void; subscribe: (fn: (params: { update: UpdateFn; refresh: () => void }) => void) => void; } export interface ActivateProxyParams extends ActivateParams { @@ -557,3 +558,10 @@ export interface RetryOptions { backoff?: 'constant' | 'exponential'; maxDelay?: number; } +export interface OnSetExtra { + update: UpdateFn; +} +export interface SubscribeOptions { + update: UpdateFn; + refresh: () => void; +} diff --git a/src/persist/persistActivateNode.ts b/src/persist/persistActivateNode.ts new file mode 100644 index 000000000..2798ee032 --- /dev/null +++ b/src/persist/persistActivateNode.ts @@ -0,0 +1,93 @@ +import type { + CacheOptions, + ListenerParams, + NodeValue, + ObservableOnChangeParams, + ObservablePersistRemoteFunctions, + ObservablePersistRemoteGetParams, + ObservablePersistRemoteSetParams, + ObservablePersistStateBase, + RetryOptions, + UpdateFn, +} from '@legendapp/state'; +import { internal, isPromise } from '@legendapp/state'; +import { onChangeRemote, persistObservable } from './persistObservable'; +const { getProxy, globalState } = internal; + +export function persistActivateNode() { + globalState.activateNode = function activateNodePersist( + node: NodeValue, + refresh: () => void, + wasPromise: boolean, + newValue: any, + ) { + const { onSetFn, subscriber, lastSync, cacheOptions, retryOptions } = node.activationState!; + + let onChange: UpdateFn | undefined = undefined; + const pluginRemote: ObservablePersistRemoteFunctions = { + get: async (params: ObservablePersistRemoteGetParams) => { + onChange = params.onChange; + if (isPromise(newValue)) { + newValue = await newValue; + } + if (lastSync.value) { + params.dateModified = lastSync.value; + } + return newValue; + }, + }; + if (onSetFn) { + // TODO: Work out these types better + pluginRemote.set = (params: ObservablePersistRemoteSetParams) => { + if (node.state?.isLoaded.get()) { + onSetFn(params as unknown as ListenerParams, { + update: onChange as UpdateFn, + updateLastSync: () => { + console.log('TODO updateLastSync'); + }, + applyRemoteChange: onChangeRemote, + }); + } + }; + } + if (subscriber) { + subscriber({ + update: (params: ObservableOnChangeParams) => { + if (!onChange) { + // TODO: Make this message better + console.log('[legend-state] Cannot update immediately before the first return'); + } else { + onChange(params); + } + }, + refresh, + applyRemoteChange: onChangeRemote, + }); + } + persistObservable(getProxy(node), { + pluginRemote, + ...(cacheOptions || {}), + remote: { + retry: retryOptions, + }, + }); + + return { update: onChange! }; + }; +} +declare module '@legendapp/state' { + interface ActivateParams { + cache: (cacheOptions: CacheOptions | (() => CacheOptions)) => void; + updateLastSync: (lastSync: number) => void; + retry: (options: RetryOptions) => void; + } + interface OnSetExtra { + updateLastSync: (lastSync: number) => void; + applyRemoteChange: (fn: () => void) => void; + } + interface SubscribeOptions { + applyRemoteChange: (fn: () => void) => void; + } + // eslint-disable-next-line @typescript-eslint/no-empty-interface + interface ObservableState extends ObservablePersistStateBase {} +} diff --git a/src/persist/persistObservable.ts b/src/persist/persistObservable.ts index 1c1227271..f7481fe4d 100644 --- a/src/persist/persistObservable.ts +++ b/src/persist/persistObservable.ts @@ -1,5 +1,4 @@ import type { - CacheOptions, Change, ClassConstructor, FieldTransforms, @@ -7,14 +6,10 @@ import type { NodeValue, Observable, ObservableObject, - ObservableOnChangeParams, ObservablePersistLocal, ObservablePersistRemoteClass, ObservablePersistRemoteFunctions, - ObservablePersistRemoteGetParams, - ObservablePersistRemoteSetParams, ObservablePersistState, - ObservablePersistStateBase, ObservablePersistStateInternal, ObservableReadable, ObservableWriteable, @@ -24,9 +19,7 @@ import type { PersistOptionsRemote, PersistTransform, Primitive, - RetryOptions, TypeAtPath, - UpdateFn, WithPersistState, } from '@legendapp/state'; import { @@ -50,7 +43,7 @@ import { import { observablePersistConfiguration } from './configureObservablePersistence'; import { invertFieldMap, transformObject, transformObjectWithPath, transformPath } from './fieldTransformer'; import { observablePersistRemoteFunctionsAdapter } from './observablePersistRemoteFunctionsAdapter'; -const { getProxy, globalState } = internal; +const { globalState } = internal; export const mapPersistences: WeakMap< ClassConstructor, @@ -88,7 +81,7 @@ function doInOrder(arg1: T | Promise, arg2: (value: T) => void): any { return isPromise(arg1) ? arg1.then(arg2) : arg2(arg1); } -function onChangeRemote(cb: () => void) { +export function onChangeRemote(cb: () => void) { when( () => !globalState.isLoadingRemote$.get(), () => { @@ -867,66 +860,3 @@ export function persistObservable( return obs as any; } - -globalState.activateNode = function activateNodePersist( - node: NodeValue, - refresh: () => void, - wasPromise: boolean, - newValue: any, -) { - const { onSetFn, subscriber, lastSync, cacheOptions, retryOptions } = node.activationState!; - - let onChange: UpdateFn | undefined = undefined; - const pluginRemote: ObservablePersistRemoteFunctions = { - get: async (params: ObservablePersistRemoteGetParams) => { - onChange = params.onChange; - if (isPromise(newValue)) { - newValue = await newValue; - } - if (lastSync.value) { - params.dateModified = lastSync.value; - } - return newValue; - }, - }; - if (onSetFn) { - // TODO: Work out these types better - pluginRemote.set = (params: ObservablePersistRemoteSetParams) => { - if (node.state?.isLoaded.get()) { - onSetFn(params as unknown as ListenerParams); - } - }; - } - if (subscriber) { - subscriber({ - update: (params: ObservableOnChangeParams) => { - if (!onChange) { - // TODO: Make this message better - console.log('[legend-state] Cannot update immediately before the first return'); - } else { - onChange(params); - } - }, - refresh, - }); - } - persistObservable(getProxy(node), { - pluginRemote, - ...(cacheOptions || {}), - remote: { - retry: retryOptions, - }, - }); - - return { update: onChange! }; -}; - -declare module '@legendapp/state' { - interface ActivateParams { - cache: (cacheOptions: CacheOptions | (() => CacheOptions)) => void; - updateLastSync: (lastSync: number) => void; - retry: (options: RetryOptions) => void; - } - // eslint-disable-next-line @typescript-eslint/no-empty-interface - interface ObservableState extends ObservablePersistStateBase {} -}